Plataforma Distribuida ESP32 + SHT41 + Servidor Linux
Documentación Técnica Completa
Versión 2.0 - Febrero 2026
- Resumen Ejecutivo
- Arquitectura del Sistema
- Componentes del Sistema
- Scripts del Servidor
- Instalación y Configuración
- Operación y Mantenimiento
- API REST del ESP32
- Sistema de Alertas
- Seguridad y Mejores Prácticas
- Resolución de Problemas
Sistema robusto y escalable diseñado para monitorizar temperatura y humedad en tiempo real, con capacidades empresariales de histórico, alertas inteligentes y observabilidad completa. Arquitectura probada lista para entornos productivos.
- 📡 Recolección de datos vía HTTP REST
- 🗄️ Almacenamiento histórico eficiente en RRDTool
- 📊 Generación automática de gráficos (24h, 7d, 30d)
- 🌐 Dashboard web responsive con auto-actualización
- 🚨 Sistema de alertas por email ante anomalías
- 🔍 Descubrimiento automático de sensores en red
- ♻️ Recuperación autónoma ante fallos
- 🔐 Seguridad y autenticación opcional
- 🏠 Hogar inteligente y automatización domótica
- 🌱 Agricultura de precisión e invernaderos
- 🏭 Monitorización industrial
- 🖥️ Data centers y salas de servidores
- 🏥 Instalaciones médicas y laboratorios
- 📦 Almacenes y logística
El sistema implementa una arquitectura distribuida de tres capas con separación clara de responsabilidades:
ESP32 + SHT41 ──HTTP/JSON──► Servidor Linux ──► Dashboard Web
(Sensores) (RRD + Scripts) (Gráficos)
| Componente | Función Principal | Tecnología |
|---|---|---|
| ESP32 + SHT41 | Lectura de datos ambientales, API REST, buffer de logs | MicroPython + asyncio |
| Servidor Linux | Recolección, almacenamiento histórico, alertas, generación de gráficos | Python 3 + Bash |
| RRDTool | Base de datos de series temporales con consolidación automática | Round Robin Database |
| Nginx/Apache | Publicación del dashboard web y archivos estáticos | Servidor HTTP |
| Sistema de Alertas | Detección de anomalías y notificaciones por email | Python + SMTP |
- Lectura: Los sensores ESP32 leen temperatura y humedad cada 5 segundos del SHT41
- Exposición: Los datos se exponen vía API REST en formato JSON
- Consulta: El servidor Linux consulta cada sensor cada 5 minutos (configurable)
- Almacenamiento: Los datos se almacenan en bases de datos RRD individuales por sensor
- Visualización: Se generan gráficos cada 10 minutos para diferentes períodos
- Dashboard: El dashboard web se actualiza automáticamente mostrando datos actuales
- Monitorización: El sistema de alertas evalúa umbrales y tendencias continuamente
Sistema asíncrono basado en MicroPython con arquitectura modular y gestión eficiente de memoria.
| Archivo | Función |
|---|---|
| boot.py | Inicialización del sistema y conectividad WiFi |
| main.py | Orquestación de tareas asíncronas (sensor, HTTP, mantenimiento) y sistema de logs |
| sht41.py | Driver optimizado para sensor SHT41 con reinicialización automática |
| wifi_service.py | Gestión de conectividad con reconexión automática y supervisión NTP |
| secrets.py | Credenciales y configuración local (no incluir en git, ver secrets.py.example) |
| Tarea | Función | Intervalo |
|---|---|---|
| Sensor Task | Lectura periódica del SHT41 vía I2C | 5 segundos |
| HTTP Task | Servidor REST no bloqueante en puerto 80 | Continuo |
| Maintenance Task | Garbage collection y watchdog | 5 segundos (GC cada 30s) |
| WiFi Monitor | Verificación y reconexión de red | 10 segundos |
- GPIO: 21 (SDA) / 22 (SCL)
- Frecuencia: 100 kHz
- Dirección I2C: 0x44 (por defecto)
- Buffer optimizado: bytearray(6) reutilizable
Watchdog hardware configurable mediante la constante WDT_LEVEL en main.py. Solo está activo un nivel a la vez:
| WDT_LEVEL | Timeout | Uso recomendado |
|---|---|---|
| 0 | Desactivado | Desarrollo y depuración |
| 1 | 30 segundos | Producción estándar (valor por defecto) |
| 2 | 15 segundos | Entornos que requieren detección rápida de bloqueos |
| 3 | 8 segundos | Máxima vigilancia (requiere feeds más frecuentes) |
El watchdog se alimenta en el loop de lectura del sensor y en el loop de mantenimiento, garantizando un feed mínimo cada 5 segundos con el nivel por defecto.
Archivo de configuración centralizado que define todos los parámetros del sistema.
| Parámetro | Descripción | Valor por Defecto |
|---|---|---|
| RRD_PATH | Ruta de bases de datos RRD | /var/lib/sensores_rrd |
| SENSOR_FILE | Archivo de mapeo sensores | sensores.json |
| TEMP_MAX | Temperatura máxima (°C) | 35 |
| TEMP_MIN | Temperatura mínima (°C) | 5 |
| HUM_MAX | Humedad máxima (%) | 80 |
| TEMP_TREND_THRESHOLD | Umbral cambio brusco (°C) | 5 |
| ALERT_EMAIL | Email de alertas | tu_correo@gmail.com |
| BASE_NET | Red base para descubrimiento | 192.168.1. |
| DISCOVERY_WORKERS | Hilos paralelos descubrimiento | 20 |
| ALERT_THROTTLE_TIME | Intervalo entre alertas (s) | 3600 |
Script inteligente que escanea la red local en busca de dispositivos con la API del sensor. Utiliza ThreadPoolExecutor para escaneo paralelo de hasta 255 direcciones IP.
- Escaneo Paralelo: Utiliza 20 hilos de trabajo simultáneos
- Detección: Consulta /api/health en cada IP
- Validación: Verifica respuesta JSON con status: ok
- Nomenclatura: Asigna nombres únicos (s1, s2, s3...)
- Creación RRD: Genera automáticamente la base de datos
- Backup: Crea copias de seguridad antes de modificar
| Parámetro | Valor | Descripción |
|---|---|---|
| Step | 300 segundos | Intervalo base de muestreo (5 minutos) |
| DS:temp | GAUGE:600:-40:80 | Temperatura (-40°C a 80°C) |
| DS:hum | GAUGE:600:0:100 | Humedad (0% a 100%) |
| RRA 1 día | AVERAGE:0.5:1:288 | Promedios cada 5 min (288 muestras) |
| RRA 1 semana | AVERAGE:0.5:12:168 | Promedios cada 1 hora (168 muestras) |
| RRA 1 año | AVERAGE:0.5:288:365 | Promedios diarios (365 muestras) |
Script principal de recolección que consulta cada sensor, actualiza las bases de datos RRD y ejecuta el sistema de alertas.
- Carga de Configuración: Lee sensores.json con recuperación desde backup
- Consulta HTTP: GET a /api/sensor con timeout de 5 segundos
- Validación: Verifica campos temperature y humidity válidos
- Actualización RRD: Inserta datos con rrdtool update
- Verificación de Anomalías: Compara contra umbrales configurados
- Análisis de Tendencias: Detecta cambios bruscos
- Gestión de Alertas: Envía notificaciones con throttling
| Tipo de Alerta | Condición | Directorio de Estado |
|---|---|---|
| Anomalía | Valor fuera de rango | /tmp/sensor_anomaly_alerts |
| Tendencia | Cambio brusco > 5°C | /tmp/sensor_trend_alerts |
| Sensor Caído | Timeout o error HTTP | /tmp/sensor_down_alerts |
Script Bash que genera gráficos PNG para cada sensor utilizando RRDTool.
| Archivo | Período | Resolución |
|---|---|---|
| s1_1d.png | 24 horas | 5 minutos |
| s1_7d.png | 7 días | 1 hora |
| s1_30d.png | 30 días | 1 hora consolidada |
- Dimensiones: 800x300 píxeles
- Colores diferenciados por período
- Doble eje Y: Temperatura (°C) y Humedad (%)
- Auto-escalado de ejes
- Estadísticas: Actual, Promedio, Mínimo, Máximo
Herramienta de diagnóstico avanzada para monitorizar el uso de memoria del ESP32 en tiempo real.
| Métrica | Descripción | Umbral |
|---|---|---|
| heap_free | Memoria libre disponible | < 20 KB Warning |
| heap_alloc | Memoria asignada | Tendencia |
| gc_freed_bytes | Bytes liberados por GC | > 5 KB presión alta |
| leak_rate | Tasa de pérdida | > 1024 B/min sospechoso |
Script de diagnóstico completo que verifica todos los componentes del sistema.
# 1. Descargar el repositorio git clone https://github.com/usuario/sensor-monitoring.git cd sensor-monitoring # 2. Ejecutar instalador como root sudo bash install_server.sh
sudo cp /usr/local/bin/config_server.py.example /usr/local/bin/config_server.py sudo nano /usr/local/bin/config_server.py
Para Gmail, generar contraseña de aplicación en Google Account > Security
ALERT_EMAIL = "tu_correo@gmail.com" SMTP_USER = "tu_correo@gmail.com" SMTP_PASS = "abcd efgh ijkl mnop" # Contraseña de aplicación
sudo /usr/local/bin/discover_sensores.py
sudo /usr/local/bin/verify_installation.py
Abrir navegador: http://IP_DEL_SERVIDOR/index.html
| Tarea | Frecuencia | Log |
|---|---|---|
| Actualización | */5 * * * * | /var/log/sensores/update.log |
| Gráficos | */10 * * * * | /var/log/sensores/graficas.log |
| Descubrimiento | 0 */6 * * * | /var/log/sensores/discover.log |
Método Automático (Recomendado):
sudo /usr/local/bin/discover_sensores.py
# Respaldar configuración tar -czf backup_sensores_$(date +%Y%m%d).tar.gz \ /var/lib/sensores_rrd/sensores.json \ /usr/local/bin/config_server.py # Respaldar histórico tar -czf backup_rrd_$(date +%Y%m%d).tar.gz \ /var/lib/sensores_rrd/*.rrd
| Endpoint | Método | Descripción |
|---|---|---|
| /api/sensor | GET | Última lectura de temp/hum |
| /api/health | GET | Estado general del sistema |
| /api/mem | GET | Estadísticas de memoria |
| /api/logs | GET | Últimas líneas del log |
| /log.txt | GET | Archivo completo de log |
Obtener Lectura:
curl http://192.168.1.50/api/sensor # Respuesta: { "temperature": 23.5, "humidity": 55.2, "timestamp": 1738819200 }
Verificar Estado:
curl http://192.168.1.50/api/health # Respuesta: { "status": "ok", "wifi_connected": true, "ip": "192.168.1.50", "uptime_sec": 86400, "last_sensor_ok": 1738819200, "sensor_error_count": 0 }
Estadísticas de Memoria:
curl http://192.168.1.50/api/mem # Respuesta: { "heap_free": 48200, "heap_alloc": 21300, "gc_freed_bytes": 3400, "heap_total": 69500 }
| Tipo | Condición | Ejemplo |
|---|---|---|
| Temp Alta | temp > 35°C | 🌡️ Temperatura: 37.2°C |
| Temp Baja | temp < 5°C | ❄️ Temperatura: 3.1°C |
| Humedad Alta | hum > 80% | 💧 Humedad: 85.5% |
| Cambio Brusco | Δtemp > 5°C | 📈 Cambio: 23°C → 29°C |
| Sensor Caído | Timeout |
Para evitar spam, período mínimo de 1 hora entre alertas similares.
| Medida | Implementación |
|---|---|
| VLAN IoT | Segmentar sensores en red dedicada |
| Firewall | Restringir acceso a puertos 80/443 |
| IP Estática | Configurar DHCP reservation |
| HTTPS/TLS | Certificado SSL en Nginx |
El archivo secrets.py contiene credenciales WiFi y HTTP y nunca debe incluirse en el repositorio. El fichero .gitignore lo excluye automáticamente. Para configurar un nuevo dispositivo, copiar secrets.py.example a secrets.py y rellenar los valores reales:
cp secrets.py.example secrets.py
# Editar secrets.py con credenciales reales- ✓ IP estática configurada en sensores
- ✓ NTP sincronizado
- ✓ /api/mem monitorizado
- ✓ Alertas activas y probadas
- ✓ Acceso HTTP restringido
- ✓ Sensores en VLAN IoT
- ✓ Backups automáticos
- ✓ secrets.py en .gitignore
- ✓ Documentación actualizada
Síntomas: discover_sensores.py no encuentra el sensor
Soluciones:
- Verificar conexión WiFi del ESP32
- Confirmar misma red (BASE_NET)
- Probar:
ping 192.168.1.50 - Verificar API:
curl http://192.168.1.50/api/health
Síntomas: Dashboard muestra error en imágenes
Soluciones:
- Verificar archivos .rrd:
ls -la /var/lib/sensores_rrd/ - Ejecutar:
sudo /usr/local/bin/graficas_sensores.sh - Revisar log:
/var/log/sensores/graficas.log - Verificar permisos de /var/www/html/graficas
# Verificar estado completo sudo /usr/local/bin/verify_installation.py # Ver logs en tiempo real tail -f /var/log/sensores/update.log # Verificar cron crontab -l # Probar sensor curl -v http://192.168.1.50/api/health
| Componente | Especificación |
|---|---|
| Microcontrolador | ESP32 Xtensa dual-core 32-bit |
| Frecuencia | 160/240 MHz |
| RAM | 520 KB SRAM |
| Flash | 4 MB |
| WiFi | 802.11 b/g/n, 2.4 GHz |
| Consumo | ~80 mA activo |
| Especificación | Valor |
|---|---|
| Rango Temperatura | -40°C a +125°C |
| Precisión Temperatura | ±0.2°C |
| Rango Humedad | 0% a 100% RH |
| Precisión Humedad | ±1.8% RH |
| Interfaz | I2C (hasta 1 MHz) |
/
├── /usr/local/bin/
│ ├── config_server.py
│ ├── discover_sensores.py
│ ├── update_sensores.py
│ ├── graficas_sensores.sh
│ ├── monitor_memory.py
│ └── verify_installation.py
│
├── /var/lib/sensores_rrd/
│ ├── sensores.json
│ └── *.rrd
│
├── /var/www/html/
│ ├── index.html
│ └── graficas/*.png
│
└── /var/log/sensores/
├── update.log
├── graficas.log
└── discover.log
| Término | Definición |
|---|---|
| RRD | Round Robin Database - BD de series temporales |
| GAUGE | Tipo de dato RRD para valores absolutos |
| Throttling | Limitación de frecuencia de eventos |
| Watchdog | Temporizador que reinicia ante bloqueos |
| GC | Garbage Collection - Recolección de basura |
| Memory Leak | Fuga de memoria gradual |
| API REST | Interfaz HTTP de programación |
| Asyncio | Framework asíncrono en Python |
El Sistema de Monitorización Ambiental es una solución completa, probada y lista para producción que combina:
- Escalabilidad: Arquitectura distribuida que soporta decenas de sensores
- Confiabilidad: Recuperación automática, watchdogs, backups
- Observabilidad: Logs completos, métricas de memoria, alertas inteligentes
- Facilidad de uso: Instalación automática, dashboard web intuitivo
- Flexibilidad: Configuración centralizada, extensible
Características destacadas:
✓ Arquitectura distribuida escalable
✓ Descubrimiento automático
✓ Almacenamiento histórico eficiente
✓ Sistema de alertas inteligente
✓ Dashboard responsive
✓ Observabilidad completa
✓ Recuperación automática
© 2026 - Sistema de Monitorización Ambiental - Documentación Técnica v2.0