diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 549c10b..d0a6a24 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,325 +1,329 @@ -# Especificación de Arquitectura del Sistema -## Sistema de Monitoreo de Parámetros Fisicoquímicos para Fotobiorreactor - -**Revisión:** 2.0 -**Estado:** Vigente - ---- - -## 1. Visión General del Sistema - -El sistema implementa una arquitectura de cuatro capas desacopladas que operan de forma asíncrona sobre una red local. El flujo de datos se inicia en el hardware físico del sensor (bus I²C) y se propaga hasta el navegador web del operador mediante una cadena de transformaciones bien definidas. En la fase actual de desarrollo, la capa de hardware es emulada por un servidor de simulación (*mock*) Node.js que reproduce fielmente las latencias y los formatos de respuesta de los módulos Atlas Scientific EZO. - -### 1.1. Diagrama de Capas - -``` -┌──────────────────────────────────────────────────────────────────────┐ -│ CAPA 4 — PRESENTACIÓN │ -│ Navegador web (HTML5, CSS3, Vanilla JS ES6+, Chart.js, SheetJS) │ -│ Polling cada 1000 ms → GET /data/*.json │ -│ Envío de comandos → POST /api/sensors/:type/command │ -├──────────────────────────────────────────────────────────────────────┤ -│ CAPA 3 — ENRUTAMIENTO Y PROXY │ -│ Nginx, puerto 8888 │ -│ - Entrega de archivos estáticos del frontend (HTML, CSS, JS) │ -│ - Proxy inverso transparente: /api/* → http://127.0.0.1:3000 │ -├──────────────────────────────────────────────────────────────────────┤ -│ CAPA 2 — LÓGICA DE NEGOCIO Y API │ -│ Node.js + Express, puerto 3000 │ -│ - GET /api/sensors/:type → historial simulado para exportación │ -│ - POST /api/sensors/:type/command → parser léxico EZO completo │ -├──────────────────────────────────────────────────────────────────────┤ -│ CAPA 1 — ADQUISICIÓN DE DATOS (HARDWARE / SIMULADO) │ -│ Demonios C nativos en Raspberry Pi (producción futura) │ -│ Lectura por I²C: /dev/i2c-1 @ 100 kHz │ -│ Módulos: EZO-RTD (0x66), EZO-pH (0x63), EZO-DO (0x61), EZO-EC (0x64)│ -└──────────────────────────────────────────────────────────────────────┘ +# Arquitectura Del Sistema + +## Objetivo + +El sistema mide variables fisicoquimicas de un fotobiorreactor usando una +Raspberry Pi y circuitos Atlas Scientific EZO por I2C. La Raspberry ejecuta una +API, un recolector de datos, Nginx y un dashboard web. + +La arquitectura evita un driver personalizado de kernel. El acceso al hardware +se realiza desde espacio de usuario mediante `/dev/i2c-1`. + +## Vista General + +```text +Sondas fisicas + | +Circuitos Atlas Scientific EZO + | +Bus I2C de Raspberry Pi (/dev/i2c-1) + | ++------------------------------+ +| Helpers C | +| - EZO_ACQUIRE | +| - EZO_COMMAND | ++------------------------------+ + | ++------------------------------+ +| Backend Node.js | +| - API Express | +| - Recolector continuo | +| - Alarmas | +| - Notificaciones | ++------------------------------+ + | ++------------------------------+ +| Archivos locales | +| - data/*.json | +| - logs/*.csv | +| - config/*.json | ++------------------------------+ + | ++------------------------------+ +| Nginx + Dashboard web | ++------------------------------+ ``` ---- +## Capas -## 2. Topología de Red Local y Flujo de Datos Asíncrono +### 1. Hardware -### 2.1. Topología +Sensores principales: -El sistema opera exclusivamente en una red de área local (LAN). Un único nodo Raspberry Pi actúa como servidor de todos los servicios. Los clientes son navegadores web en la misma red. No existe comunicación hacia redes externas en la configuración de producción. +| Variable | Circuito | Direccion | +|---|---|---:| +| Temperatura | EZO-RTD | `0x66` | +| pH | EZO-pH | `0x63` | +| Oxigeno disuelto | EZO-DO | `0x61` | +| Conductividad | EZO-EC | `0x64` | -``` - [Navegador del operador] - │ - │ HTTP, puerto 8888 - ▼ - [Nginx — Proxy Inverso] - │ │ - │ Estático │ /api/* → proxy - ▼ ▼ - [frontend/] [Node.js Express — puerto 3000] - │ - │ Simula protocolo I²C EZO (fase actual) - │ ───────────────────────────────────── - │ Producción futura: lectura real de - │ archivos JSON escritos por demonios C - ▼ - [data/EZORTD.json] - [data/EZOPH.json ] ← escritos por demonios C - [data/EZODO.json ] (Capa 1 / hardware) - [data/EZOEC.json ] -``` +Los sensores deben estar en modo I2C. Si un sensor esta en UART no aparecera en +`i2cdetect`. -### 2.2. Flujo de Datos Asíncrono — Lectura en Vivo +### 2. Helpers C -``` -1. El navegador ejecuta `setInterval(updateDashboard, 1000)`. -2. `dashboard.js` lee `data/EZORTD.json`, `data/EZOPH.json`, `data/EZODO.json` y `data/EZOEC.json`. -3. En paralelo, lee los umbrales desde `config/alarms.json`. -4. El navegador valida cada valor, actualiza el DOM y evalúa alarmas. -5. `renderAlarmSummary()` actualiza el resumen de riesgo global. -6. Las gráficas leen los CSV de `logs/` con un intervalo configurable. - -La API Express no participa actualmente en la lectura en vivo. Se utiliza para -comandos EZO reales o de demostracion, exportaciones con datos simulados y -operaciones de administracion del historial. +Ubicacion: + +```text +sensors/EZOCommand/ ``` -### 2.3. Flujo de Datos Asíncrono — Comando EZO (Consola de Hardware) +Binarios: -``` -1. El operador selecciona el sensor y emite un comando desde la interfaz -2. ezo-service.js ejecuta: POST /api/sensors/:type/command - Body: { "command": "cal,mid,7.00" } -3. Nginx reenvía la petición al puerto 3000 -4. El parser léxico de Express descompone el comando por comas: - parts = ["cal", "mid", "7.00"], baseCmd = "cal" -5. Se aplica la latencia de procesamiento químico correspondiente (600 ms para CAL) -6. El servidor responde: { "success": true, "sensor": "PH", "response": "*OK" } -7. ezo-service.js imprime el intercambio TX/RX en el terminal virtual de la UI +```text +EZO_ACQUIRE +EZO_COMMAND ``` ---- +`EZO_ACQUIRE` toma lecturas agrupadas. En lugar de esperar un segundo por cada +sensor, envia `R` a los sensores habilitados, espera una sola ventana de +conversion y luego recoge respuestas. Esto reduce tiempo de ciclo y carga del +bus. -## 3. Especificación de la API REST +`EZO_COMMAND` envia un comando a un circuito especifico. Se usa para: -### 3.1. Endpoint de Telemetría +- `i` +- `Status` +- `R` +- `Cal,?` +- Calibraciones +- Compensaciones +- Cambios de configuracion EZO -**`GET /api/sensors/:type`** +Ambos usan: -Parámetros de ruta: +```text +/tmp/photobioreactor-i2c.lock +``` -| Parámetro | Valores válidos | Descripción | -|---|---|---| -| `type` | `rtd`, `ph`, `do`, `ec`, `all` | Identificador del módulo sensor | +Ese lock evita acceso simultaneo al bus I2C. -Latencia simulada: 400 ms (emula el tiempo de procesamiento I²C más la conversión del ADC interno del EZO). +### 3. Recolector -Respuesta exitosa — tipo específico (HTTP 200): +Archivo: -```json -[ - { - "Timestamp": "2025-05-30T14:22:01.000Z", - "Sensor": "RTD", - "Valor": "25.04" - }, - ... -] +```text +api/acquisition.js ``` -Respuesta exitosa — tipo `all` (HTTP 200): - -```json -[ - { - "Timestamp": "2025-05-30T14:22:01.000Z", - "Temperatura_C": "25.04", - "pH": "7.21", - "DO_mgL": "8.52", - "EC_uS": "1048" - }, - ... -] -``` +Responsabilidades: -Respuesta de error — tipo no reconocido (HTTP 400): +- Leer configuracion de runtime. +- Ejecutar adquisicion en modo demo o hardware. +- Publicar JSON actual por sensor. +- Agregar filas CSV. +- Evaluar alarmas. +- Despachar notificaciones. +- Aplicar retencion historica. -```json -{ "error": "Sensor no válido" } -``` +Servicio: -### 3.2. Endpoint de Comandos EZO +```text +photobioreactor-acquisition.service +``` -**`POST /api/sensors/:type/command`** +### 4. API -Cuerpo de la petición (`Content-Type: application/json`): +Archivo: -```json -{ "command": "" } +```text +api/server.js ``` -Respuesta exitosa (HTTP 200): +Responsabilidades: -```json -{ - "success": true, - "sensor": "PH", - "command": "cal,mid,7.00", - "response": "*OK" -} -``` +- Servir endpoints de configuracion. +- Exponer historicos para exportacion. +- Ejecutar comandos EZO. +- Guardar umbrales. +- Guardar notificaciones. +- Limpiar historicos. +- Servir bibliotecas locales `Chart.js` y `SheetJS`. -### 3.3. Tabla de Comandos EZO Soportados por el Parser Léxico +Servicio: -| Comando base | Aplica a | Latencia simulada | Respuesta representativa | -|---|---|---|---| -| `i` | Todos | 300 ms | `?I,RTD,2.12` | -| `status` | Todos | 300 ms | `?STATUS,P,5.03` | -| `r` | Todos | 900 ms | `25.047` / `7.22` / `8.51` / `1052` | -| `cal` | Todos | 600 ms | `*OK` / `?CAL,1` | -| `sleep` | Todos | 0 ms | `[SLEEP MODE ACTIVADO]` | -| `factory` | Todos | 800 ms | `*OK` | -| `find` | Todos | 300 ms | `*OK` | -| `led` | Todos | 300 ms | `?LED,1` / `*OK` | -| `plock` | Todos | 300 ms | `?PLOCK,1` / `*OK` | -| `i2c` | Todos | 300 ms | `*OK` | -| `t`, `s`, `p` | Todos | 300 ms | `?T,25.0` / `*OK` | -| `slope` | PH | 300 ms | `?Slope,99.7,100.3,-0.89` | -| `k` | EC | 300 ms | `?K,1.0` / `*OK` | -| `tc` | EC | 300 ms | `?TC,1.90` / `*OK` | -| `o` | EC | 300 ms | `?O,EC,TDS,S,SG` / `*OK` | -| Desconocido | Todos | 300 ms | `*ER` | +```text +photobioreactor-api.service +``` ---- +### 5. Frontend -## 4. Especificación Técnica de la Capa de Hardware +Ubicacion: -### 4.1. Protocolo de Comunicación I²C con Módulos EZO +```text +frontend/ +``` -Todos los módulos EZO de Atlas Scientific implementan el protocolo I²C con la siguiente secuencia de operación para una lectura (comando `R`): +Archivos principales: +| Archivo | Uso | +|---|---| +| `index.html` | Estructura del dashboard | +| `dashboard.css` | Diseno responsive | +| `dashboard.js` | Lecturas, graficas, alarmas y configuracion | +| `ezo-service.js` | Consola y calibracion EZO | +| `export-service.js` | Exportacion CSV | +| `export-excel.js` | Exportacion Excel | + +El dashboard lee JSON cada segundo y actualiza tarjetas, estados y resumen de +alarmas. + +Las graficas se actualizan cada 10 segundos por defecto y muestran solo el dia +actual. Los CSV conservan el historico segun la retencion configurada. + +### 6. Nginx + +Nginx sirve el frontend y redirige `/api/` hacia Express. En produccion la API +escucha en `127.0.0.1`; Nginx es la entrada HTTP para navegadores de la red +local. + +## Flujo De Lectura + +```text +1. systemd inicia photobioreactor-acquisition. +2. El recolector lee config/runtime.json. +3. El recolector ejecuta EZO_ACQUIRE con los sensores habilitados. +4. EZO_ACQUIRE toma el lock I2C. +5. EZO_ACQUIRE consulta los EZO por /dev/i2c-1. +6. El recolector escribe data/*.json. +7. El recolector agrega filas a logs/*.csv. +8. El dashboard lee data/*.json cada segundo. +9. El dashboard actualiza tarjetas, alarmas y graficas. ``` -1. ioctl(fd, I2C_SLAVE, ADDR) — seleccionar dirección del esclavo -2. write(fd, "R", 1) — emitir el comando de lectura (ASCII 0x52) -3. usleep(1000000) — esperar 1000 ms para conversión analógica interna -4. read(fd, response, 32) — leer la respuesta del módulo -5. Verificar response[0] == 0x01 — código de estado: 0x01 indica éxito -6. atof(&response[1]) — parsear el float ASCII desde el byte 1 en adelante + +## Flujo De Comandos Y Calibracion + +```text +1. El operador usa la consola o el panel de calibracion. +2. El frontend envia POST /api/sensors/:type/command. +3. La API valida token y comando. +4. La API ejecuta EZO_COMMAND. +5. EZO_COMMAND toma el lock I2C. +6. EZO_COMMAND envia el comando al circuito. +7. La API devuelve la respuesta real o demo. +8. La interfaz muestra TX/RX y, si aplica, consulta Cal,?. ``` -Tabla de códigos de estado en `response[0]`: +Para comandos manuales desde terminal, detenga primero el recolector: -| Código | Significado | -|---|---| -| `0x01` | Éxito — dato válido disponible | -| `0x02` | Error de sintaxis en el comando | -| `0xFE` | Pendiente — conversión no completada | -| `0xFF` | Sin datos disponibles | +```bash +sudo systemctl stop photobioreactor-acquisition +sudo rm -f /tmp/photobioreactor-i2c.lock +``` -### 4.2. Mapa de Direcciones I²C del Bus +## Archivos De Datos -| Módulo | Dirección I²C | Constante en código fuente | -|---|---|---| -| EZO-RTD | `0x66` | `EZORTD_I2C_ADDR` | -| EZO-pH | `0x63` | `EZOPH_I2C_ADDR` | -| EZO-DO | `0x61` | `EZODO_I2C_ADDR` | -| EZO-EC | `0x64` | `EZOEC_I2C_ADDR` | +Lectura actual: -Ninguna dirección colisiona en el espacio de 7 bits del protocolo I²C estándar. El bus opera en modo maestro único (*single-master*), lo que elimina la necesidad de arbitraje. +```text +data/EZORTD.json +data/EZOPH.json +data/EZODO.json +data/EZOEC.json +``` ---- +Historicos: -## 5. Arquitectura de Hardware Propuesta — Fase 9: Shield PCB con Aislamiento Galvánico +```text +logs/temperature.csv +logs/ph.csv +logs/do.csv +logs/ec.csv +``` -### 5.1. Justificación Técnica del Aislamiento Galvánico +Alarmas: -La operación de sensores electroquímicos en un medio líquido conductor presenta una condición de riesgo inherente: la existencia de **corrientes parásitas de bucle de masa** (*ground loop currents*). Este fenómeno se produce cuando dos o más sensores sumergidos en el mismo líquido establecen caminos de retorno de corriente a través del propio medio líquido, creando diferencias de potencial espurias entre sus masas de referencia. +```text +logs/alarms.csv +``` -Las consecuencias operativas de esta condición son las siguientes: +Configuracion: -**Para el módulo EZO-pH:** La sonda de pH opera mediante la detección de una diferencia de potencial electroquímico (típicamente entre −414 mV y +414 mV para el rango de 0 a 14 pH) generada en el electrodo de vidrio. Una corriente parásita que atraviese el medio líquido introduce un potencial de interferencia directamente sumado a esta señal de alta impedancia, produciendo lecturas de pH sistemáticamente desplazadas y no reproducibles. +```text +config/runtime.json +config/alarms.json +config/sensors.json +config/notifications.json +``` -**Para el módulo EZO-EC:** La medición de conductividad eléctrica se realiza mediante la inyección de una señal de corriente alterna de frecuencia controlada a través de electrodos de acero inoxidable o platino sumergidos. La presencia de corrientes parásitas de corriente continua procedentes de otros sistemas altera la conductividad aparente del medio, introduciendo errores proporcionales a la magnitud de la corriente de interferencia. +En Raspberry instalada, la aplicacion vive en: -**Para el módulo EZO-DO:** Aunque la sonda de oxígeno disuelto es en términos eléctricos menos sensible que el electrodo de pH, las corrientes parásitas pueden inducir polarización electrolítica en los electrodos de platino de las sondas galvánicas, degradando irreversiblemente la membrana de politetrafluoroetileno (PTFE) y alterando la cinética de reducción del oxígeno. +```text +/opt/photobioreactor +``` -### 5.2. Solución de Diseño: Aisladores Digitales I²C y Convertidores DC-DC Aislados +Las notificaciones de produccion viven en: -La arquitectura de la PCB propuesta para la Fase 9 implementa una barrera galvánica completa en cada canal de sensor mediante dos componentes: +```text +/etc/photobioreactor/notifications.json +``` -**Aislador digital bidireccional I²C — Texas Instruments ISO1540:** +## Estados De Sensor -El ISO1540 es un aislador de capacitancia de silicio que implementa los canales SDA y SCL del bus I²C de forma completamente aislada, con una rigidez dieléctrica de 2500 V RMS. El dispositivo detecta el estado lógico de cada línea en el lado primario (Raspberry Pi) y reproduce la señal en el lado secundario (módulo EZO) sin conexión eléctrica directa. Sus características operativas relevantes son: +| Estado | Significado | +|---|---| +| `NORMAL` | Valor valido dentro del rango | +| `WARNING` | Valor cerca de un limite | +| `CRITICAL` | Valor fuera de rango | +| `OFFLINE` | Sensor habilitado sin lectura valida | +| `DISABLED` | Sensor deshabilitado por configuracion | -- Velocidad máxima de transferencia: 1 Mbps (compatible con el modo *Fast-mode Plus* de I²C) -- Corriente de cortocircuito de salida: ±4 mA (compatible con los pull-ups del bus) -- Tiempo de propagación: < 15 ns -- Consumo en standby: < 1 mA por canal +## Seguridad -**Convertidor DC-DC aislado — Mornsun B0303S-1W (o equivalente):** +La API protege acciones criticas con `API_AUTH_TOKEN` si esta configurado. -El ISO1540 requiere dos dominios de alimentación físicamente separados: VCC1 (lado Raspberry Pi, 3.3 V) y VCC2 (lado módulo EZO). Si ambos dominios comparten la misma referencia de tierra, la barrera galvánica del aislador digital resulta inoperante, ya que el bucle de masa se cierra a través del plano de tierra compartido de la PCB. +Acciones protegidas: -El B0303S-1W es un convertidor DC-DC de 1 W, entrada 3.3 V, salida 3.3 V, con aislamiento galvánico de 1500 V DC entre sus terminales de entrada y salida. Su interposición entre el plano de tierra de la Raspberry Pi y el plano de tierra de cada módulo EZO garantiza que no exista ningún camino eléctrico directo entre ambos dominios, eliminando efectivamente el bucle de masa. +- Comandos EZO. +- Calibraciones. +- Cambios de umbrales. +- Cambios de runtime. +- Cambios de notificaciones. +- Borrado de historicos. -### 5.3. Esquema Conceptual del Aislamiento por Canal +El dashboard envia el token como: +```text +X-API-Token ``` - Dominio Raspberry Pi (GND_PI) Dominio Sensor (GND_EZO) - ───────────────────────────── ──────────────────────── - 3.3V ──┬─────────────────────────────── VCC_in (B0303S) ──► VCC_out → VCC_EZO - │ │ │ - │ [BARRERA 1500V] │ - │ GND_EZO (flotante respecto a GND_PI) - │ - ├── SDA_PI ──► ISO1540 ──────────────────────────────────► SDA_EZO - │ [BARRERA 2500V RMS] - └── SCL_PI ──► ISO1540 ──────────────────────────────────► SCL_EZO -``` - -Este esquema se replica de forma independiente para cada uno de los cuatro módulos EZO, garantizando el aislamiento no solo respecto a la Raspberry Pi sino también entre los sensores entre sí, lo que elimina por completo los caminos de corriente parásita a través del medio líquido del fotobiorreactor. - ---- -## 6. Sistema de Evaluación de Alarmas +## Almacenamiento -### 6.1. Lógica de Evaluación +El crecimiento principal viene de los CSV historicos. Los JSON se sobrescriben. -El módulo `evaluateSensorAlarm()` de `dashboard.js` implementa una máquina de estados de cuatro niveles para cada sensor, evaluada en cada ciclo de actualización (1000 ms): +Peor caso operativo: -``` -Estado OFFLINE: JSON faltante, HTTP error, valor no numérico -Estado CRITICAL: valor < limits.min OR valor > limits.max -Estado WARNING: valor dentro del rango, pero dentro del 10% de los límites -Estado NORMAL: valor dentro del rango, fuera de la banda de advertencia +```text +4 sensores +1 lectura por segundo +30 dias ``` -La banda de advertencia se calcula como: +Resultado aproximado: -``` -margen_advertencia = (limits.max - limits.min) × WARNING_MARGIN_RATIO -WARNING si: valor ≤ (limits.min + margen_advertencia) OR - valor ≥ (limits.max - margen_advertencia) +```text +350 a 375 MB por mes ``` -donde `WARNING_MARGIN_RATIO = 0.10` (configurable en `dashboard.js`). +Ver detalles en: -### 6.2. Umbrales Operativos Configurados - -Definidos en `config/alarms.json`: - -| Variable | Mínimo | Máximo | Unidad | -|---|---|---|---| -| Temperatura | 20.0 | 30.0 | °C | -| pH | 6.8 | 7.5 | pH | -| Oxígeno Disuelto | 4.0 | 12.0 | mg/L | -| Conductividad Eléctrica | 500 | 2500 | µS/cm | - ---- - -## 7. Módulo de Exportación de Datos +```text +docs/STORAGE_ESTIMATE.md +``` -### 7.1. Exportación CSV +## Razon Para No Usar Driver De Kernel -La función `handleExport(sensorType)` en `export-service.js` recupera el historial mediante `fetchHistoricalData()`, convierte el arreglo de objetos JSON a texto CSV mediante `convertToCSV()` y fuerza la descarga del archivo en el navegador mediante un enlace temporal con `URL.createObjectURL()`. +El protocolo Atlas EZO es ASCII sobre I2C. No requiere temporizacion de kernel +ni procesamiento en tiempo real estricto. Mantenerlo en espacio de usuario +permite: -### 7.2. Exportación XLSX Multipagina +- Diagnostico con comandos simples. +- Cambios rapidos de calibracion. +- Menor riesgo de bloquear el sistema. +- Despliegue mas sencillo. +- Compatibilidad directa con Raspberry Pi OS. -La función `handleExportExcel()` en `export-excel.js` itera sobre los cuatro sensores, recupera los datos de cada uno, crea una hoja de cálculo independiente con `XLSX.utils.json_to_sheet()` y las consolida en un único libro de trabajo (`Workbook`) mediante `XLSX.utils.book_append_sheet()`. El archivo binario `.xlsx` se descarga mediante `XLSX.writeFile()`. +Un driver de kernel solo tendria sentido si existiera una necesidad medible que +no pueda resolverse con `/dev/i2c-1`, por ejemplo latencias estrictas, +integracion profunda con subsistemas Linux o requerimientos industriales +especificos. diff --git a/PROJECT_STATUS.md b/PROJECT_STATUS.md index 496f667..932ecca 100644 --- a/PROJECT_STATUS.md +++ b/PROJECT_STATUS.md @@ -1,113 +1,195 @@ # Estado del Proyecto -## Estado actual - -El dashboard integra monitoreo en vivo, alarmas configurables, tendencias, -exportación CSV/Excel, consola EZO y calibración. La adquisición puede operar en -modo demo o en Raspberry Pi mediante `/dev/i2c-1`. - -## Arquitectura operativa +## Resumen + +El proyecto implementa un dashboard web para monitoreo de fotobiorreactor con +Raspberry Pi y circuitos Atlas Scientific EZO. La aplicacion puede trabajar en +modo demo para desarrollo sin hardware y en modo hardware usando `/dev/i2c-1`. + +## Estado Actual + +Implementado: + +- Dashboard responsive. +- Lecturas en vivo desde `data/*.json`. +- Adquisicion automatica con `api/acquisition.js`. +- Helper C `EZO_ACQUIRE` para lecturas agrupadas. +- Helper C `EZO_COMMAND` para comandos y calibracion. +- Historial CSV por sensor. +- Graficas con Chart.js. +- Exportacion CSV y Excel con SheetJS. +- Alarmas configurables. +- Bitacora de alarmas en `logs/alarms.csv`. +- Notificaciones por webhook y Telegram. +- Configuracion de sensores habilitados. +- Retencion historica configurable. +- Servicios `systemd` para API y adquisicion. +- Configuracion Nginx. +- Instalador para Raspberry Pi. + +## Componentes Principales | Componente | Responsabilidad | |---|---| -| `api/server.js` | API, históricos, configuración y comandos EZO | -| `api/acquisition.js` | Ciclo continuo de adquisición | -| `api/acquisition-service.js` | Escritura atómica de JSON/CSV y configuración | -| `sensors/EZOCommand/EZO_ACQUIRE` | Lectura agrupada de los cuatro EZO | -| `sensors/EZOCommand/EZO_COMMAND` | Comandos y calibración de un circuito | -| `frontend/` | Dashboard, gráficas, alarmas, exportación y consola | - -Los dos helpers C usan `/tmp/photobioreactor-i2c.lock`. El recolector inicia la -conversión de los cuatro sensores antes de esperar, por lo que comparte una sola -ventana de procesamiento en vez de bloquear un segundo por sensor. - -## Funciones implementadas - -- Lecturas de RTD, pH, DO y EC con publicación en `data/*.json`. -- Históricos normalizados como `logs/temperature.csv`, `ph.csv`, `do.csv` y - `ec.csv`, todos con formato `timestamp,value`. -- Escritura atómica de JSON y estado `online: false` ante fallos globales o - lecturas individuales inválidas. -- Detección de datos obsoletos con tolerancia proporcional a la frecuencia. -- Frecuencia persistente de 1, 5, 10 o 60 segundos en `config/runtime.json`. -- Exportaciones alimentadas por CSV reales, sin generación aleatoria en la API. -- Verificación automática `Cal,?` después de una calibración enviada desde web. -- Chart.js 4.5.1 y SheetJS 0.20.3 instalados localmente. -- Servicios systemd, configuración Nginx e instalador para Raspberry Pi. - -## Configuracion parcial de sensores - -- `config/runtime.json` guarda `enabledSensors`. -- Los sensores deshabilitados se muestran como `DESHABILITADO`. -- Un sensor deshabilitado no cuenta como `OFFLINE`, alarma ni riesgo global. - -## Seguridad operativa - -- `API_AUTH_TOKEN` protege endpoints criticos cuando esta configurado. -- El dashboard envia el token como `X-API-Token` desde almacenamiento local del - navegador. -- La API compara tokens en tiempo constante y emite headers defensivos basicos. -- Los POST criticos usan rate limit configurable en memoria. -- Sin `API_AUTH_TOKEN`, el modo desarrollo permanece sin autenticacion. - -## Bitacora de alarmas - -- `logs/alarms.csv` registra transiciones a `WARNING`, `CRITICAL`, `OFFLINE` y - recuperaciones `RECOVERY`. -- `GET /api/alarms` expone los eventos para dashboard y futuras notificaciones. -- Los sensores `DISABLED` no generan eventos de alarma. - -## Umbrales configurables - -- `GET /api/config/alarms` expone los limites actuales. -- `POST /api/config/alarms` valida y persiste cambios en `config/alarms.json`. -- El dashboard permite editar min/max por sensor; guardar requiere token si - `API_AUTH_TOKEN` esta activo. - -## Retencion historica - -- `historyRetentionDays` en `config/runtime.json` controla poda automatica de - CSV. -- Valores permitidos: 7, 30, 90, 365 o 0 para retencion indefinida. -- La poda conserva los nombres actuales de archivos para no romper graficas ni - exportaciones. -- Las graficas filtran visualmente el dia actual; los CSV mantienen todos los - registros disponibles dentro de la retencion configurada. +| `frontend/` | Dashboard, graficas, controles, exportaciones y consola EZO | +| `api/server.js` | API HTTP, configuracion, historicos, comandos y seguridad | +| `api/acquisition.js` | Proceso continuo de adquisicion | +| `api/acquisition-service.js` | Lectura, escritura atomica, alarmas y retencion | +| `api/notification-service.js` | Webhook y Telegram | +| `sensors/EZOCommand/EZO_ACQUIRE` | Lectura agrupada de sensores EZO | +| `sensors/EZOCommand/EZO_COMMAND` | Comandos individuales EZO | +| `config/*.json` | Configuracion operativa | +| `deployment/` | Servicios systemd, Nginx y variables de entorno | +| `scripts/install-raspberry-pi.sh` | Instalacion automatizada en Raspberry Pi | + +## Sensores + +| Sensor | Direccion esperada | Estado en software | +|---|---:|---| +| EZO-RTD | `0x66` | Implementado | +| EZO-pH | `0x63` | Implementado | +| EZO-DO | `0x61` | Implementado | +| EZO-EC | `0x64` | Implementado | + +El sistema tambien puede detectar otros EZO en el bus, por ejemplo ORP, pero el +dashboard actual solo modela RTD, pH, DO y EC. + +## Modos De Operacion + +| Modo | Uso | +|---|---| +| `EZO_MODE=demo` | Desarrollo sin Raspberry ni sensores | +| `EZO_MODE=auto` | Usa hardware si esta disponible; si no, demo | +| `EZO_MODE=hardware` | Produccion estricta; no simula datos | + +En Raspberry Pi de produccion se usa `EZO_MODE=hardware`. + +## Datos + +Lecturas actuales: + +- `data/EZORTD.json` +- `data/EZOPH.json` +- `data/EZODO.json` +- `data/EZOEC.json` + +Historicos: + +- `logs/temperature.csv` +- `logs/ph.csv` +- `logs/do.csv` +- `logs/ec.csv` + +Formato: + +```csv +timestamp,value +2026-07-07T17:26:13.459Z,25.132 +``` + +Las graficas muestran el dia actual. Los CSV conservan el periodo configurado +por `historyRetentionDays`. + +## Alarmas + +Los umbrales viven en: + +```text +config/alarms.json +``` + +Estados: + +- `NORMAL` +- `WARNING` +- `CRITICAL` +- `OFFLINE` +- `DISABLED` + +Los eventos se guardan en: + +```text +logs/alarms.csv +``` + +Los sensores deshabilitados no generan alarma ni riesgo global. ## Notificaciones -- `config/notifications.json` permite activar webhook y Telegram. -- `GET /api/config/notifications` devuelve configuracion redactada. -- `POST /api/config/notifications` valida y persiste canales con token. -- El recolector despacha notificaciones desde eventos de `logs/alarms.csv`. -- `docs/TELEGRAM_BOT_SETUP.md` documenta creacion del bot, obtencion de - `chatId`, configuracion, pruebas y diagnostico. +Configuracion: + +```text +config/notifications.json +``` + +En produccion: + +```text +/etc/photobioreactor/notifications.json +``` + +Canales: + +- Webhook HTTP. +- Telegram Bot API. + +El backend redacta secretos cuando envia configuracion al navegador. + +## Seguridad + +Implementado: + +- `API_AUTH_TOKEN` para endpoints criticos. +- Header `X-API-Token`. +- Comparacion de token en tiempo constante. +- Rate limit para acciones criticas. +- Headers HTTP defensivos basicos. +- API escuchando en `127.0.0.1` detras de Nginx. + +Pendiente si se expone fuera de LAN: + +- HTTPS. +- Autenticacion de usuario completa. +- Politica de acceso por VPN o red privada. + +## Validacion + +Validado en desarrollo: -## Modos +- Pruebas automatizadas Node. +- Modo demo. +- Dashboard por HTTP local. +- Chart.js y SheetJS locales. +- Comandos EZO simulados. +- Configuracion de alarmas y notificaciones. -- `EZO_MODE=demo`: adquisición y comandos simulados. -- `EZO_MODE=auto`: hardware cuando existen el bus y los helpers; demo en otro - caso. -- `EZO_MODE=hardware`: producción estricta; un despliegue incompleto falla y no - genera valores simulados. +Validacion en Raspberry: -## Verificación realizada +- I2C mediante `/dev/i2c-1`. +- Servicios `systemd`. +- Lecturas reales parciales cuando los sensores estan conectados. -- 16 pruebas automáticas aprobadas. -- Validación sintáctica de todos los JavaScript modificados. -- Dashboard, Chart.js, SheetJS y comando pH comprobados por HTTP en modo demo. -- `npm audit --omit=dev`: cero vulnerabilidades conocidas. +La calibracion metrologica y la estabilidad final deben verificarse siempre con +sondas reales, soluciones de referencia y operacion continua. -La compilación ARM, el bus I2C, la estabilidad de las sondas y las calibraciones -metrológicas solo pueden verificarse en la Raspberry Pi con hardware real. +## Trabajo Pendiente Recomendado -## Trabajo pendiente en hardware +- Prueba continua de 8 a 24 horas en Raspberry. +- Validacion con los cuatro sensores conectados. +- Calibracion real documentada con fecha y soluciones usadas. +- Confirmar notificaciones Telegram en la red final. +- Evaluar integracion futura de ORP si se decide usar ese sensor. +- Mejorar exportaciones para seleccionar rango: dia actual, ultimas 24 horas o + todo el historico. -1. Ejecutar `i2cdetect -y 1` y confirmar `0x61`, `0x63`, `0x64` y `0x66`. -2. Compilar ambos helpers con `make -C sensors/EZOCommand`. -3. Validar `i`, `Status`, `R` y `Cal,?` individualmente. -4. Realizar las calibraciones con soluciones de referencia. -5. Probar desconexiones, reinicio automático y operación continua de varias - horas. +## Documentos Relacionados -Consulte `docs/RASPBERRY_PI_DEPLOYMENT.md` para el procedimiento completo. +- `README.md` +- `docs/README.md` +- `docs/QUICK_START.md` +- `docs/RASPBERRY_PI_DEPLOYMENT.md` +- `docs/EZO_COMMANDS.md` +- `docs/TROUBLESHOOTING.md` +- `docs/STORAGE_ESTIMATE.md` +- `docs/TELEGRAM_BOT_SETUP.md` +- `ARCHITECTURE.md` diff --git a/README.md b/README.md index 7ab8ada..f5f85ce 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,103 @@ # Photobioreactor Dashboard -Sistema de monitoreo para Raspberry Pi y circuitos Atlas Scientific EZO: +Dashboard web para monitorear un fotobiorreactor con Raspberry Pi y circuitos +Atlas Scientific EZO por I2C. -| Variable | Circuito | Dirección | Unidad | -|---|---|---|---| -| Temperatura | EZO-RTD | `0x66` | °C | -| pH | EZO-pH | `0x63` | pH | -| Oxígeno disuelto | EZO-DO | `0x61` | mg/L | -| Conductividad | EZO-EC | `0x64` | µS/cm | +El sistema ya contempla: -El sistema incluye dashboard responsive, históricos Chart.js, alarmas, -exportación CSV/Excel, consola de comandos y panel de calibración. +- Lecturas en vivo de temperatura, pH, oxigeno disuelto y conductividad. +- Historial CSV por sensor. +- Graficas Chart.js. +- Alarmas configurables. +- Exportacion CSV y Excel. +- Consola de comandos EZO. +- Panel de calibracion. +- Notificaciones por webhook y Telegram. +- Despliegue permanente con `systemd` y Nginx en Raspberry Pi. -## Arquitectura +## Lectura Rapida + +Si es la primera vez que usas el proyecto, sigue este orden: + +1. [Inicio rapido](docs/QUICK_START.md) +2. [Despliegue en Raspberry Pi](docs/RASPBERRY_PI_DEPLOYMENT.md) +3. [Comandos y calibracion EZO](docs/EZO_COMMANDS.md) +4. [Diagnostico de problemas](docs/TROUBLESHOOTING.md) + +Si ya conoces el sistema y necesitas detalle tecnico: + +- [Arquitectura](ARCHITECTURE.md) +- [Estado del proyecto](PROJECT_STATUS.md) +- [Calculo de almacenamiento](docs/STORAGE_ESTIMATE.md) +- [Telegram](docs/TELEGRAM_BOT_SETUP.md) + +## Sensores Esperados + +| Variable | Circuito | Direccion I2C | Archivo JSON | CSV historico | +|---|---|---:|---|---| +| Temperatura | EZO-RTD | `0x66` | `data/EZORTD.json` | `logs/temperature.csv` | +| pH | EZO-pH | `0x63` | `data/EZOPH.json` | `logs/ph.csv` | +| Oxigeno disuelto | EZO-DO | `0x61` | `data/EZODO.json` | `logs/do.csv` | +| Conductividad | EZO-EC | `0x64` | `data/EZOEC.json` | `logs/ec.csv` | + +El proyecto puede operar con sensores parciales. Un sensor deshabilitado se +muestra como `DESHABILITADO` y no cuenta como alarma. Un sensor habilitado pero +no disponible se muestra como `OFFLINE`. + +## Arquitectura Corta ```text -EZO por I2C +Sensores EZO I2C | + | /dev/i2c-1 + v EZO_ACQUIRE / EZO_COMMAND | -Recolector Node ---------> data/*.json - | logs/*.csv - | -API Express <------------ Dashboard + v +Recolector Node.js ---> data/*.json + | logs/*.csv + v +API Express <------ Dashboard web ^ | Nginx ``` -`EZO_ACQUIRE` obtiene las cuatro lecturas en un ciclo agrupado. -`EZO_COMMAND` ejecuta comandos interactivos y calibraciones. Ambos comparten el -bloqueo `/tmp/photobioreactor-i2c.lock`. +`EZO_ACQUIRE` toma lecturas agrupadas de los sensores habilitados. +`EZO_COMMAND` envia comandos individuales, incluyendo diagnostico y calibracion. +Ambos usan el mismo bloqueo: + +```text +/tmp/photobioreactor-i2c.lock +``` + +Ese bloqueo evita que una lectura automatica y un comando manual usen el bus I2C +al mismo tiempo. + +## Prueba Sin Sensores -## Desarrollo sin sensores +En una computadora de desarrollo: ```bash npm ci npm test ``` -Ejecute en dos terminales: +Modo demo en dos terminales: ```bash EZO_MODE=demo npm run acquire +``` + +```bash EZO_MODE=demo npm start ``` -Abra `http://localhost:3000/frontend/index.html`. +Abrir: + +```text +http://localhost:3000/frontend/index.html +``` En PowerShell: @@ -55,8 +106,6 @@ $env:EZO_MODE = "demo" npm run acquire ``` -Y en una segunda terminal: - ```powershell $env:EZO_MODE = "demo" npm start @@ -64,104 +113,154 @@ npm start ## Raspberry Pi -El despliegue de producción usa `EZO_MODE=hardware`, systemd y Nginx: +Instalacion de produccion desde el repo clonado: ```bash chmod +x scripts/install-raspberry-pi.sh sudo ./scripts/install-raspberry-pi.sh ``` -La guía de preparación, detección I2C, calibración y prueba integral está en -[`docs/RASPBERRY_PI_DEPLOYMENT.md`](docs/RASPBERRY_PI_DEPLOYMENT.md). +El instalador: -## Sensores conectados parcialmente +- Copia la aplicacion a `/opt/photobioreactor`. +- Instala dependencias. +- Compila `EZO_COMMAND` y `EZO_ACQUIRE`. +- Crea el usuario `photobioreactor`. +- Configura servicios `systemd`. +- Configura Nginx. +- Fuerza `EZO_MODE=hardware` para produccion. -Para pruebas con solo EZO-RTD conectado, limite la adquisicion al sensor de -temperatura desde el panel de configuracion o en `config/runtime.json`: +Servicios principales: + +```bash +systemctl status photobioreactor-api --no-pager +systemctl status photobioreactor-acquisition --no-pager +systemctl status nginx --no-pager +``` + +Dashboard: + +```text +http://IP_DE_LA_RASPBERRY/frontend/index.html +``` + +## Configuracion Operativa + +Archivo principal de operacion: + +```text +/opt/photobioreactor/config/runtime.json +``` + +Ejemplo con tres sensores conectados: + +```json +{ + "loggingRateSeconds": 5, + "historyRetentionDays": 30, + "enabledSensors": [ + "temperature", + "ph", + "ec" + ] +} +``` + +Ejemplo con los cuatro sensores: ```json { - "loggingRateSeconds": 1, - "enabledSensors": ["temperature"] + "loggingRateSeconds": 5, + "historyRetentionDays": 30, + "enabledSensors": [ + "temperature", + "ph", + "do", + "ec" + ] } ``` -Tambien puede forzarlo temporalmente por entorno: +Despues de cambiar esta configuracion: ```bash -EZO_MODE=hardware EZO_ENABLED_SENSORS=temperature npm run acquire +sudo systemctl restart photobioreactor-acquisition ``` -En produccion puede dejar `EZO_ENABLED_SENSORS=temperature` en -`/etc/default/photobioreactor` como override. Cuando esten conectados los cuatro -circuitos, deje la variable vacia y habilite RTD, pH, DO y EC desde el panel. +## Datos Guardados -## Seguridad operativa +Los JSON en `data/` se sobrescriben; no crecen de forma indefinida. +Los CSV en `logs/` si crecen hasta el limite definido por +`historyRetentionDays`. -En produccion configure `API_AUTH_TOKEN` en `/etc/default/photobioreactor` para -proteger comandos EZO, calibracion, cambios de configuracion y borrado de -historicos. El dashboard incluye un campo "Token API" que guarda el valor solo -en el navegador local y lo envia como header `X-API-Token`. -La API aplica comparacion de token en tiempo constante y headers defensivos -basicos (`nosniff`, `DENY`, `same-origin`, `no-store`). -Los POST criticos aplican rate limit en memoria mediante -`API_RATE_LIMIT_WINDOW_MS` y `API_RATE_LIMIT_MAX`. +Formato CSV: -## Bitacora de alarmas +```csv +timestamp,value +2026-07-07T17:26:13.459Z,25.132 +``` -El recolector registra transiciones de alarma en `logs/alarms.csv` y la API las -expone en `GET /api/alarms`. Se registran entradas a `WARNING`, `CRITICAL` y -`OFFLINE`, ademas de recuperaciones a `NORMAL`. +En el peor caso operativo: -## Retencion historica +```text +4 sensores +1 lectura por segundo +30 dias +``` -`config/runtime.json` define `historyRetentionDays`. El valor puede ser 7, 30, -90, 365 o 0 para conservar indefinidamente. El recolector poda filas antiguas de -CSV sin cambiar los nombres que usa el dashboard. +el sistema guarda aproximadamente: -Las graficas del dashboard muestran solo los datos del dia actual para evitar -saturacion visual. Los CSV conservan el periodo completo configurado por -retencion y siguen disponibles para exportacion. +```text +350 a 375 MB por mes +``` -## Umbrales de alarma +Ver el calculo completo en [docs/STORAGE_ESTIMATE.md](docs/STORAGE_ESTIMATE.md). -Los limites se guardan en `config/alarms.json`, se consultan con -`GET /api/config/alarms` y pueden editarse desde el dashboard. Guardar cambios -requiere `API_AUTH_TOKEN` cuando esta configurado. +## Exportaciones -## Notificaciones +Las graficas del dashboard muestran solo el dia actual para evitar saturacion +visual. Las exportaciones CSV y Excel leen el historico disponible en los CSV. +Por eso un Excel puede pesar mucho mas que lo que se ve en pantalla. -`config/notifications.json` define canales de webhook y Telegram. El recolector -envia notificaciones cuando una alarma persistente alcanza `minSeverity`. La API -expone configuracion redactada en `GET /api/config/notifications`; guardar -requiere token y nunca devuelve secretos sin redaccion. +## Seguridad -La configuracion completa del bot, `chatId`, pruebas y diagnostico esta en -[`docs/TELEGRAM_BOT_SETUP.md`](docs/TELEGRAM_BOT_SETUP.md). +En produccion configure `API_AUTH_TOKEN` en: -## Archivos de datos +```text +/etc/default/photobioreactor +``` -- Lecturas actuales: `data/EZORTD.json`, `EZOPH.json`, `EZODO.json`, - `EZOEC.json`. -- Históricos: `logs/temperature.csv`, `ph.csv`, `do.csv`, `ec.csv`. -- Umbrales: `config/alarms.json`. -- Frecuencia de adquisición: `config/runtime.json`. +Ese token protege: -Los CSV usan una única nomenclatura y el formato: +- Comandos EZO. +- Calibraciones. +- Cambios de configuracion. +- Borrado de historicos. +- Configuracion de notificaciones. -```csv -timestamp,value -2026-06-22T12:00:00.000Z,25.123 +El dashboard guarda el token solo en el navegador local y lo envia como header: + +```text +X-API-Token ``` -## Documentación +No exponga el dashboard directamente a Internet. Use una red local confiable o +una VPN. + +## Documentacion + +- [Inicio rapido](docs/QUICK_START.md) +- [Indice de documentacion](docs/README.md) +- [Despliegue en Raspberry Pi](docs/RASPBERRY_PI_DEPLOYMENT.md) +- [Comandos y calibracion EZO](docs/EZO_COMMANDS.md) +- [Diagnostico de problemas](docs/TROUBLESHOOTING.md) +- [Calculo de almacenamiento](docs/STORAGE_ESTIMATE.md) +- [Telegram](docs/TELEGRAM_BOT_SETUP.md) +- [Arquitectura](ARCHITECTURE.md) +- [Estado del proyecto](PROJECT_STATUS.md) -- Estado actual: [`PROJECT_STATUS.md`](PROJECT_STATUS.md) -- Comandos y calibración: [`docs/EZO_COMMANDS.md`](docs/EZO_COMMANDS.md) -- Despliegue: [`docs/RASPBERRY_PI_DEPLOYMENT.md`](docs/RASPBERRY_PI_DEPLOYMENT.md) -- Telegram: [`docs/TELEGRAM_BOT_SETUP.md`](docs/TELEGRAM_BOT_SETUP.md) -- Diseño extendido: [`ARCHITECTURE.md`](ARCHITECTURE.md) +## Nota Sobre Drivers Del Kernel -No se utiliza un driver personalizado del kernel. Linux ya proporciona la capa -I2C mediante `/dev/i2c-1`; el protocolo ASCII, la adquisición y la calibración -se mantienen en espacio de usuario para facilitar mantenimiento y diagnóstico. +No se usa un driver personalizado del kernel. Linux ya expone el bus I2C como +`/dev/i2c-1`. Mantener el protocolo Atlas EZO en espacio de usuario simplifica +diagnostico, mantenimiento, calibracion y despliegue. diff --git a/docs/EZO_COMMANDS.md b/docs/EZO_COMMANDS.md index 8ce30b0..3b45a3a 100644 --- a/docs/EZO_COMMANDS.md +++ b/docs/EZO_COMMANDS.md @@ -1,28 +1,71 @@ -# Comandos y calibracion Atlas Scientific EZO +# Comandos Y Calibracion Atlas Scientific EZO -Esta implementacion sigue los datasheets oficiales vigentes consultados para: +Guia para diagnostico, lectura y calibracion de circuitos Atlas Scientific EZO +usados en el fotobiorreactor. -- EZO-pH, datasheet V6.1, revision 02/2024. -- EZO-DO, datasheet V5.8, revision 03/2025. -- EZO-EC, datasheet V5.5. -- EZO-RTD, datasheet V3.7, revision 10/2024. +## Sensores Del Proyecto -## Transporte I2C +| Sensor | Circuito | Direccion esperada | +|---|---|---:| +| Temperatura | EZO-RTD | `0x66` | +| pH | EZO-pH | `0x63` | +| Oxigeno disuelto | EZO-DO | `0x61` | +| Conductividad | EZO-EC | `0x64` | -Los comandos son cadenas ASCII sin retorno de carro. Despues de escribir el -comando se espera el tiempo de procesamiento y se solicita la respuesta. +## Transporte I2C -El primer byte de una respuesta I2C es: +Los EZO reciben comandos ASCII. En I2C, la primera posicion de la respuesta es +un codigo de estado: | Codigo | Significado | -|---|---| +|---:|---| | `1` | Solicitud procesada correctamente | | `2` | Error de sintaxis | -| `254` | Procesando; aun no esta lista | -| `255` | No hay datos | +| `254` | Procesando; respuesta aun no lista | +| `255` | Sin datos disponibles | + +El helper `EZO_COMMAND` escribe el comando, espera el tiempo indicado y lee la +respuesta. Tambien reintenta si el circuito responde `254`. + +## Antes De Enviar Comandos Manuales + +Detenga el recolector para evitar conflicto con el bus: + +```bash +sudo systemctl stop photobioreactor-acquisition +sudo rm -f /tmp/photobioreactor-i2c.lock +``` + +Use la ruta instalada: + +```bash +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND /dev/i2c-1 0x63 300 i +``` + +Formato general: + +```bash +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND [--no-response] +``` -El ejecutable `sensors/EZOCommand/EZO_COMMAND` implementa este intercambio y -reintenta las respuestas pendientes. +Ejemplo: + +```bash +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND /dev/i2c-1 0x63 1000 R +``` + +## Comandos De Diagnostico + +Para cada sensor: + +```bash +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND /dev/i2c-1 0x63 300 i +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND /dev/i2c-1 0x63 300 Status +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND /dev/i2c-1 0x63 1000 R +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND /dev/i2c-1 0x63 300 Cal,? +``` + +Cambie `0x63` por la direccion correspondiente. ## Calibracion EZO-RTD @@ -30,11 +73,25 @@ Calibracion de un punto: ```text Cal, +``` + +Ejemplo: + +```text +Cal,25.00 +``` + +Consultar calibracion: + +```text Cal,? -Cal,clear ``` -Ejemplo: `Cal,25.00`. +Limpiar calibracion: + +```text +Cal,clear +``` ## Calibracion EZO-pH @@ -46,27 +103,34 @@ Cal,low,4.00 Cal,high,10.00 ``` -El punto medio siempre debe realizarse primero. Ejecutar `Cal,mid` sobre una -calibracion existente elimina los otros puntos. El estado se consulta con -`Cal,?` y la salud de la sonda con `Slope,?`. +Notas: + +- El punto medio debe hacerse primero. +- Ejecutar `Cal,mid` sobre una calibracion existente elimina los otros puntos. +- Consulte estado con `Cal,?`. +- Consulte salud de sonda con `Slope,?`. ## Calibracion EZO-DO -Un punto: +Calibracion de un punto en aire: ```text Cal ``` -Dos puntos, en este orden: +Calibracion de dos puntos: ```text Cal,0 Cal ``` -`Cal,0` usa solucion de cero oxigeno. `Cal` usa la sonda estabilizada en aire -atmosferico. Compensaciones disponibles: +Orden: + +1. `Cal,0` en solucion de cero oxigeno. +2. `Cal` con sonda estabilizada en aire atmosferico. + +Compensaciones disponibles: ```text T, @@ -77,11 +141,15 @@ P, ## Calibracion EZO-EC -Primero se configura la constante de la sonda con `K,` y se realiza la -calibracion en seco: +Primero configure constante de celda: ```text K,1.0 +``` + +Calibracion en seco: + +```text Cal,dry ``` @@ -100,29 +168,48 @@ Cal,low, Cal,high, ``` -No se debe usar `Cal,0` en EC. El valor cero corresponde unicamente al paso -`Cal,dry`. +No use `Cal,0` en EC. En EC, el punto cero corresponde a `Cal,dry`. -## Modos del backend +Compensacion de temperatura: -- `EZO_MODE=auto`: usa hardware si encuentra `/dev/i2c-1` y `EZO_COMMAND`; - de lo contrario usa demo. -- `EZO_MODE=hardware`: exige bus y ejecutable reales; si faltan, la API devuelve - error en vez de simular. -- `EZO_MODE=demo`: genera respuestas de desarrollo sin acceder al bus. +```text +T, +T,? +``` + +## Cambiar Direccion I2C + +Use esto solo si sabe que la nueva direccion esta libre. + +Ejemplo: cambiar a `0x61`. En decimal `0x61` es `97`. -Para preparar Raspberry Pi: +```bash +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND /dev/i2c-1 0x62 300 I2C,97 --no-response +``` + +Luego reinicie energia del modulo o reinicie la Raspberry y confirme: ```bash -make -C sensors/EZOCommand -sudo usermod -aG i2c $USER -EZO_MODE=hardware npm start +i2cdetect -y 1 ``` -Es necesario cerrar sesion y volver a entrar despues de agregar el usuario al -grupo `i2c`. +No cambie direcciones sin identificar primero el circuito con `i`. + +## Modo Demo Y Modo Hardware + +```text +EZO_MODE=demo +EZO_MODE=auto +EZO_MODE=hardware +``` + +En produccion use: + +```text +EZO_MODE=hardware +``` -## Fuentes oficiales +## Fuentes Oficiales - https://files.atlas-scientific.com/pH_EZO_Datasheet.pdf - https://files.atlas-scientific.com/DO_EZO_Datasheet.pdf diff --git a/docs/QUICK_START.md b/docs/QUICK_START.md new file mode 100644 index 0000000..5084886 --- /dev/null +++ b/docs/QUICK_START.md @@ -0,0 +1,163 @@ +# Inicio Rapido + +Esta guia es para levantar el proyecto sin entrar todavia en todos los detalles +tecnicos. + +## Que Necesitas + +Para desarrollo sin sensores: + +- Una computadora con Node.js. +- El repositorio clonado. + +Para Raspberry Pi: + +- Raspberry Pi con Raspberry Pi OS. +- I2C habilitado. +- Modulos Atlas Scientific EZO en modo I2C. +- Red local para abrir el dashboard. + +## Probar Sin Sensores + +Instale dependencias: + +```bash +npm ci +``` + +Ejecute pruebas: + +```bash +npm test +``` + +Abra dos terminales. + +Terminal 1: + +```bash +EZO_MODE=demo npm run acquire +``` + +Terminal 2: + +```bash +EZO_MODE=demo npm start +``` + +Abra: + +```text +http://localhost:3000/frontend/index.html +``` + +En Windows PowerShell: + +```powershell +$env:EZO_MODE = "demo" +npm run acquire +``` + +```powershell +$env:EZO_MODE = "demo" +npm start +``` + +## Instalar En Raspberry Pi + +Clone el repositorio: + +```bash +git clone ssh://git@gitea.itmorelia.com:222/Verano-Delfin-2026/bioreactor-multiparametric-daq-shield.git +cd bioreactor-multiparametric-daq-shield +``` + +Ejecute el instalador: + +```bash +chmod +x scripts/install-raspberry-pi.sh +sudo ./scripts/install-raspberry-pi.sh +``` + +Abra el dashboard desde otra computadora: + +```text +http://IP_DE_LA_RASPBERRY/frontend/index.html +``` + +## Verificar Que Esta Corriendo + +```bash +systemctl status photobioreactor-api --no-pager +systemctl status photobioreactor-acquisition --no-pager +systemctl status nginx --no-pager +``` + +Si todo esta bien, los servicios deben aparecer como `active (running)`. + +## Ver Sensores En I2C + +```bash +i2cdetect -y 1 +``` + +Mapa esperado: + +| Direccion | Sensor | +|---:|---| +| `0x61` | EZO-DO | +| `0x63` | EZO-pH | +| `0x64` | EZO-EC | +| `0x66` | EZO-RTD | + +Si falta un sensor, revise cableado, alimentacion y modo I2C. + +## Habilitar Solo Sensores Conectados + +Edite: + +```bash +sudo nano /opt/photobioreactor/config/runtime.json +``` + +Ejemplo con RTD, pH y EC: + +```json +{ + "loggingRateSeconds": 5, + "historyRetentionDays": 30, + "enabledSensors": [ + "temperature", + "ph", + "ec" + ] +} +``` + +Reinicie adquisicion: + +```bash +sudo systemctl restart photobioreactor-acquisition +``` + +## Revisar Datos + +```bash +cat /opt/photobioreactor/data/EZORTD.json +cat /opt/photobioreactor/data/EZOPH.json +cat /opt/photobioreactor/data/EZOEC.json +``` + +```bash +tail /opt/photobioreactor/logs/temperature.csv +tail /opt/photobioreactor/logs/ph.csv +tail /opt/photobioreactor/logs/ec.csv +``` + +## Si Algo Falla + +Lea: + +```text +docs/TROUBLESHOOTING.md +``` diff --git a/docs/RASPBERRY_PI_DEPLOYMENT.md b/docs/RASPBERRY_PI_DEPLOYMENT.md index b8a111a..cf0f3d7 100644 --- a/docs/RASPBERRY_PI_DEPLOYMENT.md +++ b/docs/RASPBERRY_PI_DEPLOYMENT.md @@ -1,116 +1,303 @@ -# Despliegue y validación en Raspberry Pi +# Despliegue En Raspberry Pi -## Prueba sin hardware +Guia para instalar, validar y operar el dashboard en Raspberry Pi. -En una computadora de desarrollo: +## 1. Preparar Raspberry Pi OS + +Actualice el sistema: + +```bash +sudo apt update +sudo apt upgrade -y +``` + +Instale herramientas base: ```bash -npm ci -npm test +sudo apt install -y git build-essential i2c-tools nginx nodejs npm ``` -Para ejecutar el sistema completo en demo, use dos terminales: +Habilite I2C: ```bash -EZO_MODE=demo npm run acquire -EZO_MODE=demo npm start +sudo raspi-config ``` -Abra `http://localhost:3000/frontend/index.html`. El recolector genera JSON y -CSV de prueba; la consola y el panel de calibración muestran transporte DEMO. +Ruta: -## Preparación del bus I2C +```text +Interface Options -> I2C -> Enable +``` -En Raspberry Pi OS: +Reinicie: ```bash -sudo raspi-config sudo reboot +``` + +## 2. Confirmar I2C + +```bash ls -l /dev/i2c-1 -sudo apt install i2c-tools i2cdetect -y 1 ``` -El mapa esperado es: +Mapa esperado: -| Circuito | Dirección | -|---|---| +| Sensor | Direccion | +|---|---:| | EZO-DO | `0x61` | | EZO-pH | `0x63` | | EZO-EC | `0x64` | | EZO-RTD | `0x66` | -No continúe con calibraciones si falta una dirección, aparece una dirección -inesperada o el barrido del bus es inestable. +Si aparece `0x62` y responde `?I,ORP,...`, ese modulo es ORP, no DO. -## Instalación +No calibre sensores hasta confirmar que la comunicacion I2C es estable. -Desde el repositorio clonado: +## 3. Clonar El Repositorio + +```bash +git clone ssh://git@gitea.itmorelia.com:222/Verano-Delfin-2026/bioreactor-multiparametric-daq-shield.git +cd bioreactor-multiparametric-daq-shield +``` + +## 4. Instalar El Proyecto ```bash chmod +x scripts/install-raspberry-pi.sh sudo ./scripts/install-raspberry-pi.sh ``` -El instalador copia la aplicación a `/opt/photobioreactor`, instala -dependencias, compila `EZO_COMMAND` y `EZO_ACQUIRE`, crea el usuario de servicio, -activa los dos servicios systemd y configura Nginx en el puerto 80. +El instalador: + +- Copia el proyecto a `/opt/photobioreactor`. +- Ejecuta instalacion de dependencias. +- Compila `EZO_COMMAND` y `EZO_ACQUIRE`. +- Crea usuario `photobioreactor`. +- Agrega permisos al grupo `i2c`. +- Configura `/etc/default/photobioreactor`. +- Crea servicios `systemd`. +- Configura Nginx. -Validación: +## 5. Verificar Servicios + +```bash +systemctl status photobioreactor-api --no-pager +systemctl status photobioreactor-acquisition --no-pager +systemctl status nginx --no-pager +``` + +Ver modo: ```bash -systemctl status photobioreactor-api -systemctl status photobioreactor-acquisition -journalctl -u photobioreactor-acquisition -f curl http://127.0.0.1:3000/api/system/ezo ``` -La respuesta de producción debe informar `hardware` tanto para comandos como -para adquisición. `EZO_MODE=hardware` evita que una instalación incompleta -caiga silenciosamente a valores simulados. +En produccion debe indicar `hardware`. + +## 6. Abrir Dashboard + +Desde una computadora en la misma red: + +```text +http://IP_DE_LA_RASPBERRY/frontend/index.html +``` + +Para saber la IP: + +```bash +hostname -I +``` + +## 7. Configurar Sensores Habilitados + +Edite: + +```bash +sudo nano /opt/photobioreactor/config/runtime.json +``` + +Tres sensores conectados: + +```json +{ + "loggingRateSeconds": 5, + "historyRetentionDays": 30, + "enabledSensors": [ + "temperature", + "ph", + "ec" + ] +} +``` + +Cuatro sensores: + +```json +{ + "loggingRateSeconds": 5, + "historyRetentionDays": 30, + "enabledSensors": [ + "temperature", + "ph", + "do", + "ec" + ] +} +``` + +Reinicie adquisicion: + +```bash +sudo systemctl restart photobioreactor-acquisition +``` + +## 8. Validar Sensores Individualmente + +Antes de ejecutar comandos manuales, detenga el recolector: + +```bash +sudo systemctl stop photobioreactor-acquisition +sudo rm -f /tmp/photobioreactor-i2c.lock +``` + +Identificar pH: + +```bash +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND /dev/i2c-1 0x63 300 i +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND /dev/i2c-1 0x63 300 Status +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND /dev/i2c-1 0x63 1000 R +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND /dev/i2c-1 0x63 300 Cal,? +``` -La API escucha únicamente en `127.0.0.1` y se publica mediante Nginx. El -dashboard todavía no implementa autenticación; despliegue esta versión solo en -una red local confiable y no exponga el puerto 80 directamente a Internet. +Cambie la direccion segun el sensor: -## Validación previa a calibración +| Sensor | Direccion | +|---|---:| +| DO | `0x61` | +| pH | `0x63` | +| EC | `0x64` | +| RTD | `0x66` | -Desde la consola web, pruebe individualmente: +Reinicie adquisicion despues: + +```bash +sudo systemctl start photobioreactor-acquisition +``` + +## 9. Revisar Datos + +```bash +cat /opt/photobioreactor/data/EZORTD.json +cat /opt/photobioreactor/data/EZOPH.json +cat /opt/photobioreactor/data/EZODO.json +cat /opt/photobioreactor/data/EZOEC.json +``` + +```bash +tail /opt/photobioreactor/logs/temperature.csv +tail /opt/photobioreactor/logs/ph.csv +tail /opt/photobioreactor/logs/do.csv +tail /opt/photobioreactor/logs/ec.csv +``` + +## 10. Prueba De Estabilidad + +Arranque limpio: + +```bash +sudo systemctl stop photobioreactor-acquisition +sudo rm -f /tmp/photobioreactor-i2c.lock +sudo systemctl start photobioreactor-acquisition +``` + +Revise logs: + +```bash +journalctl -u photobioreactor-acquisition --since "10 minutes ago" -l --no-pager +``` + +Monitoreo en vivo: + +```bash +journalctl -u photobioreactor-acquisition -f +``` + +Salir: ```text -i -Status -R -Cal,? +Ctrl + C ``` -Compruebe que cada lectura coincide con el medio físico y que los archivos de -`data/` cambian. El helper agrupado envía `R` a los cuatro circuitos, espera una -sola ventana de conversión y recoge las respuestas bajo el mismo bloqueo usado -por la consola. +Recomendacion de tiempo: + +| Duracion | Uso | +|---|---| +| 15 minutos | Prueba rapida | +| 1 hora | Prueba inicial seria | +| 4 horas | Estabilidad de bus y alimentacion | +| 8 a 12 horas | Prueba fuerte de laboratorio | +| 24 horas | Validacion previa a operacion continua | + +## 11. Calibracion -## Calibración +Use soluciones de referencia vigentes y espere estabilizacion fisica de cada +sonda. -Realice cada procedimiento con soluciones de referencia vigentes y espere la -estabilización de la sonda. El panel consulta `Cal,?` automáticamente después -de cada comando de calibración exitoso. +Resumen: - RTD: `Cal,`. -- pH: `Cal,mid,7.00`, `Cal,low,4.00`, `Cal,high,10.00`. -- DO de dos puntos: `Cal,0` y después `Cal`; configure antes las compensaciones. -- EC: configure `K`, ejecute `Cal,dry` y después uno o dos puntos húmedos. +- pH: `Cal,mid,7.00`, luego `Cal,low,4.00`, luego `Cal,high,10.00`. +- DO: `Cal,0` y luego `Cal`. +- EC: `K,`, `Cal,dry`, luego puntos humedos. -Consulte `docs/EZO_COMMANDS.md` para restricciones y comandos de diagnóstico. +Detalle completo: -## Prueba integral +```text +docs/EZO_COMMANDS.md +``` + +## 12. Seguridad Minima + +Edite: + +```bash +sudo nano /etc/default/photobioreactor +``` + +Configure: + +```text +API_AUTH_TOKEN=un_token_largo_y_privado +``` + +Reinicie API: + +```bash +sudo systemctl restart photobioreactor-api +``` + +No exponga el dashboard directamente a Internet. + +## 13. Apagado Seguro + +Para detener adquisicion: + +```bash +sudo systemctl stop photobioreactor-acquisition +``` -1. Confirme lecturas, históricos, exportaciones y alarmas. -2. Desconecte un sensor: debe aparecer `DESCONECTADO` mientras los demás siguen. -3. Detenga el recolector: las lecturas deben pasar a `DESCONECTADO` al superar - la tolerancia calculada desde la frecuencia configurada. -4. Reinicie la Raspberry y confirme el arranque automático. -5. Mantenga el sistema varias horas y revise `journalctl`, tamaño de CSV, - estabilidad de valores y recuperación después de comandos de consola. +Para apagar Raspberry: -Las pruebas físicas y la exactitud metrológica no pueden certificarse fuera de -la Raspberry Pi con las sondas y soluciones reales conectadas. +```bash +sudo shutdown now +``` + +## 14. Diagnostico + +Si algo falla, consulte: + +```text +docs/TROUBLESHOOTING.md +``` diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..e4e7759 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,48 @@ +# Documentacion + +Indice rapido de documentos del proyecto. + +## Para Empezar + +| Documento | Para que sirve | +|---|---| +| [Inicio rapido](QUICK_START.md) | Levantar el proyecto sin entrar en detalle tecnico | +| [Despliegue en Raspberry Pi](RASPBERRY_PI_DEPLOYMENT.md) | Instalar, activar servicios y validar hardware | +| [Diagnostico](TROUBLESHOOTING.md) | Resolver fallas comunes de I2C, servicios y sensores | + +## Operacion + +| Documento | Para que sirve | +|---|---| +| [Comandos EZO](EZO_COMMANDS.md) | Identificacion, lectura, diagnostico y calibracion | +| [Telegram](TELEGRAM_BOT_SETUP.md) | Crear bot, obtener chatId y activar alertas | +| [Almacenamiento](STORAGE_ESTIMATE.md) | Calcular uso de microSD y crecimiento de historicos | + +## Referencia Tecnica + +| Documento | Para que sirve | +|---|---| +| [Arquitectura](../ARCHITECTURE.md) | Capas, flujo de datos, servicios y archivos | +| [Estado del proyecto](../PROJECT_STATUS.md) | Funciones implementadas y trabajo pendiente | +| [README principal](../README.md) | Entrada general al proyecto | + +## Ruta Recomendada De Lectura + +Para alguien nuevo: + +```text +README.md +docs/QUICK_START.md +docs/RASPBERRY_PI_DEPLOYMENT.md +docs/TROUBLESHOOTING.md +``` + +Para alguien tecnico: + +```text +ARCHITECTURE.md +PROJECT_STATUS.md +docs/EZO_COMMANDS.md +docs/STORAGE_ESTIMATE.md +docs/TELEGRAM_BOT_SETUP.md +``` diff --git a/docs/STORAGE_ESTIMATE.md b/docs/STORAGE_ESTIMATE.md new file mode 100644 index 0000000..f1cdc6b --- /dev/null +++ b/docs/STORAGE_ESTIMATE.md @@ -0,0 +1,180 @@ +# Calculo De Almacenamiento + +Este documento estima cuanto espacio ocupan los datos guardados por el sistema. + +## Que Archivos Crecen + +Crecen principalmente: + +```text +logs/temperature.csv +logs/ph.csv +logs/do.csv +logs/ec.csv +logs/alarms.csv +``` + +No crecen de forma acumulativa: + +```text +data/EZORTD.json +data/EZOPH.json +data/EZODO.json +data/EZOEC.json +``` + +Los JSON se sobrescriben en cada ciclo. + +## Formato De Una Lectura + +Cada fila CSV usa: + +```csv +timestamp,value +2026-07-07T17:26:13.459Z,25.132 +``` + +Tamano aproximado por fila: + +```text +24 bytes timestamp ISO +1 byte coma +6 a 10 bytes valor +1 byte salto de linea +``` + +Rango practico: + +```text +32 a 36 bytes por lectura +``` + +Para calculos conservadores se usa: + +```text +36 bytes por lectura +``` + +## Peor Caso Operativo + +Supuestos: + +```text +4 sensores +1 lectura por segundo +30 dias +36 bytes por fila +``` + +Lecturas por sensor al mes: + +```text +30 * 24 * 60 * 60 = 2,592,000 lecturas +``` + +Espacio por sensor: + +```text +2,592,000 * 36 = 93,312,000 bytes +``` + +Resultado: + +```text +93.31 MB por sensor por mes +88.99 MiB por sensor por mes +``` + +Cuatro sensores: + +```text +93.31 MB * 4 = 373.25 MB por mes +``` + +Resultado practico: + +```text +350 a 375 MB por mes +``` + +## Tabla Por Sensor + +Con 1 lectura por segundo: + +| Periodo | Por sensor | +|---|---:| +| 1 dia | ~3.11 MB | +| 30 dias | ~93.31 MB | +| 1 ano | ~1.14 GB | + +## Tabla Del Sistema Completo + +Con 4 sensores: + +| Frecuencia | Datos por mes | +|---|---:| +| 1 segundo | ~350 a 375 MB | +| 5 segundos | ~70 MB | +| 10 segundos | ~35 MB | +| 60 segundos | ~6 MB | + +Con 3 sensores: + +| Frecuencia | Datos por mes | +|---|---:| +| 1 segundo | ~264 a 280 MB | +| 5 segundos | ~50 a 53 MB | +| 10 segundos | ~25 a 27 MB | +| 60 segundos | ~4 a 5 MB | + +## Tiempo Estimado Por MicroSD + +Estimacion teorica solo para datos, sin borrar historicos: + +| MicroSD | Tiempo aproximado con 4 sensores a 1 Hz | +|---|---:| +| 16 GB | ~3.5 anos | +| 32 GB | ~7 anos | +| 64 GB | ~14 anos | +| 128 GB | ~28 anos | + +Estimacion conservadora, reservando espacio para Raspberry Pi OS, paquetes, +logs del sistema y margen libre: + +| MicroSD | Espacio comodo para datos | Tiempo comodo | +|---|---:|---:| +| 16 GB | ~6 GB | ~16 meses | +| 32 GB | ~18 GB | ~4 anos | +| 64 GB | ~43 GB | ~9.5 anos | +| 128 GB | ~94 GB | ~21 anos | + +## Retencion Historica + +El sistema puede podar historicos con: + +```json +{ + "historyRetentionDays": 30 +} +``` + +Con 30 dias de retencion, el uso de CSV no crece indefinidamente. En el peor +caso de 4 sensores a 1 Hz se estabiliza alrededor de: + +```text +350 a 375 MB +``` + +## Excel No Cuenta Como Almacenamiento Continuo + +Los reportes Excel pueden pesar mucho porque `.xlsx` almacena celdas, hojas y +metadatos. Un dia con 4 sensores a 1 Hz puede tener: + +```text +345,600 filas +mas de 1,000,000 de celdas si hay 3 columnas +``` + +Por eso un Excel diario puede pesar decenas de MB. Ese peso solo cuenta si se +descarga o guarda el reporte; no es parte del almacenamiento continuo del +sistema. diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md new file mode 100644 index 0000000..c1b2ec7 --- /dev/null +++ b/docs/TROUBLESHOOTING.md @@ -0,0 +1,248 @@ +# Diagnostico De Problemas + +Guia practica para resolver fallas comunes en Raspberry Pi, sensores EZO y +dashboard. + +## Ver Estado General + +```bash +systemctl status photobioreactor-api --no-pager +systemctl status photobioreactor-acquisition --no-pager +systemctl status nginx --no-pager +``` + +Logs recientes: + +```bash +journalctl -u photobioreactor-api --since "10 minutes ago" -l --no-pager +journalctl -u photobioreactor-acquisition --since "10 minutes ago" -l --no-pager +``` + +## El Dashboard No Abre + +1. Confirme IP de la Raspberry: + +```bash +hostname -I +``` + +2. Confirme Nginx: + +```bash +systemctl status nginx --no-pager +``` + +3. Pruebe localmente: + +```bash +curl http://127.0.0.1/frontend/index.html +curl http://127.0.0.1/api/system/ezo +``` + +4. Desde otra computadora abra: + +```text +http://IP_DE_LA_RASPBERRY/frontend/index.html +``` + +## No Aparece Un Sensor En `i2cdetect` + +Detenga adquisicion: + +```bash +sudo systemctl stop photobioreactor-acquisition +sudo rm -f /tmp/photobioreactor-i2c.lock +``` + +Revise bus: + +```bash +i2cdetect -y 1 +``` + +Direcciones esperadas: + +| Sensor | Direccion | +|---|---:| +| DO | `0x61` | +| pH | `0x63` | +| EC | `0x64` | +| RTD | `0x66` | + +Si no aparece: + +- Confirme alimentacion. +- Confirme GND comun si no hay aislamiento galvanico. +- Confirme SDA y SCL. +- Confirme que el circuito EZO esta en modo I2C. +- Revise que no haya una direccion cambiada. + +## Identificar Que Sensor Hay En Una Direccion + +```bash +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND /dev/i2c-1 0x63 300 i +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND /dev/i2c-1 0x63 300 Status +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND /dev/i2c-1 0x63 1000 R +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND /dev/i2c-1 0x63 300 Cal,? +``` + +Cambie `0x63` por la direccion que quiera probar. + +Ejemplos de identificacion: + +```text +?I,pH,2.17 +?I,EC,2.14 +?I,RTD,2.12 +?I,DO,2.XX +?I,ORP,2.14 +``` + +Si aparece `?I,ORP,...`, ese modulo no es DO. + +## Error: No Se Pudo Bloquear El Bus I2C + +Significa que el helper no pudo tomar: + +```text +/tmp/photobioreactor-i2c.lock +``` + +Solucion rapida: + +```bash +sudo systemctl stop photobioreactor-acquisition +sudo rm -f /tmp/photobioreactor-i2c.lock +sudo systemctl start photobioreactor-acquisition +``` + +Si sigue fallando: + +```bash +ls -ld /tmp +id photobioreactor +ls -l /dev/i2c-1 +groups photobioreactor +ps -eo pid,user,stat,cmd | grep -E "EZO_ACQUIRE|EZO_COMMAND|acquisition.js" | grep -v grep +``` + +Prueba directa como usuario de servicio: + +```bash +sudo -u photobioreactor /opt/photobioreactor/sensors/EZOCommand/EZO_ACQUIRE /dev/i2c-1 temperature ph ec +``` + +Si esta prueba responde JSON, el bus y permisos estan bien. + +## Error: EZO_COMMAND No Existe + +Si esta en `~` o en otra carpeta, esta ruta puede fallar: + +```bash +./sensors/EZOCommand/EZO_COMMAND +``` + +Use la ruta instalada: + +```bash +/opt/photobioreactor/sensors/EZOCommand/EZO_COMMAND +``` + +O compile desde el repositorio: + +```bash +make -C sensors/EZOCommand +``` + +## El Servicio Dice 1/1, 2/2 O 3/3 Sensores + +Eso significa que solo estan habilitados esos sensores en: + +```text +/opt/photobioreactor/config/runtime.json +``` + +Ejemplo con tres sensores: + +```json +{ + "loggingRateSeconds": 5, + "historyRetentionDays": 30, + "enabledSensors": [ + "temperature", + "ph", + "ec" + ] +} +``` + +Despues de editar: + +```bash +sudo systemctl restart photobioreactor-acquisition +``` + +## SSH Se Vuelve Inestable + +Posibles causas: + +- Alimentacion insuficiente. +- Bus I2C bloqueado. +- Sensor mal cableado. +- Frecuencia de adquisicion muy agresiva durante pruebas. +- Raspberry reiniciandose. + +Revise: + +```bash +dmesg | tail -n 80 +journalctl -u photobioreactor-acquisition --since "30 minutes ago" -p warning --no-pager +vcgencmd get_throttled +``` + +Si `vcgencmd get_throttled` no devuelve `throttled=0x0`, hay indicios de +problemas de alimentacion o temperatura. + +## Excel Pesa Mucho + +Las graficas muestran solo el dia actual, pero Excel exporta el historico +disponible en CSV. + +Con 4 sensores a 1 lectura por segundo: + +```text +86,400 filas por sensor por dia +345,600 filas totales por dia +1,036,800 celdas en Excel si son 3 columnas +``` + +Por eso un Excel diario puede pesar decenas de MB. El CSV es mas eficiente. + +## Prueba De Estabilidad + +Para dejarlo corriendo: + +```bash +sudo systemctl stop photobioreactor-acquisition +sudo rm -f /tmp/photobioreactor-i2c.lock +sudo systemctl start photobioreactor-acquisition +``` + +Revisar errores: + +```bash +journalctl -u photobioreactor-acquisition --since "1 hour ago" -p warning --no-pager +journalctl -u photobioreactor-api --since "1 hour ago" -p warning --no-pager +``` + +Revisar crecimiento de CSV: + +```bash +wc -l /opt/photobioreactor/logs/temperature.csv +wc -l /opt/photobioreactor/logs/ph.csv +wc -l /opt/photobioreactor/logs/ec.csv +wc -l /opt/photobioreactor/logs/do.csv +``` + +Con `loggingRateSeconds` en `5`, cada sensor debe sumar aproximadamente 720 +filas por hora.