# ICEBERG Hardware Agent — Contexto
#agent #hardware #usb #flask #hid #ir #keep-alive

## Proposito
Servicio HTTP local (Flask, puerto 5555) que actua como puente entre el servidor FastAPI y el programador USB IR de pulseras LED.

## Archivos del modulo
| Archivo | Funcion |
|---------|---------|
| `agent.py` | Servidor Flask + endpoints + keep-alive loop + logging |
| `programmer.py` | Comunicacion HID raw con el CH9326 (protocolo USB-HID) |
| `config.py` | `PORT = 5555`, `HOST = '0.0.0.0'` |
| `logs/agent.log` | Log rotativo (creado en runtime) |
| `agent_token.txt` | Bearer token generado al primer arranque |

## Hardware
- **Bridge USB-HID**: CH9326 (VID `0x1A86`, PID `0xE010`, UART 9600 baud 8N1)
- **MCU pulsera**: STC 8C2K32S2 — recibe comandos IR
- **Protocolo paquete** (11 bytes):
  ```
  [0x05][R][Rhi][Rlo][G][Ghi][Glo][B][Bhi][Blo][checksum]
  ```
  R/G/B = minutos (0-65535 cada canal)
- **Respuesta MCU**: `OK` (4 bytes) o `FAIL!` (6 bytes)

## Endpoints
| Metodo | Ruta | Auth | Descripcion |
|--------|------|------|-------------|
| GET | `/status` | No | Estado basico del agente (uptime, programmer_connected) |
| GET | `/info` | Bearer | Version, uptime, total programadas/desactivadas, ultimo error |
| POST | `/program` | Bearer | Programa pulsera → bloquea hasta OK o timeout (default 30s) |
| GET | `/deactivations` | Bearer | Retorna contador de desactivadas y lo **resetea** |
| GET | `/program_count` | Bearer | Total programadas desde arranque |

### Body `/program`
```json
{
  "red_minutes": 8,
  "green_minutes": 5,
  "blue_minutes": 60,
  "timeout": 30,
  "session_id": "ABC123"
}
```
Respuestas: `{"status": "ok", "programmed_at": "ISO"}` | `{"status": "timeout"}` | HTTP 503 sin hardware

## Keep-Alive loop
- Hilo daemon corriendo desde el arranque
- Envia `R=0,G=0,B=0` cada **~500ms** (0.3s sleep + 0.2s lectura)
- Si una pulsera en **fase roja** se acerca al lector → responde `OK`
  → `_deact_count++` (consultado via `/deactivations`)
- El lock `device_lock` protege acceso concurrente: keep-alive usa `acquire(blocking=False)`

## Flujo de desactivacion automatica
```
Pulsera roja acerca al lector
  → keep-alive recibe OK
  → _deact_count += 1
  → app polling GET /deactivations (cada 2s)
  → _deact_pending[0] += count
  → _tick() en active_wristbands_tab
  → mark_returned(first_expired_id)
```

## Seguridad
- Token generado en `agent_token.txt` al primer arranque
- Endpoints protegidos requieren: `Authorization: Bearer <token>`
- `/status` es publico (no requiere auth)

## Logging
- Archivo: `agent/logs/agent.log`
- Formato: `YYYY-MM-DD HH:MM:SS [LEVEL] mensaje`
- Eventos: conexion USB, cada programacion, desactivaciones, errores

## Iniciar manualmente
```bash
cd agent
python agent.py
```

## Relacionado
- [→ CONTEXTO.md](../CONTEXTO.md) — Arquitectura general #root
- [→ CONTEXTO_APP.md](../app/CONTEXTO_APP.md) — app/api.py llama a este agente #app
- [→ CONTEXTO_SERVER.md](../server/CONTEXTO_SERVER.md) — server/services/hardware_client.py tambien lo llama #server
- [→ CONTEXTO_INSTALADOR.md](../instalador/CONTEXTO_INSTALADOR.md) — como se despliega #deploy

## Tags de navegacion
#agent #hardware #usb #hid #flask #keep-alive #deactivation #ir #ch9326 #stc #bearer-token
