El soporte de Beckhoff TwinCAT MQTT permite que un PC industrial Beckhoff publique datos de máquina directamente desde el runtime del PLC, sin un gateway aparte en el armario. En este tutorial usarás las funciones IoT de TwinCAT 3 para conectarte a un broker MQTT, serializar un tipo de dato estructurado a JSON, publicarlo al cambiar y con un temporizador y, por último, proteger la conexión con TLS y credenciales. El mismo patrón escala desde un único banco de pruebas hasta una flota de máquinas.
Comparativa de opciones MQTT en TwinCAT
Beckhoff ofrece más de una vía hacia MQTT, y elegir la adecuada desde el principio ahorra trabajo.
| Opción | Qué es | Quién la configura | Ideal para |
|---|---|---|---|
| TF6701 IoT Communication | Librería de PLC (Tc3_IotBase) con un bloque de función de cliente MQTT | El programador del PLC, en texto estructurado | Control total de topics, payloads y temporización |
| TF6720 IoT Data Agent | Gateway basado en configuración que asigna símbolos ADS a MQTT | Interfaz gráfica de configuración, sin código de PLC | Publicar símbolos existentes sin cambiar el programa del PLC |
| Gateway ADS externo | Tu propio servicio que lee símbolos por ADS y publica MQTT | El equipo de software | Canalizaciones a medida, muchos controladores, formatos no estándar |
Este tutorial usa TF6701 porque es la opción más habitual entre los fabricantes de máquinas que quieren que el comportamiento MQTT forme parte del proyecto de PLC versionado. Tanto TF6701 como TF6720 son funciones de TwinCAT con licencia; una licencia de prueba de 7 días basta para seguir el tutorial.
Requisitos previos
- TwinCAT 3.1 XAE (Visual Studio o TwinCAT XAE Shell) y un destino: un IPC de Beckhoff, o tu PC de ingeniería en modo run para pruebas.
- La función TF6701 instalada en el destino y una licencia de prueba o completa activada.
- Acceso de red saliente desde el destino hasta el broker por TCP 1883 para pruebas y 8883 para TLS.
- Las librerías de PLC Tc3_IotBase y Tc3_JsonXml añadidas a las referencias del proyecto.
- Clientes de mosquitto en un PC para la verificación.
Paso 1: definir un tipo de dato estructurado
Publicar una estructura en lugar de variables sueltas mantiene juntos los valores relacionados y coherentes las marcas de tiempo. Añade un DUT:
TYPE ST_PressData :
STRUCT
rForce_kN : REAL;
rTemperature_C : REAL;
nCycleCount : UDINT;
bRunning : BOOL;
sState : STRING(20);
END_STRUCT
END_TYPE
Paso 2: conectar con FB_IotMqttClient
FB_IotMqttClient, de Tc3_IotBase, se configura mediante propiedades y se controla llamando a su método Execute en cada ciclo. Llámalo desde una tarea con un ciclo de 10 ms o más rápido; el cliente gestiona su propia comunicación en segundo plano, pero solo avanza cuando se llama a Execute.
PROGRAM MAIN
VAR
fbMqttClient : FB_IotMqttClient;
bSetParameter : BOOL := TRUE;
bConnect : BOOL := TRUE;
fbJson : FB_JsonSaxWriter;
stPress : ST_PressData;
stLastPress : ST_PressData;
sTopicData : STRING(255) := 'connectmq/demo/t3w9p1/plant1/stamping/cell4/press1/telemetry';
sPayload : STRING(1023);
fbHeartbeat : TON;
bPublish : BOOL;
END_VAR
// --- One-time client configuration ---
IF bSetParameter THEN
bSetParameter := FALSE;
fbMqttClient.sHostName := 'broker.connectmq.com';
fbMqttClient.nHostPort := 1883;
fbMqttClient.sClientId := 'twincat-demo-t3w9p1'; // non-empty and unique
fbMqttClient.nKeepAlive := 30;
END_IF
// --- Keep the connection alive every cycle ---
fbMqttClient.Execute(bConnect);
// --- Decide when to publish: on change or every 10 s ---
fbHeartbeat(IN := NOT fbHeartbeat.Q, PT := T#10S);
bPublish := fbHeartbeat.Q
OR ABS(stPress.rForce_kN - stLastPress.rForce_kN) > 1.0
OR stPress.bRunning <> stLastPress.bRunning
OR stPress.sState <> stLastPress.sState;
// --- Serialize and publish ---
IF bPublish AND fbMqttClient.bConnected THEN
fbJson.ResetDocument();
fbJson.StartObject();
fbJson.AddKey('force_kN'); fbJson.AddReal(stPress.rForce_kN);
fbJson.AddKey('temperature_C'); fbJson.AddReal(stPress.rTemperature_C);
fbJson.AddKey('cycle_count'); fbJson.AddUdint(stPress.nCycleCount);
fbJson.AddKey('running'); fbJson.AddBool(stPress.bRunning);
fbJson.AddKey('state'); fbJson.AddString(stPress.sState);
fbJson.EndObject();
fbJson.CopyDocument(sPayload, SIZEOF(sPayload));
fbMqttClient.Publish(
sTopic := sTopicData,
pPayload := ADR(sPayload),
nPayloadSize := LEN(sPayload),
eQoS := TcIotMqttQos.AtLeastOnceDelivery,
bRetain := FALSE,
bQueue := FALSE);
stLastPress := stPress;
END_IF
Algunas notas sobre las decisiones anteriores:
CopyDocumenten lugar deGetDocument.GetDocumentdevuelve un string estándar de 255 caracteres, que trunca en silencio los payloads más grandes. Copiar en un buffer dimensionado lo evita.- Report by exception. La banda muerta de fuerza y las comparaciones de estado publican los cambios reales de inmediato, mientras que el latido de 10 segundos demuestra que la máquina sigue viva aunque nada cambie.
- Gestión de errores. Vigila
fbMqttClient.hrErrorCodeyfbMqttClient.eConnectionStateen la vista online durante la puesta en marcha. La mayoría de los fallos aparecen ahí primero.
Para estructuras más grandes, Tc3_JsonXml también ofrece una función auxiliar que serializa un tipo de dato completo, incluidos atributos como las unidades, en una sola llamada. La salida SAX escrita a mano como la anterior te da un control exacto sobre los nombres de las claves, algo importante cuando otros equipos consumen los datos.
Paso 3: verificar en el broker público
Activa la configuración, arranca el PLC y suscríbete desde un PC:
mosquitto_sub -h broker.connectmq.com -p 1883 -i twincat-watch-t3w9p1 \
-t 'connectmq/demo/t3w9p1/#' -v
Salida esperada:
connectmq/demo/t3w9p1/plant1/stamping/cell4/press1/telemetry {"force_kN":412.5,"temperature_C":38.2,"cycle_count":10233,"running":true,"state":"AUTO"}
Fuerza un valor en la vista online y el cambio aparecerá al instante. El servidor MQTT público gratuito broker.connectmq.com, anónimo, es perfecto para este tipo de puesta en marcha, pero es público y está pensado para pruebas y prototipos, no para datos de producción, así que usa un prefijo de topic aleatorio y nada confidencial.
Paso 4: proteger la conexión Beckhoff TwinCAT MQTT
Las máquinas de producción nunca deben publicar por TCP sin cifrar hacia internet. Crea un broker privado en el portal de ConnectMQ, anota el usuario, la contraseña y el client ID generados y después:
- Descarga el certificado ISRG Root X1 (la raíz de Let's Encrypt, que usa el broker de ConnectMQ) y cópialo al destino, por ejemplo en una carpeta
Certificatesdentro del directorio de arranque o de configuración de TwinCAT. - Amplía la configuración inicial:
fbMqttClient.sHostName := 'YOUR_BROKER_HOST';
fbMqttClient.nHostPort := 8883;
fbMqttClient.sClientId := 'YOUR_CLIENT_ID';
fbMqttClient.sUserName := 'YOUR_USERNAME';
fbMqttClient.sUserPassword := 'YOUR_PASSWORD';
fbMqttClient.stTLS.sCA := 'C:\TwinCAT\3.1\Config\Certificates\isrgrootx1.pem';
- Configura un Last Will mediante la estructura de will del cliente, por ejemplo un mensaje retained
offlineenplant1/stamping/cell4/press1/status, y publica unonlineretained en el mismo topic tras conectar. Así los consumidores podrán distinguir una máquina parada de una conexión perdida. - Elimina el prefijo de demostración y usa la jerarquía de topics ISA-95 de tu planta.
Mantén las credenciales fuera del control de versiones: cárgalas desde un archivo en el destino o desde una variable persistente fijada durante la puesta en marcha, en lugar de escribirlas directamente en un proyecto que se comparte.
Diseñar topics para una flota de máquinas
Los fabricantes de máquinas suelen entregar el mismo proyecto TwinCAT a decenas de clientes, por ejemplo a plantas automotrices en el Bajío mexicano o en el País Vasco, así que los topics escritos a fuego se convierten enseguida en un problema de mantenimiento. Algunos hábitos ayudan:
- Convierte el prefijo del topic en un parámetro. Guarda los nombres de empresa, planta, área, línea y máquina en variables persistentes fijadas en la puesta en marcha y construye el string del topic al arrancar.
- Separa datos, estado y eventos. Usa
.../telemetrypara valores periódicos,.../statuspara la información retained de conexión y estado, y.../eventspara alarmas o finalizaciones de lote. Los consumidores se suscriben solo a lo que necesitan. - Versiona tu payload. Una clave
"schema": 1cuesta unos pocos bytes y permite que el código posterior gestione una actualización de firmware que añada o renombre campos. - Mantén los payloads pequeños. Publica los valores que realmente se usan. Los volcados de diagnóstico pueden ir en un topic aparte, bajo demanda.
Estas convenciones también facilitan explorar los datos: un broker que reconoce rutas de estilo ISA-95 puede presentar todas las máquinas en un árbol de plantas y líneas sin configuración adicional, y un gemelo digital 3D de la línea puede suscribirse a la misma jerarquía para mostrar cada prensa en su posición real.
Lista de comprobación para la puesta en marcha
| Comprobación | Por qué importa |
|---|---|
| Reloj del destino sincronizado por NTP | TLS rechaza los certificados cuando el reloj está muy desfasado |
| DNS configurado en el IPC | El hostname del broker debe resolverse |
| Client ID único por máquina | Los duplicados se desconectan entre sí una y otra vez |
| Buffer del payload dimensionado para el JSON más grande | Evita el truncado silencioso |
| Latido más report by exception | Poco tráfico con prueba de vida |
| Topic de estado retained con Last Will | Detección fiable de conexión y desconexión |
| Licencia de TF6701 activada | La licencia de prueba caduca a los 7 días |
Solución de problemas
hrErrorCodemuestra un rechazo de conexión. Credenciales o client ID incorrectos; en brokers que vinculan los client ID a las credenciales, ambos deben coincidir con lo emitido.- Errores TLS tras un reinicio. La ruta del certificado en el destino es incorrecta, o el archivo de la CA no se copió con el proyecto de arranque.
- No se publica nada a pesar de
bConnected.bPublishnunca es verdadero, o se llama aPublishantes de construir el payload. - Los mensajes llegan a ráfagas.
bQueue := TRUEcon una frecuencia de llamada aExecutelenta; llama aExecuteen cada ciclo desde una tarea rápida.
Dónde encaja esto
Publicar desde el IPC es una de varias arquitecturas para sacar datos de máquina; compárala con los diseños basados en gateway y en SCADA de conectividad de PLC a la nube. Si trabajas con controladores de distintas marcas, el tutorial CODESYS MQTT usa un patrón execute-and-publish muy parecido. Y cuando muchas máquinas publican en una misma jerarquía, la guía de IoT industrial con MQTT explica cómo modelarla como un Unified Namespace que cualquier aplicación puede consumir a través del broker MQTT.
Conecta tus máquinas Beckhoff a ConnectMQ
Ejecutar tu propio broker junto a cada máquina implica certificados, actualizaciones y monitorización en cada planta. Un broker MQTT gestionado elimina ese trabajo. Crea un broker Serverless gratuito en app.connectmq.com, sin tarjeta de crédito, y observa cómo llegan tus datos de TwinCAT al explorador de topics en vivo en cuestión de minutos.
Preguntas frecuentes
¿Qué licencia de TwinCAT necesito para MQTT?
El enfoque con librería de PLC requiere TF6701 TwinCAT 3 IoT Communication. La alternativa basada en configuración es TF6720 IoT Data Agent. Ambas ofrecen una licencia de prueba de 7 días.
¿Admite TwinCAT MQTT el uso de TLS?
Sí. Indica la ruta del certificado de la CA en la estructura TLS del cliente, conéctate al puerto 8883 y añade las credenciales. También se admiten certificados de cliente si tu broker los exige.
¿Puede TwinCAT suscribirse a topics MQTT?
Sí. FB_IotMqttClient admite suscripciones con una cola de mensajes que lees en el PLC. Valida cada valor recibido antes de que afecte a la lógica de control.
¿Por qué mi payload JSON se corta a los 255 caracteres?
GetDocument devuelve un string de longitud estándar. Usa CopyDocument hacia un buffer más grande, como se muestra arriba.



