Conexión Modbus TCP — Guía Técnica
Cómo conectar un PLC Modbus TCP a Rela AI: campos del formulario, register map, modos cloud_direct vs edge, emit policies, test de conexión y troubleshooting por tipo de error.
Conexión Modbus TCP
Modbus TCP es el protocolo más común en plantas industriales para exponer registros de PLCs, RTUs y dispositivos de E/S. Rela AI lo soporta de forma nativa: tu PLC se conecta directo al worker de Cloud Run (o via gateway edge) sin middleware adicional.
¿Para qué sirve?
Leer el estado del equipo en tiempo casi real: temperatura del reactor, RPM del motor, contadores de producción, alarmas de seguridad, setpoints de setproceso. Cada registro que configuras se convierte en un evento dentro del pipeline predictivo — se normaliza, se correla, alimenta el Asset Health Index y dispara las reglas que definiste.
¿Cómo funciona?
El worker de Rela AI abre una conexión TCP al PLC (puerto 502 por defecto), hace read_holding_registers / read_coils / etc. a intervalos configurables (default 5 segundos), decodifica el valor según el tipo de dato que le declaraste (int16, uint32, float32, IEEE-754…), y emite un evento sólo cuando el valor cambia significativamente (deadband + política de emisión). El circuit breaker suspende reintentos cuando el PLC está inalcanzable durante más de 10 ciclos consecutivos, y emite una alarma canónica PLC_UNREACHABLE para que el operador la vea.
Beneficios
| Sin middleware | Conexión directa PLC → Rela AI. Nada de SCADA intermedio ni brokers MQTT obligatorios. |
| Decodificación declarativa | Eliges el data type + byte order en la UI; el worker hace el decode (IEEE-754, two's complement, word swap, etc.). |
| Polling optimizado | Los registros contiguos se agrupan en un solo read_holding_registers (hasta 125 words / call) para minimizar round-trips al PLC. |
| Emit policies configurables | Por registro: data_change (delta absoluta/relativa), threshold_crossed (cruza un umbral), bit_flip (para booleans). |
| Observabilidad SRE-grade | Métricas Prometheus por tenant+source: modbus_poll_latency_seconds, modbus_connection_state, modbus_tag_staleness_seconds. |
Alta de una fuente Modbus — paso a paso
1. Navegar a fuentes
Dashboard → Alarmas → Fuentes → Nueva fuente. Elige protocolo Modbus TCP.
2. Completar los campos principales
| Campo | Dónde viene | Ejemplo |
|---|---|---|
| Nombre | Libre (para identificar la fuente en el inbox) | Reactor Línea 3 |
| Host | IP o hostname del PLC dentro de tu red | 10.200.7.50 |
| Puerto | 502 por defecto (Modbus estándar) | 502 |
| Unit ID | Slave ID del dispositivo (1 si es un PLC directo, >1 si hay gateway RS-485 al frente) | 1 |
| Deployment Mode | cloud_direct si el PLC se alcanza desde GCP vía VPN/VPC; edge si está detrás de firewall estricto | cloud_direct |
| Edge Gateway ID | Sólo si deployment_mode=edge — referencia al gateway registrado | gw_a1b2c3 |
Si configuraste una VPN en Configuración → Conectividad VPN, el host del PLC es la IP privada dentro de tu subnet OT (por ejemplo 192.168.10.20). Si no, necesitas exponer el PLC por un túnel — nunca directo a internet.
3. Agregar el map de registros
Cada fila del map describe un registro que queremos leer. Los campos son:
| Campo | Significado |
|---|---|
| Tipo de registro | holding (FC03), input (FC04), coil (FC01), discrete (FC02). El más común es holding. |
| Nombre | Etiqueta humana — por ejemplo reactor.temperature. Se usa como tag en las métricas Prometheus y en el inbox. |
| Address | Dirección base 0. Si tu PLC documenta en base 1 (Modicon: 40001 = holding[0]), restá 1. |
| Count | Cuántos words leer. 1 para int16/uint16, 2 para int32/uint32/float32, 4 para float64. |
| Data type | int16, uint16, int32, uint32, float32, float64. Para coil/discrete: siempre booleano. |
| Byte order | big_endian (ABCD, por defecto — AB-CD es dos words), little_endian (DCBA), big_endian_swap (BADC), little_endian_swap (CDAB). |
| Poll interval | Segundos entre lecturas (5 default). Menor = más tráfico + carga al PLC. |
4. Configurar emit policy por registro
Tres modos, pensados para distintos tipos de señal:
- data_change — emite cuando el valor cambia más allá del deadband (absoluto o relativo %). Para analógicos ruidosos donde cada jitter no importa.
- threshold_crossed — emite exactamente una vez cuando el valor cruza un umbral. Requiere operador (
>,>=,<,<=) + valor. Útil para alarmas duras tipo "temperatura > 90 °C". - bit_flip — emite en cada cambio
0→1o1→0. Obligatorio para coils/discretes (booleanos).
5. Guardar y probar conexión
Al guardar, verás el botón Test connection arriba de la lista de registros. Pulsarlo:
- Abre una conexión TCP al PLC.
- Lee cada registro del map una vez.
- Muestra el RTT en ms + los valores decodificados + warnings por si algún registro falló.
Si ves rtt_ms entre 50 y 300 con los valores esperados, estás listo. El listener arranca automáticamente y empieza a emitir eventos al pipeline.
Deployment modes — cuándo usar cada uno
cloud_direct
El worker de Rela AI (Cloud Run en europe-west1) abre la conexión TCP. Requiere que la IP del PLC sea alcanzable desde nuestro VPC — típicamente vía Conectividad VPN (WireGuard dedicado, ver VPN / Alta).
Usa este modo cuando:
- Tenés VPN WireGuard o site-to-site configurada.
- El firewall de planta permite conexión entrante al puerto 502 desde la IP VPN asignada (10.200.X.X).
- La red OT está segmentada pero alcanzable desde la DMZ o red corporativa.
edge
Instalás un contenedor rela-ai-edge en un mini-PC / Raspberry Pi dentro de la planta. El contenedor abre una conexión saliente (outbound HTTPS) al worker de Cloud Run, y el polling Modbus ocurre localmente en la planta.
Usa este modo cuando:
- El firewall sólo permite tráfico saliente HTTPS (443) hacia dominios específicos.
- No tenés posibilidad de configurar VPN (IT no aprueba, equipo viejo, etc.).
- Querés buffering local en caso de pérdida temporal de conexión a internet.
Ver Edge Gateway para la guía completa de instalación del contenedor.
Decodificación de datos — referencia rápida
Analógicos (int16, uint16)
Un solo word, 16 bits. int16 interpreta el MSB como signo (two's complement); uint16 va de 0 a 65535.
Ejemplo: tu PLC expone reactor.temperature × 10 en holding[0]. Lees:
data_type: uint16
count: 1Luego divides por 10 en la lógica del agente (via field mapping o en la regla).
Enteros 32-bit (int32, uint32)
Dos words consecutivos. El orden de bytes importa: big_endian (ABCD) es el default de Modicon/Schneider; big_endian_swap (BADC) lo usan Siemens y algunos dispositivos Allen-Bradley.
Ejemplo: runtime.hours como uint32 en holding[4-5]:
address: 4
count: 2
data_type: uint32
byte_order: big_endianSi ves valores absurdos (número gigante que debería ser chico), prueba con big_endian_swap — es el error más común.
Punto flotante (float32 IEEE-754)
Igual que int32 pero interpretado como float. 99% de los PLCs usan big_endian (ABCD) pero Siemens frecuentemente big_endian_swap (BADC).
Si el test de conexión te devuelve un número tipo 3.14e38, tenés el byte order mal.
Coils / Discretes (booleanos)
Address por bit, no por byte. Cada coil = 1 bit. Count controla cuántos bits leés en un solo request (hasta 2000).
Para un E-stop en coil[1]:
register_type: coil
address: 1
count: 1
emit_as: bit_flipTroubleshooting por tipo de error
Connection refused
El PLC rechaza el TCP handshake. Causas:
- El servicio Modbus TCP está apagado en el PLC (verificá en la config del PLC).
- El firewall de planta bloquea el puerto 502 entre el origen (tu gateway VPN o Cloud Run) y el PLC.
- Hay otro cliente Modbus ocupando el único slot disponible (algunos PLCs sólo aceptan 1-2 clientes concurrentes).
Check: desde el gateway VPN o el contenedor edge, nc -zv <PLC_IP> 502. Si falla ahí, el problema es de red.
Connection timeout
El TCP se inicia pero no responde. Causas:
- PLC apagado o en modo STOP.
- Latencia de red excesiva (VPN con muchos saltos).
- MTU mismatch en túnel WireGuard (1420 vs 1500 — raro con Modbus porque los packets son chicos, pero puede pasar).
Check: ping <PLC_IP> desde el mismo origen que el worker. RTT >200 ms suele ser señal de problema de red.
Illegal data address (Modbus exception 02)
Estás pidiendo una dirección que el PLC no expone. Causas:
- Offset 0-based vs 1-based: Modicon documenta
40001pero la dirección Modbus real es0. - Contaste mal los words: float32 necesita address + count=2 para leer 2 words consecutivos. Si pediste count=1, el siguiente registro lee "el segundo word del float anterior" — caos.
Check: abrí el manual del PLC en la sección "Mapping Table" y confirmá la dirección exacta.
Illegal function (Modbus exception 01)
Estás pidiendo una función que el PLC no soporta. Algunos PLCs (viejos, Micrologix, etc.) sólo soportan FC03 (holding) y FC06 (write). Intentar FC04 (input registers) falla.
Check: cambiá register_type a holding y reintentá.
Valores absurdos (muy grandes, muy chicos, 0xFFFF)
Problemas de decodificación, casi siempre byte order.
| Síntoma | Probable causa | Fix |
|---|---|---|
| Valor esperado 25.0, leés ~3.4e38 | float32 con byte order invertido | Probá big_endian_swap |
| Valor esperado 1800, leés 0x0708 (1800) pero como uint16 y esperabas uint32 | Data type equivocado | Cambiá a uint16 o ajustá count |
| Valor esperado 1800, leés 1799 o 1801 | Nada roto — el sensor tiene jitter | Ajustá el deadband |
ConnectionError: operation on closed connection
El PLC cerró la conexión. Suele ser:
- Idle timeout del PLC (algunos Schneider M340 cierran después de 30s sin requests).
- Keepalive TCP deshabilitado en el worker —
poll_interval_seconds: 5evita esto pero si alguno es >30s, puede pasar.
Check: keepalive_seconds en la fuente (default: TCP_KEEPIDLE=30). Si hay un timeout de PLC conocido, bájalo por debajo del timeout.
El test de conexión funciona pero no llegan eventos al inbox
El polling arranca pero los registros no emiten. Causas:
- Emit policy = threshold_crossed: si el valor no cruzó el umbral todavía, no emite nada. Bajá el umbral para validar.
- Agente desactivado: verificá que el machine agent asignado a la fuente está
enabled: true. - Severidad mínima del agente: si el agent tiene
min_severity=critical, los eventosinfose filtran antes de llegar al inbox.
Cómo probar que la conexión funciona end-to-end
Checklist operativo (en orden):
- Dashboard → Alarmas → Fuentes → tu-fuente-modbus: el banner de estado debe estar en verde (
connected). - Test connection:
rtt_ms < 300y los sample_values muestran el valor esperado. - Dashboard → Alarmas → Inbox: a los pocos minutos debés ver eventos con
event_typeigual al nombre del registro (reactor.temperature,motor.speed, etc.). - Metrics (si tenés Grafana conectado):
modbus_connection_state{source_id="<tu-id>"} == 1ymodbus_register_reads_totalsubiendo. - Circuit breaker sano: no debés ver eventos
PLC_UNREACHABLEen el inbox. Si los ves, el túnel o el firewall tienen un problema intermitente.
Templates de dispositivos
Para PLCs populares (Schneider M340, Siemens S7-1500, Allen-Bradley MicroLogix, etc.), tenemos device templates con el register map pre-configurado. En la alta de fuente, pulsá Usar template y elegí tu modelo — se auto-rellenan los campos principales y sólo quedan por ajustar host, port, unit_id.
Si tu dispositivo no está, crea una fuente custom y — opcionalmente — convierte tu configuración en template per-tenant para reutilizarla en futuras plantas.
Limitaciones conocidas
- Writes: actualmente sólo lectura. Para escritura (setpoints, comandos) usa un tool Modbus write desde el agente.
- Max registros por fuente: 64 registros simultáneos. Si necesitás más, partí en múltiples fuentes.
- Precision temporal: polling cada 5s (configurable a 1s mínimo). No es para control de ciclo — es condition monitoring.
Fuentes de Eventos / Conexiones
Fuentes de datos industriales que conectan sensores, PLCs y SCADA a los agentes de Rela AI mediante HTTP, MQTT y OPC UA.
Edge Gateway — Instalación y Operación
Cómo instalar el contenedor rela-ai-edge en tu planta, registrarlo, asignarle fuentes, monitorear el fleet y solucionar problemas de conexión.