diff --git a/app/Console/Commands/SimularArcoReforma.php b/app/Console/Commands/SimularArcoReforma.php new file mode 100644 index 0000000..dc8f546 --- /dev/null +++ b/app/Console/Commands/SimularArcoReforma.php @@ -0,0 +1,43 @@ +option('min'); + $max = (int) $this->option('max'); + $single = $this->option('single'); + + if ($single) { + $this->info('Simulando paso de un vehículo...'); + $resultado = $simulador->simularPasoVehiculo(); + + if ($resultado['success']) { + $this->info("Vehículo detectado: {$resultado['vehiculo']['placa']} - {$resultado['vehiculo']['marca']} {$resultado['vehiculo']['modelo']}"); + $this->line(json_encode($resultado['deteccion'], JSON_PRETTY_PRINT)); + } else { + $this->error($resultado['message']); + } + + return Command::SUCCESS; + } + + $this->info("Iniciando simulación continua del ARCO Reforma..."); + $this->info("Tiempo de espera entre vehículos: {$min}-{$max} segundos"); + $this->warn("Presiona Ctrl+C para detener la simulación"); + + $simulador->iniciarSimulacionContinua($min, $max); + + return Command::SUCCESS; + } +} diff --git a/app/Http/Controllers/Api/VehicleController.php b/app/Http/Controllers/Api/VehicleController.php index 7972fed..f420f58 100644 --- a/app/Http/Controllers/Api/VehicleController.php +++ b/app/Http/Controllers/Api/VehicleController.php @@ -2,6 +2,7 @@ use App\Http\Controllers\Controller; use App\Models\Vehicle; +use App\Models\Detection; use App\Services\VehicleService; use App\Services\ConsultaEstatalService; use App\Services\ReporteRoboService; @@ -330,4 +331,15 @@ public function listarRecuperados() ]); } + public function listarDetecciones() + { + $detecciones = Detection::orderBy('fecha_deteccion', 'desc') + ->paginate(config('app.pagination')); + + return ApiResponse::OK->response([ + 'success' => true, + 'detecciones' => $detecciones + ]); + } + } diff --git a/app/Models/Detection.php b/app/Models/Detection.php new file mode 100644 index 0000000..9e855ba --- /dev/null +++ b/app/Models/Detection.php @@ -0,0 +1,32 @@ + + * + * @version 1.0.0 + */ +class Detection extends Model +{ + public $timestamps = false; + + protected $fillable = [ + 'epc', + 'vin', + 'placa', + 'marca', + 'modelo', + 'color', + 'fecha_deteccion' + ]; + + protected $casts = [ + 'fecha_deteccion' => 'datetime' + ]; +} diff --git a/app/Models/VehicleFake.php b/app/Models/VehicleFake.php new file mode 100644 index 0000000..a7569c2 --- /dev/null +++ b/app/Models/VehicleFake.php @@ -0,0 +1,25 @@ + + * + * @version 1.0.0 + */ +class VehicleFake extends Model +{ + protected $fillable = [ + 'placa', + 'vin', + 'marca', + 'color', + 'modelo', + ]; +} diff --git a/app/Services/ArcoSimuladorService.php b/app/Services/ArcoSimuladorService.php new file mode 100644 index 0000000..89049b5 --- /dev/null +++ b/app/Services/ArcoSimuladorService.php @@ -0,0 +1,73 @@ +first(); + + if (!$vehiculo) { + return [ + 'success' => false, + 'message' => 'No hay vehículos disponibles para simular' + ]; + } + + $epc = $this->generarEPC($vehiculo->vin); + + Detection::create([ + 'epc' => $epc, + 'vin' => $vehiculo->vin, + 'placa' => $vehiculo->placa, + 'marca' => $vehiculo->marca, + 'modelo' => $vehiculo->modelo, + 'color' => $vehiculo->color, + 'fecha_deteccion' => now() + ]); + + return [ + 'success' => true, + 'vehiculo' => [ + 'placa' => $vehiculo->placa, + 'vin' => $vehiculo->vin, + 'marca' => $vehiculo->marca, + 'modelo' => $vehiculo->modelo, + 'color' => $vehiculo->color, + 'epc' => $epc + ], + 'mensaje' => 'Detección registrada localmente' + ]; + } + + public function iniciarSimulacionContinua(int $minSegundos = 5, int $maxSegundos = 30): void + { + while (true) { + $this->simularPasoVehiculo(); + + $espera = rand($minSegundos, $maxSegundos); + Log::info("Esperando {$espera} segundos para próxima simulación..."); + + sleep($espera); + } + } + + private function generarEPC(string $vin): string + { + $prefijo = 'E280117000000'; + $sufijo = substr(strtoupper($vin), -8); + $relleno = str_pad($sufijo, 11, '0', STR_PAD_LEFT); + + return $prefijo . $relleno; + } + + public function obtenerTiempoAleatorio(int $min = 5, int $max = 30): int + { + return rand($min, $max); + } +} diff --git a/app/Services/VehicleService.php b/app/Services/VehicleService.php index f99b131..673ae3e 100644 --- a/app/Services/VehicleService.php +++ b/app/Services/VehicleService.php @@ -3,6 +3,7 @@ namespace App\Services; use App\Models\Vehicle; +use App\Models\Detection; use Illuminate\Support\Facades\Redis; use Illuminate\Support\Facades\Log; @@ -22,11 +23,15 @@ public function procesarDeteccion(string $epc, ?int $arcoId = null): array if ($enRedis) { // Ya está marcado como robado, verificar si sigue así - return $this->verificarVehiculoRobado($epc, $arcoId, json_decode($enRedis, true)); + $resultado = $this->verificarVehiculoRobado($epc, $arcoId, json_decode($enRedis, true)); + $this->registrarDeteccion($epc, $resultado); + return $resultado; } // No está en Redis, consultar servicios - return $this->consultarNuevoVehiculo($epc, $arcoId); + $resultado = $this->consultarNuevoVehiculo($epc, $arcoId); + $this->registrarDeteccion($epc, $resultado); + return $resultado; } private function consultarNuevoVehiculo(string $epc, ?int $arcoId): array @@ -184,4 +189,23 @@ public function listarVehiculosRobados(): array return $vehiculos; } + + private function registrarDeteccion(string $epc, array $resultado): void + { + if (!$resultado['success'] || !isset($resultado['vehiculo'])) { + return; + } + + $vehiculo = $resultado['vehiculo']; + + Detection::create([ + 'epc' => $epc, + 'vin' => $vehiculo['vin'] ?? null, + 'placa' => $vehiculo['placa'] ?? null, + 'marca' => $vehiculo['marca'] ?? null, + 'modelo' => $vehiculo['modelo'] ?? null, + 'color' => $vehiculo['color'] ?? null, + 'fecha_deteccion' => now() + ]); + } } diff --git a/database/migrations/2025_12_20_123906_create_vehicle_fakes_table.php b/database/migrations/2025_12_20_123906_create_vehicle_fakes_table.php new file mode 100644 index 0000000..883776a --- /dev/null +++ b/database/migrations/2025_12_20_123906_create_vehicle_fakes_table.php @@ -0,0 +1,32 @@ +id(); + $table->string('placa')->unique(); + $table->string('vin')->unique(); + $table->string('marca'); + $table->string('color'); + $table->string('modelo'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('vehicle_fakes'); + } +}; diff --git a/database/migrations/2025_12_20_143000_create_detections_table.php b/database/migrations/2025_12_20_143000_create_detections_table.php new file mode 100644 index 0000000..c85cb4e --- /dev/null +++ b/database/migrations/2025_12_20_143000_create_detections_table.php @@ -0,0 +1,35 @@ +id(); + + // Datos del vehículo detectado + $table->string('epc'); + $table->string('vin')->nullable(); + $table->string('placa')->nullable(); + $table->string('marca')->nullable(); + $table->string('modelo')->nullable(); + $table->string('color')->nullable(); + $table->timestamp('fecha_deteccion')->useCurrent(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('detections'); + } +}; diff --git a/routes/api.php b/routes/api.php index a7ba85f..2553033 100644 --- a/routes/api.php +++ b/routes/api.php @@ -24,6 +24,7 @@ Route::post('/vehicles/recuperar', [VehicleController::class, 'recuperarVehiculo']); Route::get('/vehicles/robados', [VehicleController::class, 'listarRobados']); Route::get('/vehicles', [VehicleController::class, 'listarRecuperados']); + Route::get('/vehicles/detecciones', [VehicleController::class, 'listarDetecciones']); }); /** Rutas públicas */