Rela AIRela AI Docs
Agentes de Maquinas

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 middlewareConexión directa PLC → Rela AI. Nada de SCADA intermedio ni brokers MQTT obligatorios.
Decodificación declarativaEliges el data type + byte order en la UI; el worker hace el decode (IEEE-754, two's complement, word swap, etc.).
Polling optimizadoLos registros contiguos se agrupan en un solo read_holding_registers (hasta 125 words / call) para minimizar round-trips al PLC.
Emit policies configurablesPor registro: data_change (delta absoluta/relativa), threshold_crossed (cruza un umbral), bit_flip (para booleans).
Observabilidad SRE-gradeMé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 → FuentesNueva fuente. Elige protocolo Modbus TCP.

2. Completar los campos principales

CampoDónde vieneEjemplo
NombreLibre (para identificar la fuente en el inbox)Reactor Línea 3
HostIP o hostname del PLC dentro de tu red10.200.7.50
Puerto502 por defecto (Modbus estándar)502
Unit IDSlave ID del dispositivo (1 si es un PLC directo, >1 si hay gateway RS-485 al frente)1
Deployment Modecloud_direct si el PLC se alcanza desde GCP vía VPN/VPC; edge si está detrás de firewall estrictocloud_direct
Edge Gateway IDSólo si deployment_mode=edge — referencia al gateway registradogw_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:

CampoSignificado
Tipo de registroholding (FC03), input (FC04), coil (FC01), discrete (FC02). El más común es holding.
NombreEtiqueta humana — por ejemplo reactor.temperature. Se usa como tag en las métricas Prometheus y en el inbox.
AddressDirección base 0. Si tu PLC documenta en base 1 (Modicon: 40001 = holding[0]), restá 1.
CountCuántos words leer. 1 para int16/uint16, 2 para int32/uint32/float32, 4 para float64.
Data typeint16, uint16, int32, uint32, float32, float64. Para coil/discrete: siempre booleano.
Byte orderbig_endian (ABCD, por defecto — AB-CD es dos words), little_endian (DCBA), big_endian_swap (BADC), little_endian_swap (CDAB).
Poll intervalSegundos 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→1 o 1→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:

  1. Abre una conexión TCP al PLC.
  2. Lee cada registro del map una vez.
  3. 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: 1

Luego 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_endian

Si 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_flip

Troubleshooting 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 40001 pero la dirección Modbus real es 0.
  • 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íntomaProbable causaFix
Valor esperado 25.0, leés ~3.4e38float32 con byte order invertidoProbá big_endian_swap
Valor esperado 1800, leés 0x0708 (1800) pero como uint16 y esperabas uint32Data type equivocadoCambiá a uint16 o ajustá count
Valor esperado 1800, leés 1799 o 1801Nada roto — el sensor tiene jitterAjustá 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: 5 evita 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 eventos info se filtran antes de llegar al inbox.

Cómo probar que la conexión funciona end-to-end

Checklist operativo (en orden):

  1. Dashboard → Alarmas → Fuentes → tu-fuente-modbus: el banner de estado debe estar en verde (connected).
  2. Test connection: rtt_ms < 300 y los sample_values muestran el valor esperado.
  3. Dashboard → Alarmas → Inbox: a los pocos minutos debés ver eventos con event_type igual al nombre del registro (reactor.temperature, motor.speed, etc.).
  4. Metrics (si tenés Grafana conectado): modbus_connection_state{source_id="<tu-id>"} == 1 y modbus_register_reads_total subiendo.
  5. Circuit breaker sano: no debés ver eventos PLC_UNREACHABLE en 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.

En esta página