Añadir 03-debug-simulador.md

2026-05-23 02:33:55 +00:00
parent 79afadba1b
commit 2c9d5cf406

451
03-debug-simulador.md.-.md Normal file

@@ -0,0 +1,451 @@
# Debug del Simulador
Herramientas y comandos para verificar el estado del simulador y troubleshooting avanzado.
---
## Verificar que el simulador está corriendo
### Método 1: Endpoint de status
```bash
curl http://localhost:8000/admin/route/RUTA-01/status
```
**Si está corriendo:**
```json
{
"route_id": "RUTA-01",
"current_position_id": 3,
"current_position_name": "Parque Xochipilli",
"status": "EN_RUTA",
"last_update": "2026-05-22T19:35:12.123456"
}
```
**Si NO está corriendo:**
```json
{
"detail": "Ruta no encontrada o simulador detenido"
}
```
---
### Método 2: Logs del servidor
En la terminal donde corre `uvicorn`, deberías ver:
```
INFO: Tick simulador: RUTA-01 -> posición 3
INFO: Broadcast WebSocket a address_id 1: aproximandose
INFO: Tick simulador: RUTA-01 -> posición 4
```
**Si NO ves logs cada 10s** → el simulador está detenido.
---
## Arrancar el simulador
```bash
curl -X POST http://localhost:8000/admin/route/RUTA-01/start
```
**Response esperada:**
```json
{
"message": "Ruta RUTA-01 iniciada",
"route_id": "RUTA-01",
"status": "EN_RUTA"
}
```
---
## Detener el simulador
```bash
curl -X POST http://localhost:8000/admin/route/RUTA-01/stop
```
**Response:**
```json
{
"message": "Ruta RUTA-01 detenida",
"route_id": "RUTA-01"
}
```
---
## Inspeccionar la base de datos
### Abrir con sqlite3
```bash
cd basura_backend
sqlite3 basura.db
# Comandos útiles:
.tables # Listar tablas
.schema truck_status # Ver estructura de tabla
SELECT * FROM truck_status; # Ver estado actual
SELECT * FROM rutas; # Ver rutas disponibles
SELECT * FROM puntos_ruta WHERE ruta_id = 'RUTA-01' ORDER BY orden; # Waypoints
SELECT * FROM notificaciones ORDER BY creada_en DESC LIMIT 10; # Últimas 10 notificaciones
.quit
```
---
### Verificar datos del seed
```sql
-- Debe haber 1 ruta
SELECT COUNT(*) FROM rutas;
-- Resultado: 1
-- Debe haber 5 puntos de ruta
SELECT COUNT(*) FROM puntos_ruta WHERE ruta_id = 'RUTA-01';
-- Resultado: 5
-- Debe haber 1 usuario demo
SELECT * FROM users;
-- Resultado: id=1, email='demo@ejemplo.com'
-- Debe haber 1 domicilio
SELECT * FROM addresses;
-- Resultado: id=1, user_id=1, route_id='RUTA-01'
```
---
## Problemas comunes del simulador
### El camión no avanza
**Síntoma:** `current_position_id` no cambia.
**Diagnóstico:**
```bash
# 1. Verificar que el simulador está corriendo
curl http://localhost:8000/admin/route/RUTA-01/status
# 2. Verificar logs del servidor
# Deberías ver "Tick simulador" cada 10s
```
**Causa 1:** El simulador nunca se arrancó.
**Solución:**
```bash
curl -X POST http://localhost:8000/admin/route/RUTA-01/start
```
**Causa 2:** El camión ya llegó al último punto.
**Solución:**
```sql
-- Reiniciar posición a 1
sqlite3 basura.db "UPDATE truck_status SET current_position_id = 1 WHERE route_id = 'RUTA-01';"
-- Arrancar de nuevo
curl -X POST http://localhost:8000/admin/route/RUTA-01/start
```
**Causa 3:** El status es `AVERIADA`.
**Solución:**
```sql
-- Cambiar status a EN_RUTA
sqlite3 basura.db "UPDATE truck_status SET status = 'EN_RUTA' WHERE route_id = 'RUTA-01';"
```
---
### No llegan notificaciones WebSocket
**Síntoma:** Flutter conecta pero no recibe eventos.
**Diagnóstico:**
```bash
# 1. Conectar con wscat
wscat -c ws://localhost:8000/ws/1
# 2. Arrancar simulador
curl -X POST http://localhost:8000/admin/route/RUTA-01/start
# 3. Esperar 10 segundos
# ¿Recibes eventos?
```
**Causa 1:** El ETA es muy grande (>10 min).
**Solución:** Esperar o forzar proximidad:
```sql
-- Poner el camión cerca del domicilio
sqlite3 basura.db "UPDATE truck_status SET current_position_id = 4 WHERE route_id = 'RUTA-01';"
```
**Causa 2:** Las preferencias de notificación están desactivadas.
**Solución:**
```sql
SELECT * FROM notification_preferences WHERE user_id = 1;
-- Si notify_proximity = False:
UPDATE notification_preferences SET notify_proximity = 1 WHERE user_id = 1;
```
**Causa 3:** El `address_id` no pertenece a `RUTA-01`.
**Solución:**
```sql
SELECT route_id FROM addresses WHERE id = 1;
-- Si es NULL o diferente a 'RUTA-01':
UPDATE addresses SET route_id = 'RUTA-01' WHERE id = 1;
```
---
### El simulador se detiene solo
**Síntoma:** El simulador arranca pero se detiene después de unos segundos.
**Diagnóstico:**
```bash
# Revisar logs del servidor
# Busca errores como:
# ERROR: Exception in simulator
```
**Causa 1:** Error en el código del simulador.
**Solución:**
```bash
# Revisar logs completos
uvicorn app.main:app --reload --log-level debug
```
**Causa 2:** El camión llegó al último punto.
**Solución:**
```bash
# El simulador se detiene automáticamente al final
# Esto es comportamiento esperado
```
---
## Ajustar velocidad del simulador
### Acelerar para demos
```bash
# En .env
SIM_TICK_SECONDS=5 # Tick cada 5s (más rápido)
SIM_SPEED_MULTIPLIER=2.0 # Doble velocidad
```
Reinicia el backend:
```bash
uvicorn app.main:app --reload
```
---
### Ralentizar para debug
```bash
# En .env
SIM_TICK_SECONDS=30 # Tick cada 30s
SIM_SPEED_MULTIPLIER=0.5 # Mitad de velocidad
```
---
## Forzar eventos manualmente
### Forzar avería
```bash
curl -X POST http://localhost:8000/alerts/breakdown \
-H "Content-Type: application/json" \
-d '{"route_id": "RUTA-01"}'
```
**Efecto:**
- Detiene el simulador
- Cambia status a `AVERIADA`
- Broadcast WebSocket `falla_mecanica` a todos los domicilios
---
### Forzar retraso
```bash
curl -X POST http://localhost:8000/admin/route/RUTA-01/delay \
-H "Content-Type: application/json" \
-d '{"delay_minutes": 15}'
```
**Efecto:**
- Cambia status a `RETRASADA`
- Broadcast WebSocket `ruta_tarde`
---
### Forzar proximidad (para testing)
```sql
-- Mover el camión al penúltimo punto
sqlite3 basura.db "UPDATE truck_status SET current_position_id = 4 WHERE route_id = 'RUTA-01';"
-- Arrancar simulador
curl -X POST http://localhost:8000/admin/route/RUTA-01/start
-- En 10s, recibirás evento "aproximandose"
```
---
## Monitorear en tiempo real
### Ver logs del simulador
```bash
# En la terminal del backend
tail -f <archivo-de-logs>
# O con uvicorn:
uvicorn app.main:app --reload --log-level info
```
**Logs esperados cada 10s:**
```
INFO: Tick simulador: RUTA-01 -> posición 2
INFO: ETA calculado para address_id 1: 18 minutos
INFO: Tick simulador: RUTA-01 -> posición 3
INFO: ETA calculado para address_id 1: 12 minutos
INFO: Tick simulador: RUTA-01 -> posición 4
INFO: ETA calculado para address_id 1: 6 minutos
INFO: Broadcast WebSocket a address_id 1: aproximandose
```
---
### Ver tabla de notificaciones
```sql
-- Ver últimas 20 notificaciones enviadas
SELECT
tipo,
address_id,
eta_minutos,
mensaje,
creada_en
FROM notificaciones
ORDER BY creada_en DESC
LIMIT 20;
```
**Ejemplo de salida:**
```
aproximandose|1|8|El camión llega en ~8 minutos|2026-05-22 19:35:00
aproximandose|1|9|El camión llega en ~9 minutos|2026-05-22 19:34:50
ruta_iniciada|1|NULL|El camión comenzó su recorrido|2026-05-22 19:00:00
```
---
## Resetear el simulador completamente
```bash
# 1. Detener el backend (Ctrl+C)
# 2. Borrar la BD
rm basura.db
# 3. Arrancar de nuevo (recrea BD + seed)
uvicorn app.main:app --reload
# 4. Verificar que el seed fue creado
curl http://localhost:8000/admin/route/RUTA-01/status
# 5. Arrancar simulador
curl -X POST http://localhost:8000/admin/route/RUTA-01/start
```
---
## Troubleshooting avanzado
### Ver el código del simulador
```python
# app/services/simulador.py
def tick_simulador(self):
# Este método se ejecuta cada SIM_TICK_SECONDS
# 1. Avanza current_position_id
# 2. Calcula ETA para cada address
# 3. Si ETA <= umbral, broadcast WebSocket
# Agregar prints para debug:
print(f"DEBUG: current_position = {current_position_id}")
print(f"DEBUG: ETA calculado = {eta_minutos}")
```
---
### Ver el broadcast WebSocket
```python
# app/services/ws_manager.py
async def broadcast_zona(self, zona_key: str, payload: dict):
# Agregar log:
print(f"DEBUG: Broadcasting a zona {zona_key}: {payload}")
# ...
```
---
### Verificar APScheduler
```python
# app/services/simulador.py
# Ver jobs activos
from apscheduler.schedulers.asyncio import AsyncIOScheduler
scheduler = AsyncIOScheduler()
jobs = scheduler.get_jobs()
print(f"DEBUG: Jobs activos: {len(jobs)}")
for job in jobs:
print(f" - {job.id}: {job.next_run_time}")
```
---
## Checklist de debug
- [ ] Backend está corriendo (`curl /health`)
- [ ] Simulador está arrancado (`GET /admin/route/.../status`)
- [ ] Logs muestran "Tick simulador" cada 10s
- [ ] `truck_status.current_position_id` incrementa
- [ ] ETA se calcula correctamente (`GET /eta/1`)
- [ ] WebSocket conecta (`wscat -c ws://...`)
- [ ] Eventos llegan a Flutter
- [ ] Preferencias de notificación activadas
- [ ] `address_id` pertenece a la ruta correcta
---
## Siguiente paso
- [Errores comunes](01-errores-comunes.md) — soluciones rápidas
- [Problemas de versiones](02-versiones.md) — Dart, Java, Python
- [Documentación de API](../api/01-endpoints.md) — endpoints disponibles