ADD: Implementa modelo y migraciones para detecciones y vehículos simulados, y agrega nuevas rutas y métodos en el controlador

This commit is contained in:
Juan Felipe Zapata Moreno 2025-12-20 13:26:04 -06:00
parent 216c1644e1
commit 6c31941803
9 changed files with 279 additions and 2 deletions

View File

@ -0,0 +1,43 @@
<?php namespace App\Console\Commands;
use App\Services\ArcoSimuladorService;
use Illuminate\Console\Command;
class SimularArcoReforma extends Command
{
protected $signature = 'arco:simular
{--min=5 : Tiempo mínimo de espera entre vehículos (segundos)}
{--max=30 : Tiempo máximo de espera entre vehículos (segundos)}
{--single : Simular solo un vehículo}';
protected $description = 'Simula vehículos pasando por el ARCO RFID de Reforma';
public function handle(ArcoSimuladorService $simulador): int
{
$min = (int) $this->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;
}
}

View File

@ -2,6 +2,7 @@
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\Vehicle; use App\Models\Vehicle;
use App\Models\Detection;
use App\Services\VehicleService; use App\Services\VehicleService;
use App\Services\ConsultaEstatalService; use App\Services\ConsultaEstatalService;
use App\Services\ReporteRoboService; 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
]);
}
} }

32
app/Models/Detection.php Normal file
View File

@ -0,0 +1,32 @@
<?php namespace App\Models;
/**
* @copyright (c) 2025 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
*/
use Illuminate\Database\Eloquent\Model;
/**
* Modelo para registrar detecciones de vehículos por el ARCO RFID
*
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
*
* @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'
];
}

View File

@ -0,0 +1,25 @@
<?php namespace App\Models;
/**
* @copyright (c) 2025 Notsoweb Software (https://notsoweb.com) - All Rights Reserved
*/
use Illuminate\Database\Eloquent\Model;
/**
* Descripción
*
* @author Moisés Cortés C. <moises.cortes@notsoweb.com>
*
* @version 1.0.0
*/
class VehicleFake extends Model
{
protected $fillable = [
'placa',
'vin',
'marca',
'color',
'modelo',
];
}

View File

@ -0,0 +1,73 @@
<?php
namespace App\Services;
use App\Models\VehicleFake;
use App\Models\Detection;
use Illuminate\Support\Facades\Log;
class ArcoSimuladorService
{
public function simularPasoVehiculo(): array
{
$vehiculo = VehicleFake::inRandomOrder()->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);
}
}

View File

@ -3,6 +3,7 @@
namespace App\Services; namespace App\Services;
use App\Models\Vehicle; use App\Models\Vehicle;
use App\Models\Detection;
use Illuminate\Support\Facades\Redis; use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@ -22,11 +23,15 @@ public function procesarDeteccion(string $epc, ?int $arcoId = null): array
if ($enRedis) { if ($enRedis) {
// Ya está marcado como robado, verificar si sigue así // 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 // 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 private function consultarNuevoVehiculo(string $epc, ?int $arcoId): array
@ -184,4 +189,23 @@ public function listarVehiculosRobados(): array
return $vehiculos; 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()
]);
}
} }

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('vehicle_fakes', function (Blueprint $table) {
$table->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');
}
};

View File

@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('detections', function (Blueprint $table) {
$table->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');
}
};

View File

@ -24,6 +24,7 @@
Route::post('/vehicles/recuperar', [VehicleController::class, 'recuperarVehiculo']); Route::post('/vehicles/recuperar', [VehicleController::class, 'recuperarVehiculo']);
Route::get('/vehicles/robados', [VehicleController::class, 'listarRobados']); Route::get('/vehicles/robados', [VehicleController::class, 'listarRobados']);
Route::get('/vehicles', [VehicleController::class, 'listarRecuperados']); Route::get('/vehicles', [VehicleController::class, 'listarRecuperados']);
Route::get('/vehicles/detecciones', [VehicleController::class, 'listarDetecciones']);
}); });
/** Rutas públicas */ /** Rutas públicas */