← Blog | Arquitectura 15 Ene 2026 · 20 min lectura

Del Sensor al Auricular: IoT Hub y Audio Hub como Agentes de Escritorio

Dos apps Electron que se registran como agentes en Cadences. IoT Hub conecta sensores, cámaras y actuadores via MQTT, Serial y HTTP. Audio Hub permite que las IAs hablen con personas y las personas con IAs, usando Whisper y un cascade de 5 motores TTS. Y Cadences orquesta el loop completo: un sensor cruza un umbral → un workflow IA decide → un humano recibe la acción por auricular, WhatsApp, llamada, email o cualquier canal.

cadences.app · IoT Hub · Audio Hub

1 El concepto: agentes de escritorio domain-specific

El modelo SaaS tradicional fuerza todo a vivir en el navegador. Pero hay dominios que necesitan acceso al sistema operativo: Bluetooth para auriculares, puertos Serial para Arduino, ffmpeg para cámaras RTSP, Whisper para transcribir audio localmente.

La solución: apps Electron que se registran como agentes en Cadences. Cada app opera de forma autónoma en local — base de datos SQLite, procesamiento sin internet, UI nativa — y se sincroniza con la nube cuando hay conexión. El backend de Cadences actúa como orquestador central: recibe eventos de cualquier agente, ejecuta workflows IA, y despacha acciones al canal correcto.

🔌 El loop completo

🌡️ Sensor IoT cruza umbral (IoT Hub)
MQTT / Serial / HTTP → Cadences API
🤖 Workflow IA decide la acción (Cadences)
Agente IA → selecciona canal de salida
🔊 Auricular · 📲 WhatsApp · 📞 Llamada · 📧 Email · 📡 SMS

El auricular via Audio Hub es solo uno de los canales de salida. Cadences es un Swiss Army knife: el mismo workflow puede despachar la acción por el canal que mejor encaje — un WhatsApp al técnico de guardia, una llamada automática al supervisor, un email al cliente, o un broadcast de voz al equipo en campo.

2 Por qué Electron: lo que el browser no puede hacer

Capacidad Browser Electron
Bluetooth system-level Limitado (Web Bluetooth parcial) Full access
Serial ports (Arduino/ESP32) No No restrictions
child_process (Python, ffmpeg) No spawn / exec
Micrófono sin restricciones Permisos limitados Full, sin popups
SQLite nativo No (solo IndexedDB) better-sqlite3
MQTT nativo (TCP) Solo WebSocket TCP directo + WSS
File system completo Sandboxed Full R/W
System tray / auto-start No Nativo

Patrón compartido: Ambas apps usan el mismo stack base — Electron 33, better-sqlite3 con WAL mode, electron-store para config persistida, contextBridge con IPC whitelisted, y vanilla HTML/CSS/JS en el renderer (sin React). UI con estética iOS 17 dark.

3 IoT Hub: multi-protocolo, multi-dispositivo, multi-todo

IoT Hub es una app Electron que transforma cualquier PC en un gateway IoT completo. Conecta sensores, actuadores y cámaras por tres protocolos — y todo lo que capture se almacena localmente en SQLite y se sincroniza con Cadences cada 5 minutos.

MQTT

Multi-broker simultáneo. QoS 0/1/2. Auto-reconnect. JSON auto-parsing. Suscripciones por topic con binding a dispositivos. mqtt.js v5.

Serial

Conexión directa a Arduino, ESP32 y microcontroladores. Listado de puertos, baudrates (9600–115200), parseo de líneas JSON. Terminal integrado con envío de comandos.

HTTP Polling

GET/POST/PUT/PATCH/DELETE. Polling configurable por intervalo. Headers y auth personalizables. Para APIs REST de dispositivos comerciales.

// Routing protocol-agnostic — el automation engine no sabe qué protocolo usa cada device automationEngine.on('execute-device-command', async ({ deviceId, command, params }) => { const device = db.prepare('SELECT * FROM devices WHERE id = ?').get(deviceId); const config = JSON.parse(device.config); if (device.protocol === 'mqtt') { mqttClient.publish(config.brokerId, topic, JSON.stringify({ command, ...params })); } else if (device.protocol === 'http') { await fetch(url, { method: 'POST', body: JSON.stringify({ command, ...params }) }); } else if (device.protocol === 'serial') { serialManager.send(config.port, JSON.stringify({ command, ...params })); } });

4 40+ tipos de dispositivo en 10 categorías

El registro de dispositivos (deviceTypes.js, 602 líneas) define cada tipo con su icono, protocolos compatibles, capabilities, data points con unidades, comandos y esquemas de configuración:

Categoría Dispositivos Ejemplo de data points
🌡️ Ambiental Temperatura, humedad, calidad de aire, presión, CO2, UV, ruido, luz, lluvia, viento { aqi: AQI, pm25: µg/m³, co2: ppm }
🔒 Seguridad Movimiento (PIR), puerta/ventana, rotura de cristal, humo, gas, agua, vibración, botón de pánico { motion: bool, zone: string }
⚡ Energía Medidor de potencia, voltaje, corriente, batería, solar, enchufe inteligente { power: W, voltage: V, kwh: kWh }
💡 Iluminación Bombilla smart, tira LED, switch, dimmer { brightness: %, color: hex }
❄️ Clima Termostato, AC, calefacción, ventilador, HVAC { target_temp: °C, mode: string }
📷 Cámaras IP (ONVIF), USB, ESP32-CAM, doorbell, PTZ, térmica Snapshot, video H.264, MJPEG stream
⚙️ Actuadores Relé, servo, stepper, motor DC, válvula, cerradura smart, persianas, garaje, riego { state: on/off, position: % }
📡 Gateways Zigbee, Z-Wave, LoRa, BLE { connected_devices: int }
💙 Salud Ritmo cardíaco, presión arterial, báscula, sleep tracker { bpm: int, spo2: % }
🏭 Industrial PLC, SCADA, Modbus, nivel de tanque, caudalímetro, cinta transportadora { level: %, flow: L/min }

15 protocolos soportados: MQTT, HTTP/HTTPS, Serial, WebSocket, CoAP, Modbus TCP/RTU, Zigbee, Z-Wave, LoRa, Bluetooth/BLE, RTSP, ONVIF.

5 Motor de automatización: triggers → condiciones → acciones

El automationEngine.js (796 líneas) es un motor de reglas event-driven con template variables. Cada automatización define: cuándo disparar, si las condiciones se cumplen, y qué hacer.

Triggers

  • device_state — propiedad del device cambia
  • threshold — sensor cruza un umbral
  • schedule"every 5 minutes" / "at 08:00"
  • webhook — invocación externa
  • sunrise / sunset — solares
  • scene — al activar una escena

Condiciones

  • Operadores: =, !=, >, <, contains, starts_with, changed_to
  • time_range — solo entre horas X e Y
  • day_of_week — solo ciertos días
  • cooldown — mínimo entre disparos
  • Lógica AND entre todas las condiciones

Acciones

  • device_command — enviar al device
  • camera_capture/record
  • mqtt_publish — publicar a un topic
  • http_request — llamada HTTP
  • notification — alerta in-app
  • activate_scene
  • cadences_workflow — ejecutar workflow remoto
  • delay — esperar entre acciones
// Template variables — las acciones se resuelven dinámicamente resolveTemplates(input, context) { return input.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (match, path) => { const parts = path.split('.'); let value = context; for (const part of parts) { value = value?.[part]; } return value !== undefined ? value : match; }); } // Ejemplo: "Zona {{device.location}} a {{value}}°C" → "Zona Nave 3 a 47°C"

Scene Manager: presets multi-dispositivo

🌅 Good Morning Luces graduales + clima
🌙 Good Night Todo off + alarma
💪 Away Mode Cámaras + seguridad
🎦 Movie Time Luces 10% + persianas
🚨 Alert Doble captura cámara

6 Sistema de cámaras: ffmpeg como backend universal

El camera.js (619 líneas) unifica todos los tipos de cámara bajo un solo backend: ffmpeg. En lugar de integrar un SDK por cada fabricante, todo pasa por ffmpeg — que ya sabe hablar RTSP, DirectShow, V4L2 y HTTP/MJPEG.

📹 IP Camera RTSP/ONVIF
📸 USB Webcam DirectShow / V4L2
📡 ESP32-CAM HTTP / MJPEG
🔔 Doorbell Cam RTSP + audio bidireccional
// Captura RTSP — ffmpeg como subproceso con timeout de 30s captureFromRtsp(camera, outputPath) { const args = [ '-rtsp_transport', 'tcp', '-i', url, '-frames:v', '1', // Solo 1 frame '-q:v', '2', // Calidad alta '-y', outputPath ]; const ffmpeg = spawn(this.ffmpegPath, args); } // Grabación de video — H.264 ultrafast para bajo consumo de CPU const args = [ '-c:v', 'libx264', '-preset', 'ultrafast', '-crf', '23' ];

7 Audio Hub: la IA que habla con personas (y viceversa)

Audio Hub convierte un conjunto de auriculares Bluetooth en un sistema de comunicación bidireccional IA↔humano. Un coordinador — o un workflow automático de Cadences — genera voz TTS y la transmite a los auriculares del equipo en campo. Cuando un operador habla, Whisper transcribe el audio localmente y el texto resultante alimenta al contexto del sistema.

La clave: es un canal de interacción humano↔IA powered by contexto. Detrás del mensaje de voz hay un workflow completo — datos del proyecto, estado de los dispositivos IoT, historial de la conversación, condiciones de los sensores — todo el contexto que el agente necesita para generar la respuesta correcta.

TTS cascade: 5 motores con fallback automático

1. gTTS (Google TTS — gratis, alta calidad, requiere internet)

2. edge-tts (Microsoft Neural Voices — gratis, alta calidad, requiere internet)

3. pyttsx3 (100% offline, menor calidad, fallback último recurso)

4. ElevenLabs (12 voces mapeadas, modelo eleven_multilingual_v2)

5. OpenAI TTS (6 voces: alloy, echo, fable, onyx, nova, shimmer)

🎙️ STT: Whisper local

5 tamaños de modelo (tiny 39MB → large 1.5GB). Chunks de 5 segundos en tiempo real con MediaRecorder. Timestamps por segmento. 11 idiomas. Visualizador de audio con barras de frecuencia en Canvas.

📡 Bluetooth multi-dispositivo

Scan de auriculares Bluetooth + USB. 4 roles con permisos: coordinator (broadcast), operator (recibe), supervisor (full), support (recibe). Heartbeat cada 30s. Cola de mensajes con prioridad (urgent > high > normal > low). Detección automática: AirPods, JBL, Sony, Bose.

Caching inteligente: Cada audio generado se cachea con un hash MD5 de texto:voz:velocidad:slow. Si el mismo mensaje se envía dos veces, el audio se reproduce del cache — sin regenerar. Control de velocidad 0.5x–2.0x adaptado por motor.

8 PythonBridge: JSON Lines sobre stdio

Audio Hub necesita Python para Whisper y los motores TTS. El bridge es deliberadamente simple: un child_process.spawn() que envía y recibe líneas JSON por stdin/stdout.

// Node → Python (stdin): una línea JSON por request { "id": 1, "command": "transcribe", "params": { "audio_base64": "UklGR..." } } // Python → Node (stdout): correlación por ID { "type": "response", "id": 1, "data": { "text": "Necesito asistencia en zona 3" } } // Handshake al startup: { "type": "ready", "data": { "capabilities": ["transcribe", "stt", "tts"], "whisper_model": "base", "tts_engine": "gTTS (Google)" }}
10s startup timeout
30s per-request timeout
PYTHONUNBUFFERED=1 evitar deadlocks

9 El puente Cadences: donde todo se conecta

Ambas apps se registran como agentes en el backend de Cadences — cada instancia con su UUID, tipo (iot-hub / audio-hub), e info del host. Esto permite que un evento en cualquier agente dispare un workflow en Cadences que ejecute acciones en cualquier otro agente — o en cualquier canal de comunicación.

IoT Hub → Cadences

Sync cada 5 min: registro de agente, inventario de devices, upload de readings (últimas 24h, hasta 1,000), fetch de comandos pendientes. El automation engine puede disparar cadences_workflow como acción — un umbral de temperatura ejecuta un workflow completo en cloud.

Audio Hub → Cadences

Verificación de cuenta, registro como agente audio-hub, recepción de mensajes programados, reporte de estado de dispositivos Bluetooth. POST /api/agents/register con tipo y capabilities.

Cadences → Cualquier canal de salida

El workflow que procesa el evento puede despachar la acción por cualquier canal que Cadences tenga integrado — no está limitado al auricular.

🔌 Cadences como Swiss Army knife de salida

🔊 Audio Hub TTS al auricular Bluetooth
📲 WhatsApp Mensaje via API de WhatsApp
📞 Llamada Twilio voice call
📧 Email Notificación por correo
📡 SMS Twilio SMS
🔔 Push / In-app Notificación en cadences.app

El workflow IA no solo elige qué decir, sino por qué canal: si es urgente, llamada. Si es informativo, WhatsApp. Si el equipo está en campo, auricular. Si es un reporte, email.

10 Escenarios reales: del mundo físico a la acción inteligente

🏭

Seguridad de instalaciones industriales

Trigger: sensor de vibración en zona restringida + sensor PIR detecta movimiento fuera de horario. Condición: es después de las 22:00 y día laborable. Acción: cámara captura snapshot → workflow Cadences evalúa la imagen → si es intrusión: llamada automática a seguridad + broadcast TTS al equipo de guardia por auricular + WhatsApp al supervisor con la foto + activar escena "Alert" (luces encendidas + sirena).

🌡️

Monitoreo de infraestructuras y HVAC

Trigger: temperatura de sala de servidores supera 28°C (threshold + cooldown 15 min). Acción: comando MQTT al HVAC para modo de emergencia → workflow Cadences analiza tendencia de las últimas horas → si la tendencia es ascendente: email al equipo de facilities con gráfico + SMS al técnico de guardia + TTS al auricular del operador de turno: "Atención, sala de servidores a {{value}} grados, tendencia ascendente, HVAC en modo emergencia".

👷

Coordinación de equipos en campo

Escenario: un técnico en campo dice por su auricular "Necesito asistencia en zona 3". Whisper transcribe → Cadences lo procesa como ticket → el agente IA consulta disponibilidad del equipo → envía por TTS al auricular del técnico más cercano: "Carlos, Pedro necesita asistencia en zona 3, puedes dirigirte" → confirma por WhatsApp al supervisor.

🏡

Automatización de edificios inteligentes

Trigger: sunrise + sensor de presencia detecta primera persona. Acción: activar escena "Good Morning" (luces graduales, HVAC confort, persianas) → Audio Hub lee el briefing del día por TTS: "Buenos días, hoy tienes 3 reuniones y la sala A está reservada de 10 a 12" → datos sacados del calendario del proyecto en Cadences.

🌱

Agricultura y monitoreo remoto

Trigger: sensor de humedad de suelo vía LoRa baja de 30%. Acción: activar válvula de riego vía relé (Serial) → si no hay respuesta del actuador en 60s: SMS al encargado + workflow que abre ticket de mantenimiento. IoT Hub funciona offline con SQLite y synca cuando hay conexión celular.

11 Almacenamiento local: SQLite offline-first

IoT Hub — 14 tablas

devices — inventario con protocolo, config, firmware, ubicación, tags
readings — time-series de sensores con calidad y metadata
commands — cola de comandos con prioridad 1–10 y retry
captures — fotos/videos de cámaras con dimensiones y duración
automations — reglas con trigger, conditions, actions JSON
scenes — presets multi-dispositivo
alerts + alert_history — definición + ocurrencias + ACK
mqtt_brokers + mqtt_subscriptions
dashboards — layouts personalizables JSON

Audio Hub — 9 tablas

devices — Bluetooth con MAC, rol, empleado, batería, señal
audio_messages — TTS con archivo, status, prioridad
message_queue — cola por dispositivo con prioridad
roles — coordinator, operator, supervisor, support
groups — grupos de comunicación
transcriptions — resultados Whisper con confianza y timing
tts_cache — cache indexado por hash MD5
quick_phrases — frases rápidas por categoría y rol
event_log — auditoría completa

12 El stack completo

Capa IoT Hub Audio Hub
Desktop Electron 33 Electron 33
Database better-sqlite3 (WAL) better-sqlite3 (WAL)
IoT protocols MQTT + Serial + HTTP
Audio input Whisper (Python)
Audio output gTTS + edge-tts + pyttsx3 + ElevenLabs + OpenAI
Cámaras ffmpeg (RTSP, USB, ESP32, doorbell)
Automatización Rule engine 796 líneas + Scene manager Cola con prioridades + roles
Python bridge JSON Lines over stdio
Cadences sync Auto-sync 5 min + workflow trigger Agent register + scheduled messages
IPC channels 50+ handlers 40+ handlers
UI HTML/CSS/JS + Chart.js HTML/CSS/JS + Canvas visualizer

13 Lo que aprendimos

1. Electron como agente de dominio

El patrón "app Electron que se registra como agente en un backend cloud" es poderoso. Cada app es autónoma offline, tiene acceso completo al SO, y se sincroniza cuando puede. El backend no necesita saber cómo funciona cada agente — solo recibe eventos y despacha acciones.

2. Protocol-agnostic routing

El automation engine no sabe si un device habla MQTT, Serial o HTTP. Emite execute-device-command y main.js lo rutea al protocolo correcto. Añadir un protocolo nuevo (BLE, Modbus TCP) solo requiere un manager nuevo, sin tocar el engine.

3. El canal de salida es una decisión del workflow, no de la app

Diseñar Audio Hub como un canal de salida de Cadences — no como el canal — fue la decisión de arquitectura más importante. El mismo evento puede acabar en un auricular, un WhatsApp, una llamada de Twilio, un email o un SMS. El workflow IA decide el canal según urgencia, contexto y disponibilidad del destinatario.

4. ffmpeg es la mejor abstracción de cámaras que existe

En lugar de un SDK por fabricante, todo pasa por ffmpeg. RTSP, DirectShow, V4L2, HTTP/MJPEG — ffmpeg ya los soporta todos. Snapshot en 1 línea, grabación H.264 en 3 argumentos, detección de USB en 1 comando. Cross-platform sin cambios.

5. SQLite WAL + sync oportunista = offline-first sin dolor

SQLite con WAL mode permite lecturas concurrentes mientras se escribe. Los agentes almacenan todo local, y el sync service sube los datos pendientes cuando hay conexión. Para IoT en campo — sin WiFi estable — es la única arquitectura que funciona.

📊 Del Sensor al Auricular en cifras

2 apps Electron
40+ device types
15 protocolos soportados
5 motores TTS
90+ IPC handlers combinados
23 tablas SQLite (14+9)
6+ canales de salida
1 orquestador central
C

Cadences Engineering

Documentación técnica del equipo de ingeniería