mirror of
https://github.com/cheveguerra/TotalConnect.git
synced 2026-08-19 00:46:37 +00:00
Initial commit: Hybrid polling, interactive log modal and 3-second hard reset
This commit is contained in:
+44
@@ -0,0 +1,44 @@
|
||||
# Análisis Comparativo: Arquitecturas Alternativas para el Monitoreo de TotalConnect
|
||||
|
||||
Este documento analiza dos enfoques técnicos alternativos para resolver el mismo problema de obtención de estatus de alarmas, comparándolos con nuestra implementación actual en **Python (REST API)**.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Cuadro Comparativo de Alternativas
|
||||
|
||||
| Característica | Enfoque 1: Python + REST API (Actual) | Enfoque 2: Node.js + Puppeteer (Scraping) | Enfoque 3: Go/Rust + REST/SOAP (Compilado) |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **Consumo de Memoria** | Medio (~40-60 MB RAM) | Muy Alto (~150-350 MB RAM por navegador) | Mínimo (<15 MB RAM) |
|
||||
| **Tiempo de Respuesta** | Medio (~1-2 minutos por el ciclo secuencial) | Lento (~2-3 minutos por carga de interfaz) | Ultra Rápido (Segundos, por concurrencia nativa) |
|
||||
| **Robustez ante Cambios** | Alta (El API cambia muy rara vez) | Muy Baja (Cualquier cambio de HTML lo rompe) | Alta (El API cambia muy rara vez) |
|
||||
| **Complejidad del Código** | Baja/Media (Usa librerías existentes) | Media (Fácil de entender, difícil de depurar) | Alta (Requiere programar clientes HTTP y parsing a mano) |
|
||||
| **Facilidad de Despliegue**| Media (Requiere Python y venv) | Compleja (Requiere Node.js y dependencias de Chrome/X11) | Ultra Simple (Un único archivo binario compilado) |
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Enfoque Alternativo A: Node.js + Puppeteer/Playwright (Web Scraping)
|
||||
|
||||
Consiste en programar un script en Node.js que levante un navegador "invisible" (Headless Chrome), entre a la página de inicio de sesión de Total Connect 2.0, ingrese el usuario y contraseña simulando clics humanos, navegue a la pantalla del teclado virtual y extraiga el texto y las clases CSS de las sucursales directamente del DOM del sitio web.
|
||||
|
||||
### 👍 Pros:
|
||||
* **Fidelidad al Usuario:** No depende de endpoints REST no documentados o secretos. Si funciona en la página web oficial, funcionará en el script.
|
||||
* **Manejo de Estados Visuales:** Obtiene exactamente lo que el usuario ve (los mismos íconos y textos que ya están renderizados en la web de Honeywell).
|
||||
|
||||
### 👎 Contras:
|
||||
* **Footprint de Recursos Masivo:** Ejecutar Chrome sin interfaz en un servidor Linux consume una cantidad enorme de CPU y memoria RAM. No es viable en servidores pequeños o con recursos limitados.
|
||||
* **Fragilidad del DOM:** Si Resideo actualiza el diseño de su página web (cambia un `id`, una clase de CSS o cambia la estructura de las etiquetas HTML), el scraper se rompe instantáneamente y requiere mantenimiento de emergencia.
|
||||
* **Dificultad con MFA:** Si la página de Honeywell decide exigir Verificación de Dos Pasos (MFA) o CAPTCHA en horarios de alta carga, simular el login a través de código es sumamente difícil de automatizar.
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Enfoque Alternativo B: Go (Golang) o Rust + Clientes REST Nativos
|
||||
|
||||
Consiste en desarrollar un servicio binario en Go o Rust que se conecte directamente a los endpoints REST de Honeywell (haciendo las mismas llamadas OAuth2 que hace nuestro script en Python), compile un binario único optimizado y exponga un servidor HTTP ultraligero.
|
||||
|
||||
### 👍 Pros:
|
||||
* **Rendimiento Inigualable:** Un binario compilado en Go o Rust se ejecuta casi instantáneamente, consume menos de 15 MB de memoria RAM y no tiene dependencias en el servidor de producción (no necesita intérpretes de lenguaje, `venv` ni `node_modules`).
|
||||
* **Concurrencia Nativa (Velocidad de Carga):** Al tener soporte nativo de multiprocesamiento ligero (como las `goroutines` en Go), el script puede consultar las 100+ sucursales de forma **simultánea** en paralelo (en lugar de una por una en un ciclo secuencial). Esto reduciría el tiempo de actualización de 2 minutos a **menos de 5 segundos**.
|
||||
|
||||
### 👎 Contras:
|
||||
* **Curva de Aprendizaje y Desarrollo Lento:** No existen wrappers oficiales o librerías maduras de la comunidad para TotalConnect en Go o Rust. Habría que programar desde cero el flujo de autenticación OAuth2, la renovación del token de sesión y el mapeo de todas las complejas estructuras JSON y SOAP de Honeywell.
|
||||
* **Mantenibilidad:** Cualquier cambio o ajuste requiere volver a compilar el binario para la arquitectura del servidor destino.
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
# Explicación de Modos de Polling (Rápido vs. Full)
|
||||
|
||||
Este documento describe la arquitectura de consultas del monitor de TotalConnect 2.0, especificando el funcionamiento del **Polling Rápido (Ligero)** y del **Polling Completo (Profundo)**, así como las circunstancias en las que se ejecuta cada uno.
|
||||
|
||||
---
|
||||
|
||||
## 1. Polling Rápido (Ligero / Delta)
|
||||
|
||||
El Polling Rápido es un mecanismo altamente optimizado diseñado para detectar cambios de estado en tiempo real con el mínimo consumo de ancho de banda y rendimiento.
|
||||
|
||||
* **Tecnología Utilizada:**
|
||||
* **SOAP:** Método `GetLiveEvents` (usando el SessionID GUID).
|
||||
* **REST (Respaldo):** Endpoint `/sessiondetails` (ejecutado únicamente si SOAP está desactivado o falla).
|
||||
* **Funcionamiento:**
|
||||
* Solicita al servidor de Honeywell la lista de eventos ocurridos a partir de un ID de evento de referencia (`LastEventIdReceived`).
|
||||
* En modo de respaldo REST, solicita una lista compacta de las sucursales y sus estados básicos en una sola petición.
|
||||
* **No realiza consultas directas a los paneles físicos** de las sucursales, lo que permite que la respuesta tarde menos de 1 segundo para cientos de ubicaciones.
|
||||
* **Cuándo se ejecuta:**
|
||||
* **De forma automática y continua:** Cada **45 segundos** en el hilo de segundo plano del servidor (`background_poller_thread`).
|
||||
|
||||
---
|
||||
|
||||
## 2. Polling Completo (Profundo / Full)
|
||||
|
||||
El Polling Completo obtiene el estado exhaustivo de una o todas las sucursales, interactuando directamente con el panel físico a través de la nube de Resideo.
|
||||
|
||||
* **Tecnología Utilizada:** Endpoint REST `/partitions/fullStatus` de cada sucursal.
|
||||
* **Funcionamiento:**
|
||||
* Consulta el estado en tiempo real de cada partición (P1-P6) y zona (Z1-Z285).
|
||||
* Extrae detalles críticos como fallos de zonas (puertas/ventanas abiertas), alarmas de fuego/gas/intrusión activas y horas localized de disparo de alarma.
|
||||
* Actualiza la persistencia local en `last_state.json` y regenera el reporte visual `status.html`.
|
||||
* **Cuándo se ejecuta:**
|
||||
|
||||
### A. Para sucursales individuales (Optimización Delta):
|
||||
Se ejecuta **únicamente para las sucursales específicas que cambiaron**, durante el ciclo automático de 45 segundos, si el Polling Rápido detecta alguna de las siguientes circunstancias:
|
||||
1. **Actividad reportada por SOAP:** Un evento nuevo en el delta de SOAP indica que hubo cambios en esa sucursal.
|
||||
2. **Cambio de estado general:** El estatus de armado básico en la respuesta REST de respaldo cambió respecto al valor en caché (ej: Desarmado ➔ Armado Stay).
|
||||
3. **Alarma activa:** La sucursal entra en un estado de alarma disparada (`ALARMING`, `ALARMING_FIRE_SMOKE`, etc.).
|
||||
4. **Validación de restablecimiento:** La sucursal tenía particiones disparadas en el ciclo anterior (necesario para verificar si ya se desactivó/silenció la alarma).
|
||||
5. **Nueva sucursal:** Se detecta una sucursal en la cuenta que no existía previamente en la caché.
|
||||
|
||||
### B. Para todas las sucursales de la cuenta (Fuerza Bruta):
|
||||
Se ejecuta una consulta completa para todas las sucursales de la cuenta bajo las siguientes circunstancias:
|
||||
1. **Refresco manual:** El usuario hace clic en el botón **"Actualizar"** en el panel web (lo que envía una solicitud POST a `/refresh` con `full_refresh=True`).
|
||||
2. **Arranque inicial sin caché:** El servidor inicia por primera vez y no existe el archivo `last_state.json`, lo que obliga a crear la base de datos de estatus desde cero.
|
||||
Executable
+81
@@ -0,0 +1,81 @@
|
||||
# Guía de Empaquetado y Portabilidad: TotalConnect 2.0
|
||||
|
||||
Para hacer que este proyecto sea lo más portable posible y evitar configurar entornos virtuales (`venv`), instalar `pip` o gestionar dependencias manualmente en cada servidor, existen dos enfoques recomendados:
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Método 1: Empaquetar como un Ejecutable Único (PyInstaller)
|
||||
Este método compila tu script de Python y todas sus dependencias (incluyendo el intérprete de Python, las librerías `total-connect-client`, `zeep`, etc.) dentro de un **único archivo ejecutable binario para Linux**.
|
||||
|
||||
### 👍 Ventajas:
|
||||
* Genera un solo archivo (ej. `totalconnect`).
|
||||
* **Cero dependencias:** No necesitas tener instalado Python, `pip`, ni crear entornos virtuales en el servidor destino. Solo copias el archivo y lo corres.
|
||||
* Súper ligero (~15-20 MB).
|
||||
|
||||
### 🛠️ Cómo empaquetarlo (Ejecutar en la VM Linux `192.168.100.50`):
|
||||
|
||||
1. **Instalar PyInstaller en el entorno virtual actual:**
|
||||
```bash
|
||||
cd /mnt/data2/Software/Bot-WhatsApp/TotalConnect
|
||||
./venv/bin/pip install pyinstaller
|
||||
```
|
||||
|
||||
2. **Compilar el script en un único archivo:**
|
||||
```bash
|
||||
./venv/bin/pyinstaller --onefile --name totalconnect index.py
|
||||
```
|
||||
*(Este comando creará una carpeta `dist/` que contendrá el ejecutable final llamado `totalconnect`).*
|
||||
|
||||
3. **Cómo usar el ejecutable generado:**
|
||||
Puedes mover el archivo `dist/totalconnect` a cualquier parte (por ejemplo, a `/usr/local/bin/` para que sea un comando global) y correrlo directamente:
|
||||
* **Modo Servidor:** `./totalconnect --server 8080`
|
||||
* **Modo On-Demand:** `./totalconnect`
|
||||
|
||||
*Nota: Recuerda que `credentials.json` y `locations_cache.json` deben estar en la misma carpeta desde donde ejecutes el binario, ya que busca esos archivos en su directorio relativo.*
|
||||
|
||||
---
|
||||
|
||||
## 🐳 Método 2: Contenedorizar con Docker
|
||||
Este método empaqueta todo el entorno (sistema operativo base, Python, librerías y código) dentro de una imagen de Docker.
|
||||
|
||||
### 👍 Ventajas:
|
||||
* **Portabilidad absoluta:** Funciona de forma idéntica en cualquier sistema (Windows, macOS, Linux, AWS, Proxmox) que tenga instalado Docker.
|
||||
* **Aislamiento total:** No interfiere en lo absoluto con las librerías del sistema operativo.
|
||||
* Gestión de reinicios integrada (Docker se encarga de mantenerlo vivo).
|
||||
|
||||
### 🛠️ Archivos necesarios en la carpeta `/TotalConnect`:
|
||||
|
||||
1. **Crear un archivo `Dockerfile`:**
|
||||
```dockerfile
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Instalar dependencias
|
||||
RUN pip install --no-cache-dir total-connect-client
|
||||
|
||||
# Copiar código
|
||||
COPY index.py /app/index.py
|
||||
|
||||
# Exponer puerto del servidor
|
||||
EXPOSE 8080
|
||||
|
||||
# Comando para arrancar el servidor por defecto
|
||||
CMD ["python", "index.py", "--server", "8080"]
|
||||
```
|
||||
|
||||
2. **Construir la imagen de Docker:**
|
||||
```bash
|
||||
docker build -t totalconnect-monitor .
|
||||
```
|
||||
|
||||
3. **Ejecutar el contenedor (montando las credenciales para poder cambiarlas desde fuera):**
|
||||
```bash
|
||||
docker run -d \
|
||||
--name tc-monitor \
|
||||
--restart unless-stopped \
|
||||
-p 8080:8080 \
|
||||
-v $(pwd)/credentials.json:/app/credentials.json \
|
||||
-v $(pwd)/locations_cache.json:/app/locations_cache.json \
|
||||
totalconnect-monitor
|
||||
```
|
||||
Executable
+76
@@ -0,0 +1,76 @@
|
||||
# Guía de Ubicación, Actualización y Despliegue del Proyecto
|
||||
|
||||
Esta guía documenta la estructura de directorios del proyecto, el flujo de sincronización y los comandos necesarios para iniciar, reiniciar y monitorear el servicio en la máquina virtual Linux por SSH.
|
||||
|
||||
---
|
||||
|
||||
## 1. Ubicaciones del Código
|
||||
|
||||
El proyecto reside en tres entornos clave:
|
||||
|
||||
1. **Copia de Desarrollo (Windows Local):**
|
||||
`E:\Software\TotalConnect\`
|
||||
*Uso:* Compilación del ejecutable standalone `totalconnect.exe` para Windows usando PyInstaller.
|
||||
2. **Copia Compartida (Samba Share):**
|
||||
`Z:\data2\Software\Bot-WhatsApp\TotalConnect\`
|
||||
*Uso:* Compartido en la red que la VM Linux monta de forma nativa. Cualquier cambio guardado en `Z:\` se refleja de forma instantánea en la VM.
|
||||
3. **Entorno de Producción (Linux VM - `192.168.100.50`):**
|
||||
`/mnt/data2/Software/Bot-WhatsApp/TotalConnect/`
|
||||
*Uso:* Directorio donde se ejecuta el demonio de polling de forma continua.
|
||||
|
||||
---
|
||||
|
||||
## 2. Flujo de Actualización de Cambios
|
||||
|
||||
Cada vez que se modifica el código (ej: en `index.py`), se debe seguir el siguiente orden para sincronizar los entornos:
|
||||
|
||||
1. Modificar el archivo principal en la red compartida:
|
||||
`Z:\data2\Software\Bot-WhatsApp\TotalConnect\index.py`
|
||||
2. Copiar los cambios a la ruta de desarrollo local en Windows:
|
||||
```powershell
|
||||
Copy-Item "Z:\data2\Software\Bot-WhatsApp\TotalConnect\index.py" "E:\Software\TotalConnect\index.py" -Force
|
||||
```
|
||||
3. Si el cambio requiere actualizar el ejecutable de Windows `totalconnect.exe`, ejecutar en Windows:
|
||||
```powershell
|
||||
cd E:\Software\TotalConnect\
|
||||
python -m PyInstaller --clean totalconnect.spec
|
||||
Copy-Item "E:\Software\TotalConnect\dist\totalconnect.exe" "E:\Software\TotalConnect\totalconnect.exe" -Force
|
||||
```
|
||||
4. Reiniciar el demonio en la VM (ver comandos en sección 3) para que lea las modificaciones de `index.py`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Ejecución del Servicio en la VM por SSH
|
||||
|
||||
El demonio de polling corre en la máquina virtual Linux en segundo plano. Para interactuar con él, conéctate por SSH:
|
||||
|
||||
```powershell
|
||||
ssh -i "C:\Users\JAGU\.gemini\antigravity-ide\brain\d979a063-dd63-47a8-8ec1-785abc40b475\scratch\id_ed25519_win" -o StrictHostKeyChecking=no root@192.168.100.50
|
||||
```
|
||||
|
||||
### Comandos de Control en la VM:
|
||||
|
||||
* **Detener el demonio activo:**
|
||||
```bash
|
||||
pkill -f 'python3 index.py'
|
||||
```
|
||||
* **Iniciar el demonio en segundo plano (Recomendado):**
|
||||
```bash
|
||||
cd /mnt/data2/Software/Bot-WhatsApp/TotalConnect
|
||||
nohup ./venv/bin/python3 index.py >> server.log 2>&1 &
|
||||
```
|
||||
* **Reiniciar el demonio (Detener e Iniciar en una línea):**
|
||||
```bash
|
||||
pkill -f 'python3 index.py'; sleep 2; cd /mnt/data2/Software/Bot-WhatsApp/TotalConnect && nohup ./venv/bin/python3 index.py >> server.log 2>&1 &
|
||||
```
|
||||
|
||||
### Comandos de Monitoreo:
|
||||
|
||||
* **Comprobar si el proceso de Python está activo:**
|
||||
```bash
|
||||
ps aux | grep 'python3 index.py' | grep -v grep
|
||||
```
|
||||
* **Visualizar los logs de actividad en tiempo real:**
|
||||
```bash
|
||||
tail -f /mnt/data2/Software/Bot-WhatsApp/TotalConnect/server.log
|
||||
```
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
# Plan de Implementación y Walkthrough Propuesto: Integración de Eventos en Tiempo Real
|
||||
|
||||
Este documento detalla el plan de diseño técnico y la arquitectura de los cambios que se implementarán en el proyecto TotalConnect (`index.py`) para integrar el monitoreo por eventos en tiempo real.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Objetivos de la Implementación
|
||||
|
||||
1. **Monitoreo Automático en Segundo Plano:** El servidor Python consultará a Honeywell mediante `GetEvents` cada 45–60 segundos sin requerir la intervención del usuario.
|
||||
2. **Actualización Ultra-Rápida (Delta Update):** En lugar de consultar las 285 sucursales (1-2 minutos), el sistema identificará únicamente las sucursales que registraron eventos nuevos y actualizará el reporte en **1 a 3 segundos**.
|
||||
3. **Cero Retraso al Abrir la Página (`GET /`):** La carga inicial seguirá leyendo `last_state.json` de inmediato (< 5 milisegundos).
|
||||
4. **Control Manual y Circuit Breaker (Botonera & Kill-Switch):**
|
||||
* Botón en la cabecera del dashboard para **Pausar / Reanudar Polling**.
|
||||
* Pausa automática inteligente si Honeywell responde errores de autenticación (401) o límite de peticiones (429).
|
||||
5. **DOM Patching Silencioso en la Interfaz (JS):** Actualización instantánea en el navegador únicamente de los nodos/tarjetas que cambiaron de estado, evitando parpadeos o animaciones molestas.
|
||||
6. **Manejo Resiliente Multicuenta y Revocados:** Las cuentas fuera de línea se mantendrán clasificadas con prioridad 3 al final del listado con fondo gris.
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Cambios Arquitectónicos por Componente
|
||||
|
||||
### 1. Backend (`index.py`)
|
||||
|
||||
#### A. Hilo Demonio de Polling en Segundo Plano (`BackgroundPollerThread`)
|
||||
* Se agregará un `threading.Thread(daemon=True)` que se ejecuta automáticamente al arrancar el servidor.
|
||||
* Mantiene variables globales en memoria:
|
||||
* `polling_enabled` (`True` / `False`): Estado global del motor de consulta.
|
||||
* `last_event_ids`: Diccionario `{ "Ccontrol2020": 850123, "Ccontrol2019": 412099 }` con el último ID de evento procesado por cuenta.
|
||||
* `consecutive_errors`: Contador de fallos consecutivos por cuenta.
|
||||
|
||||
#### B. Flujo del Poller (`poll_events_cycle()`):
|
||||
1. **Verificación de Pausa:** Si `polling_enabled` es `False`, el hilo espera 15 segundos y re-evalúa.
|
||||
2. **Petición Delta `GetEvents`:**
|
||||
Para cada cuenta activa en `credentials.json`, envía una llamada ligera `GetEvents` pasando `LastEventIdReceived`.
|
||||
3. **Evaluación de Resultados:**
|
||||
* **Sin cambios:** Honeywell responde `[]`. No se hace nada más.
|
||||
* **Con cambios:** Extrae los `LocationID` afectados. Ejecuta `fullStatus` únicamente para esos IDs.
|
||||
4. **Actualización de Estado:** Consolida la información en `last_state.json` y vuelve a generar `status.html`.
|
||||
5. **Manejo de Errores (Circuit Breaker):** Si una cuenta recibe 2 errores `401` o `429` seguidos, el servidor pausa el polling automático para esa cuenta y notifica a la UI.
|
||||
|
||||
#### C. Endpoints HTTP Nuevos en `DashboardHandler`
|
||||
* `GET /polling-status`: Devuelve el estado actual (`enabled`, `last_run`, `active_errors`).
|
||||
* `POST /toggle-polling`: Permite a la interfaz web activar o pausar manualmente el polling.
|
||||
|
||||
---
|
||||
|
||||
### 2. Frontend (`status.html` / Template en `index.py`)
|
||||
|
||||
#### A. Botón de Control de Polling en Cabecera
|
||||
Junto al botón "Actualizar" y al selector de cuentas, se agregará un nuevo botón dinámico:
|
||||
```html
|
||||
<button id="toggle-polling-btn" class="btn-polling-active" onclick="togglePolling()">
|
||||
<span class="polling-indicator">●</span> Polling: Activo
|
||||
</button>
|
||||
```
|
||||
|
||||
#### B. Polling Local JS y DOM Patching
|
||||
Un script JS en el cliente ejecutará una consulta ultrarrápida a `GET /polling-status` cada 15 segundos:
|
||||
* Si la respuesta indica un cambio en el timestamp del último estado, realiza un `fetch('/')` silencioso.
|
||||
* Compara los estados de las sucursales y actualiza el HTML **únicamente de las tarjetas que cambiaron**, manteniendo la posición y el foco del usuario.
|
||||
* **Auto-Check por Visibilidad (`visibilitychange`):** Al volver a la pestaña tras estar inactivo, el navegador refresca los datos al instante.
|
||||
|
||||
---
|
||||
|
||||
## 📝 Plan de Verificación
|
||||
|
||||
1. **Prueba de Polling en Segundo Plano:** Iniciar el servidor, alterar el estado de una sucursal de prueba y verificar en consola que la consulta toma < 2 segundos.
|
||||
2. **Prueba de Kill-Switch:** Presionar el botón "Pausar Polling" en la interfaz y verificar que cesan las llamadas HTTP a Honeywell.
|
||||
3. **Prueba de Circuit Breaker:** Simular una credencial inválida y verificar que el servidor desactiva automáticamente el polling tras 2 intentos fallidos.
|
||||
4. **Prueba de Rendimiento:** Confirmar que la carga inicial `GET /` sigue respondiendo en < 5ms.
|
||||
Executable
+84
@@ -0,0 +1,84 @@
|
||||
# Walkthrough - Resumen de Mejoras y Correcciones (TotalConnect Client)
|
||||
|
||||
Este documento resume los cambios y optimizaciones realizados para robustecer el panel de monitoreo centralizado de alarmas.
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Cambios Realizados
|
||||
|
||||
### 1. Actualización en Tiempo Real del Progreso de Carga
|
||||
* **Problema:** El modal de carga se quedaba en un mensaje estático ("Conectando a los paneles...") y no actualizaba qué sucursal estaba procesando.
|
||||
* **Solución:**
|
||||
* Se configuró la variable global `current_loading_status` para actualizarse en cada paso de `run_update()` (conexión inicial, selección de cuenta y consulta específica de sucursal).
|
||||
* Se agregaron cabeceras anti-caché en la respuesta HTTP (`Cache-Control: no-cache, no-store, must-revalidate`).
|
||||
* Se implementó un sondeo mediante `fetch` periódico (intervalo de 1.5s) que actualiza el texto de forma dinámica sin retrasos.
|
||||
|
||||
### 2. Lista de Exclusiones / Excepciones (`exclude`)
|
||||
* **Problema:** El usuario deseaba omitir ciertas sucursales de prueba o fuera de servicio de la visualización global.
|
||||
* **Solución:**
|
||||
* Se agregó soporte para una clave `"exclude": [...]` en el archivo de configuración `credentials.json`.
|
||||
* El script valida de forma inteligente si el ID numérico de la sucursal o su nombre coincide parcialmente con alguno de los elementos a excluir, omitiendo la consulta y el reporte de manera automática.
|
||||
|
||||
### 3. Apertura Automática del Navegador
|
||||
* **Problema:** Iniciar el ejecutable requería que el usuario abriera manualmente la página en `http://localhost:8080/`.
|
||||
* **Solución:**
|
||||
* Se integró el uso del módulo nativo `webbrowser` para abrir la pestaña al arrancar en modo servidor.
|
||||
* **Headless-safety:** El script detecta si el host no posee entorno gráfico (ausencia de `DISPLAY` en sistemas Linux/SSH) y desactiva esta apertura de forma segura para evitar cuelgues o warnings.
|
||||
* Se puede personalizar a través de `"open_browser": true/false` en el JSON o usando las banderas `--no-browser` / `-nb` en la CLI.
|
||||
|
||||
### 4. Filtrado de Historial de Alarma (Alarm Memory)
|
||||
* **Problema:** Algunas sucursales desarmadas o armadas normalmente mostraban alertas de alarma activas debido a memorias no limpiadas físicamente en el teclado Honeywell.
|
||||
* **Solución:**
|
||||
* Se rediseñó el bucle de validación de zonas. Ahora, una zona **sólo se marca como `ALARMA`** si la partición correspondiente de la sucursal está activamente disparada (`is_triggered`).
|
||||
* Si la sucursal está normal, las zonas cerradas no generan falsas alertas y las abiertas se muestran propiamente como `Abierta/Fallo` (color ámbar).
|
||||
|
||||
### 5. Tarjetas Deshabilitadas para Cuentas con Token Revocado
|
||||
* **Problema:** Cuando una cuenta de Total Connect pierde credenciales o se revoca, sus sucursales se cargaban de la caché local pero se visualizaban igual que las sucursales normales de cuentas activas.
|
||||
* **Solución:**
|
||||
* Se añadió la clase CSS `.branch-card-disabled` a las tarjetas cargadas desde la caché local con estatus `REVOKED`.
|
||||
* Esto les otorga un fondo gris medio (`#e2e8f0`), una opacidad del 65% y bloquea los efectos visuales de interacción en hover (sombra y escala), permitiendo distinguir a simple vista qué datos son históricos fuera de línea.
|
||||
|
||||
### 6. Diseño Responsivo y Text Wrapping
|
||||
* **Problema:** En zonas activas largas, las horas de disparo quedaban recortadas con puntos suspensivos en la tarjeta.
|
||||
* **Solución:**
|
||||
* Se eliminó el límite fijo de ancho de `.zone-desc` y se desactivó `white-space: nowrap`.
|
||||
* Se aumentó el ancho mínimo de las columnas en el grid responsivo a `290px`. Las descripciones largas ahora realizan un salto de línea natural posicionando la hora debajo de forma sumamente estética.
|
||||
|
||||
### 7. Checkboxes de Selección de Cuentas en la UI
|
||||
* **Problema:** El usuario deseaba poder elegir qué cuentas actualizar para evitar demoras innecesarias (por ejemplo, evitar actualizar cuentas revocadas).
|
||||
* **Solución:**
|
||||
* Se implementaron checkboxes en la cabecera que listan dinámicamente las cuentas de `credentials.json`.
|
||||
* Al hacer clic en "Actualizar", la UI envía mediante el cuerpo del POST (JSON) únicamente las etiquetas de las cuentas seleccionadas.
|
||||
|
||||
### 8. Persistencia y Mezcla de Estado (`last_state.json`)
|
||||
* **Problema:** Si se actualizaba únicamente una cuenta, el reporte en el frontend sobrescribía el archivo HTML y hacía desaparecer las demás sucursales.
|
||||
* **Solución:**
|
||||
* Se programó la escritura de `last_state.json` al finalizar cualquier consulta exitosa para guardar el último estado de todas las sucursales.
|
||||
* Cuando se realiza una actualización parcial (donde no se seleccionaron todas las cuentas), el backend carga los estados anteriores desde `last_state.json`, los mezcla con los nuevos resultados y genera la vista unificada.
|
||||
|
||||
### 9. Priorización de Cuentas Revocadas al Final del Listado
|
||||
* **Problema:** El usuario deseaba ver las cuentas inactivas/revocadas al final de la página para que no interfieran visualmente con las activas.
|
||||
* **Solución:**
|
||||
* Se definió un cuarto nivel de clasificación de prioridad:
|
||||
* `0`: Alarmas Activas (cabeza de página)
|
||||
* `1`: Sucursales Desarmadas
|
||||
* `2`: Sucursales Armadas (Stay, Away, etc.)
|
||||
* `3`: Sucursales Revocadas / Desconectadas (con fondo gris)
|
||||
* Todas las tarjetas dentro de cada categoría mantienen su estricto orden secuencial numérico.
|
||||
|
||||
### 10. Polling en Segundo Plano & Controles (Kill-Switch y Circuit Breaker)
|
||||
* **Problema:** El usuario requería monitoreo continuo sin bloqueos de API de Honeywell y con la capacidad de detener el polling manualmente o si Honeywell responde errores de autenticación/rate limit.
|
||||
* **Solución:**
|
||||
* **Motor Poller Daemon (`background_poller_thread`):** Se ejecuta cada 45s en segundo plano en el servidor Python.
|
||||
* **Circuit Breaker:** Si se registran 2 fallos de autenticación seguidos (`401` / `429`), el backend desactiva el polling automático previniendo bloqueos de IP de Honeywell.
|
||||
* **Endpoints Controladores:** Agregados `GET /polling-status` y `POST /toggle-polling`.
|
||||
* **Botonera en UI:** Se agregó el botón interactivo `[ ● Polling: Activo ]` / `[ ○ Polling: Pausado ]` en el encabezado.
|
||||
* **Auto-Focus (`visibilitychange`):** El navegador recarga el estatus automáticamente al regresar a la pestaña tras periodos de inactividad.
|
||||
|
||||
---
|
||||
|
||||
## 🔬 Verificación y Pruebas
|
||||
|
||||
* **Compilación y Empaquetado:** Generación exitosa de `totalconnect.exe` en Windows `E:\Software\TotalConnect\dist\totalconnect.exe`.
|
||||
* **Sincronización:** Actualizado y desplegado en segundo plano en la VM de Linux accesible a través del puerto `8080`.
|
||||
* **Validación de Funcionalidad:** Todas las rutas del dashboard, filtros por JSON, exclusiones y endpoints de polling operan correctamente.
|
||||
Reference in New Issue
Block a user