Las implantaciones de MQTT en petróleo y gas se han convertido en una forma estándar de monitorizar cabezas de pozo, oleoductos y gasoductos, estaciones de compresión y baterías de tanques situadas lejos de cualquier fibra. Su modelo de report by exception, sus paquetes pequeños y su tolerancia a enlaces poco fiables encajan con la realidad de las comunicaciones celulares y por satélite. En esta guía aprenderás a diseñar la monitorización remota con MQTT, qué ajustes de keep alive, sesión y QoS funcionan en enlaces caros y cómo construir un publicador de borde que mantenga bajo el ancho de banda sin perder eventos importantes.
Por qué los activos remotos de petróleo y gas encajan con MQTT
Los activos de upstream y midstream comparten una serie de limitaciones que hacen penoso el sondeo tradicional:
- Ancho de banda caro o limitado. Los planes por satélite y algunos celulares facturan por byte o tienen topes de datos estrictos. Sondear cada pocos segundos valores que no cambian es tirar el dinero.
- Alta latencia. Los viajes de ida y vuelta por satélite geoestacionario son largos, así que un maestro que sondea cientos de emplazamientos de forma secuencial acaba con ciclos de escaneo muy lentos.
- Conectividad intermitente. El clima, la alimentación y la cobertura provocan cortes que el sistema de telemetría debe superar sin perder alarmas.
- Presupuesto energético. Las RTU y gateways alimentados por energía solar necesitan que la radio esté inactiva el mayor tiempo posible.
- Exposición de seguridad. Los emplazamientos remotos son accesibles físicamente y se conectan por redes públicas.
MQTT aborda todo esto directamente. Los dispositivos de campo abren una sola conexión TLS saliente y la mantienen, publican solo los cambios significativos y dejan que el broker distribuya los datos al SCADA, a los historiadores y a la analítica. La guía de MQTT en sistemas SCADA explica con más detalle este cambio respecto al sondeo.
Arquitectura de referencia
Una arquitectura típica de MQTT en petróleo y gas tiene cuatro capas:
- Instrumentos y controladores de campo. Computadores de caudal, transmisores de presión y temperatura, radares de nivel de tanque, controladores de bombas y sistemas ESD, que normalmente hablan Modbus o un protocolo propietario en local.
- Gateway de borde o RTU. Lee los dispositivos locales, aplica bandas muertas, pone marcas de tiempo a los valores, los almacena durante los cortes y publica por MQTT. A menudo con Sparkplug B para la compatibilidad con el SCADA.
- Enlace de retorno (backhaul). Celular (LTE, LTE-M), radio con o sin licencia, o satélite (geoestacionario o de órbita baja).
- Broker y consumidores. Un broker central con hosts SCADA, historiadores, contabilidad de producción y sistemas de detección de fugas como suscriptores.
Mantén las funciones de seguridad en local. La parada de emergencia y la protección contra sobrepresión nunca deben depender del enlace ni del broker; MQTT transporta datos de monitorización y, donde esté aprobado, solo comandos de supervisión.
Ajustar MQTT para enlaces celulares y por satélite
Los ajustes por defecto de la mayoría de librerías MQTT dan por hecho una LAN. En enlaces remotos, unos pocos parámetros marcan la diferencia entre un sistema fiable y uno ruidoso y caro.
| Ajuste | Valor por defecto en LAN | Recomendación para enlaces remotos | Por qué |
|---|---|---|---|
| Keep alive | 60 s | De 60 a 300 s, pero por debajo del timeout de inactividad del NAT del operador | Cada PINGREQ cuesta bytes; si es demasiado largo, el NAT corta la sesión TCP en silencio |
| Sesión | Clean session | Sesión persistente (MQTT 5: clean start false más session expiry) | Las suscripciones y los mensajes QoS 1 en cola sobreviven a cortes breves |
| QoS para telemetría | 0 o 1 | 1 para eventos y alarmas, 0 para valores de alta frecuencia que la siguiente muestra sustituye | Equilibrar las garantías de entrega con la sobrecarga de confirmaciones |
| Message expiry (MQTT 5) | Ninguno | Configúralo en comandos y datos de vida corta | Evita que una consigna obsoleta se ejecute tras un corte largo |
| Formato del payload | JSON detallado | JSON compacto con claves cortas, o Protobuf de Sparkplug B | Los bytes importan en enlaces con tarificación por consumo |
| Estrategia de publicación | Intervalo fijo | Report by exception más un latido lento | La mayoría de valores cambian rara vez |
| Espera de reconexión | Inmediata | Exponencial con jitter | Evita tormentas de reconexión tras un corte de red generalizado |
Keep alive y timeouts de NAT
Los operadores celulares sitúan los dispositivos detrás de un NAT de operador (CGNAT), que corta los flujos TCP inactivos tras un periodo que decide el operador. Si tu keep alive es más largo, la conexión muere en silencio y el dispositivo solo se entera cuando falla su siguiente publicación. Mídelo: empieza con 120 segundos, busca reconexiones inexplicables en el registro de conexiones del broker y acórtalo hasta que desaparezcan. En enlaces por satélite, ten en cuenta también los largos tiempos de ida y vuelta al elegir el timeout de ping del cliente.
Report by exception para datos de cabeza de pozo
Una presión de tubing que varía un 0,1 por ciento no necesita cruzar un satélite. Fija bandas muertas por tag según la precisión del instrumento y su relevancia operativa, publica los estados digitales y las alarmas en cada cambio y envía un refresco completo cada 15 a 60 minutos como prueba de vida. La guía de report by exception trata la selección de bandas muertas, y store-and-forward para MQTT explica cómo almacenar y reenviar datos durante los cortes.
Ejemplo: un publicador de borde consciente del ancho de banda
Este publicador en Python usa MQTT 5 con una sesión persistente, claves JSON cortas, bandas muertas por tag, un latido, caducidad de mensajes en los datos de poco valor y espera de reconexión exponencial. Sustituye read_instruments() por tus lecturas Modbus o del computador de caudal.
import json
import random
import time
import uuid
import paho.mqtt.client as mqtt
from paho.mqtt.packettypes import PacketTypes
from paho.mqtt.properties import Properties
# Public test broker for the lab: readable by everyone, so use simulated data only.
BROKER, PORT, USE_TLS = "broker.connectmq.com", 1883, False
USERNAME, PASSWORD = None, None # production: "YOUR_USERNAME", "YOUR_PASSWORD"
CLIENT_ID = f"wellpad-{uuid.uuid4().hex[:8]}" # production: "YOUR_CLIENT_ID"
BASE = f"connectmq/demo/{uuid.uuid4().hex[:6]}/basin1/pad12/well3"
KEEPALIVE = 120
HEARTBEAT = 900 # full refresh every 15 minutes
DEADBANDS = {"tp": 2.0, "cp": 2.0, "ft": 0.5, "lv": 0.02} # psi, psi, degF, m
def read_instruments():
"""Simulated values; replace with real Modbus or flow computer reads."""
return {
"tp": round(850 + random.uniform(-3, 3), 1), # tubing pressure, psi
"cp": round(420 + random.uniform(-3, 3), 1), # casing pressure, psi
"ft": round(96 + random.uniform(-1, 1), 1), # flowline temperature, degF
"lv": round(2.41 + random.uniform(-0.03, 0.03), 3), # tank level, m
"esd": False, # ESD tripped
}
def on_connect(client, userdata, flags, reason_code, properties):
print("Connected:", reason_code, "session present:", flags.session_present)
client.publish(f"{BASE}/st", "online", qos=1, retain=True)
def on_disconnect(client, userdata, flags, reason_code, properties):
print("Disconnected:", reason_code)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID,
protocol=mqtt.MQTTv5)
if USERNAME:
client.username_pw_set(USERNAME, PASSWORD)
if USE_TLS:
client.tls_set()
client.will_set(f"{BASE}/st", "offline", qos=1, retain=True)
client.reconnect_delay_set(min_delay=5, max_delay=300) # exponential backoff
client.on_connect = on_connect
client.on_disconnect = on_disconnect
connect_props = Properties(PacketTypes.CONNECT)
connect_props.SessionExpiryInterval = 1800 # keep the session for 30 minutes
client.connect(BROKER, PORT, keepalive=KEEPALIVE, clean_start=False,
properties=connect_props)
client.loop_start()
expiring = Properties(PacketTypes.PUBLISH)
expiring.MessageExpiryInterval = 3600 # analog values older than 1 h are useless
last, last_full = {}, 0.0
print("Publishing under", BASE)
while True:
values = read_instruments()
now = time.time()
full = now - last_full >= HEARTBEAT
changed = {}
for key, value in values.items():
if isinstance(value, bool):
if full or value != last.get(key):
# alarms and states: QoS 1, own topic, no expiry
client.publish(f"{BASE}/alm/{key}", json.dumps(value), qos=1, retain=True)
last[key] = value
elif full or key not in last or abs(value - last[key]) >= DEADBANDS[key]:
changed[key] = value
last[key] = value
if changed:
changed["t"] = int(now) # epoch seconds: short and unambiguous
client.publish(f"{BASE}/v", json.dumps(changed, separators=(",", ":")),
qos=1, properties=expiring)
if full:
last_full = now
time.sleep(10)
Un mensaje de valores modificados tiene el aspecto {"tp":853.4,"t":1792139421}, unas decenas de bytes en lugar de una instantánea completa en cada escaneo. Obsérvalo desde tu mesa:
mosquitto_sub -h broker.connectmq.com -p 1883 -i wellpad-watch-01 \
-t 'connectmq/demo/+/basin1/#' -v
El servidor MQTT público gratuito conserva las sesiones hasta 30 minutos, lo que coincide con la caducidad de sesión anterior; en los brokers de producción con tu propio plan es donde la ajustas a tu perfil real de cortes.
Seguridad para emplazamientos remotos
Los emplazamientos remotos están expuestos de formas en que no lo está el equipo de planta. Aplica como mínimo estos controles:
- TLS en el puerto 8883 para cada conexión sobre una red pública, con la validación de certificados activada.
- Usuario, contraseña y client ID únicos por emplazamiento, para poder revocar por separado un gateway robado.
- Conectividad solo saliente; ningún puerto entrante en el módem celular ni en el terminal de satélite.
- Solo lectura por defecto. Los comandos remotos, como los cambios de estrangulador (choke), necesitan flujos de aprobación, enclavamientos y caducidad de mensajes.
- Gateways bastionados: servicios no usados desactivados, arranque seguro donde esté disponible y protección física contra manipulaciones.
- Alertas ante desconexiones inesperadas, que pueden indicar manipulación además de problemas del enlace.
Gestión del broker
El broker central es el componente compartido más importante y debe ser accesible desde todos los emplazamientos. ConnectMQ ofrece un broker MQTT gestionado con MQTT 3.1.1 y 5.0, TLS, caducidad de sesión y de mensajes, y credenciales por cliente. Su portal incluye un explorador de topics en vivo, una vista de dispositivos ISA-95 que agrupa emplazamientos y activos, y reglas de alerta por umbral, por ejemplo sobre el nivel de un tanque o la presión de revestimiento (casing), con un registro de alertas para su revisión. Los datos de gateways de borde que usan Sparkplug B pueden decodificarse y republicarse en topics ISA-95 legibles para los consumidores que no hablan Sparkplug. Para flotas más grandes, los planes de pago y dedicados amplían el número de conexiones y el tamaño de los mensajes, y BYOC sitúa el broker MQTT gestionado en tu propia cuenta cloud.
Para saber más sobre la elección de enlaces y el comportamiento de los módems, consulta MQTT sobre red celular y, para la arquitectura general, la guía de IoT industrial con MQTT.
Monitoriza activos remotos con ConnectMQ
Empieza con un solo pad de pozos o una estación de compresión. Crea un broker Serverless gratuito en app.connectmq.com, sin tarjeta de crédito, conecta un gateway de borde con TLS y configura tu primera alerta por umbral sobre una presión o un nivel. Cuando el piloto demuestre su valor, escala sobre el mismo broker MQTT en la nube de ConnectMQ.
Preguntas frecuentes
¿Funciona MQTT sobre enlaces por satélite?
Sí. Las conexiones persistentes de MQTT, sus cabeceras pequeñas y la publicación por excepción encajan con los enlaces por satélite de alta latencia. Ajusta el keep alive, usa sesiones persistentes y mantén compactos los payloads.
¿Qué keep alive debería usar en una red celular?
Empieza en torno a 120 segundos y mantenlo por debajo del timeout de inactividad del NAT del operador. Si ves reconexiones inexplicables, acórtalo.
¿Es mejor Sparkplug B o JSON para la telemetría de petróleo y gas?
Sparkplug B es más compacto y se integra bien con los hosts SCADA. El JSON con claves cortas es más fácil de inspeccionar y funciona bien cuando los payloads son pequeños y los cambios poco frecuentes.
¿Deben enviarse comandos de parada por MQTT?
No. Las funciones de seguridad deben seguir siendo locales e independientes de la red. MQTT es adecuado para la monitorización y, con las salvaguardas adecuadas, para comandos de supervisión.



