Ir al contenido principal

Configurar MQTT genérico en Crimson: tags Red Lion a la nube

Envía tags de Red Lion Crimson 3.1 o 3.2 a Ubidots con el conector Generic MQTT: tus tópicos, tags de texto, varios dispositivos y un decodificador UbiFunction.

Escrito por Sergio M

El conector Generic MQTT de Crimson publica los tags de Red Lion como JSON en el tópico MQTT que elijas, en Crimson 3.1 y 3.2. Con Ubidots, apúntalo al broker de Ubidots o a una UbiFunction que primero transforme cada mensaje. Usa el conector Generic MQTT en lugar del conector Ubidots MQTT integrado en Crimson cuando necesites tus propios tópicos, tags de texto o varios dispositivos por conector.

Un dispositivo de Ubidots llamado Line 1 con variables publicadas por el conector Generic MQTT de Crimson: officetemp, linespeed, partcount, running y connected

Cuándo usar Generic MQTT en lugar del conector de Ubidots

El conector Ubidots MQTT de Crimson necesita tres ajustes: un host, un nombre de dispositivo y un token. El conector Generic MQTT, en cambio, expone el tópico MQTT, el inicio de sesión y el formato del mensaje, así que sirve para configuraciones que el conector de Ubidots no permite. El manual Crimson 3.2 Software Guide (LP1153, capítulo 24) lista los ajustes de ambos conectores. Para tags numéricos que van a un solo dispositivo, la guía del conector Ubidots MQTT es más corta.

Necesidad

Conector Ubidots MQTT

Conector Generic MQTT

Tópico MQTT

Se construye a partir del Device Name

Cualquier Publication Topic, más un Topic Suffix por tag set en Crimson 3.2

Inicio de sesión

Access Token

User Name y Password, que las UbiFunctions necesitan

Tags de texto

No se envían

Se envían como texto JSON; una UbiFunction los guarda en el contexto del dot

Formato del mensaje

Fijo

Force Into Root, Data Encoding, Label Set, Tag Structure, Site Name

Builds de Crimson

3.2.0014.0 y 3.1.3119.001 o posteriores

También builds anteriores

Escrituras de Ubidots a los tags

Tag Writes en el tag set

No se cubre aquí: la suscripción espera el formato JSON propio de Crimson

Dos rutas hacia Ubidots

La ruta A publica directamente en el broker de Ubidots, en industrial.api.ubidots.com. La ruta B publica en una UbiFunction en functions.ubidots.com, que convierte cada mensaje de Crimson y lo escribe en Ubidots. La ruta A tiene menos piezas; la ruta B conserva más datos.

Ruta A: broker de Ubidots

Ruta B: UbiFunction

Variables

Una por tag numérico, más connected y una variable timestamp con la hora de Crimson en segundos Unix

Una por tag, más connected

Tags de texto

Se descartan

Se guardan como texto en el contexto del dot

Hora de cada valor

Hora de llegada a Ubidots

La marca de tiempo de Crimson, así que los datos del buffer conservan su hora original

Varios dispositivos

Un conector por dispositivo (Crimson 3.2)

Un conector, con un Topic Suffix por tag set

Probada en hardware

Sí, Crimson 3.1 en un CR3000

No, consulta Solución de problemas

Requisitos

  • Un dispositivo Red Lion programado con Crimson 3.1 o 3.2 y software Group 2 o superior, por ejemplo un FlexEdge, un HMI Graphite o CR3000, o un DA30D. Descarga Crimson desde la página de Crimson de HMS Networks.

  • Una cuenta de Ubidots, tu token de Ubidots y, para la ruta B, tu nombre de usuario de Ubidots.

  • Una red que permita al dispositivo llegar a industrial.api.ubidots.com (ruta A) o a functions.ubidots.com (ruta B) por el puerto 8883 con TLS, o 1883 sin TLS, con gateway predeterminado y servidores DNS.

1. Crea los tags y activa el conector Generic MQTT

El conector Generic MQTT publica los tags de datos que pongas en sus tag sets. Crea tus tags en Data Tags; el ejemplo de esta guía usa cuatro tags numéricos de un HMI CR3000. Luego abre Communications, selecciona Generic MQTT en Connectors y pon Enable Agent en Yes en la pestaña Service.

Lista Data Tags de Crimson con los tags de ejemplo officeTemp, upDown, changeValue y testValue
  1. En Diagnostics, escribe en Status el nombre de un tag nuevo, como connectionStatus. Crimson ofrece crear el tag; haz clic en Yes. El conector escribe su estado en este tag, de 0 a 4.

  2. En la pestaña Device Data, pon Transfer Mode en Disabled. El bloque del dispositivo contiene marcadores de posición, no datos.

  3. En la pestaña Tag Set 1, deja Transfer Mode en Periodic, configura el Update Rate y arrastra tus tags hasta Contents. Usa más tag sets para los tags que necesiten otra frecuencia.

Pestaña Tag Set 1 de Generic MQTT en Crimson: transferencia Periodic cada 1.0 segundos, Label Set, Tag Structure y cuatro tags en Contents

2A. Ruta A: publica en el broker de Ubidots

En la ruta A, el conector Generic MQTT publica en un tópico de dispositivo de Ubidots, y el broker convierte cada clave numérica en una variable. El mensaje por defecto de Crimson anida los tags y envía algunos valores como texto, que el broker no puede leer, así que Force into Root y Numeric Only deben estar activados. Configura la pestaña Service así.

Campo

Valor

Host Name 1

industrial.api.ubidots.com

Client ID

Cualquier nombre único para este dispositivo, por ejemplo line-1-cr3000

Publication Topic

/v1.6/devices/<device-label>, por ejemplo /v1.6/devices/line-1, en minúsculas

Subscription Topic

Déjalo vacío

Use Dollar Sign

No

Force into Root

Enabled

Data Encoding

Numeric Only

User Name

Tu token de Ubidots

Password

Déjalo vacío

Pestaña Service de Generic MQTT en Crimson para la ruta A: Host Name 1 industrial.api.ubidots.com, Publication Topic /v1.6/devices/helloedge, Force into Root en Enabled y Data Encoding en Numeric Only

En la pestaña Network, pon Transport Protocol en TLS y Connect via Port en 8883, y luego descarga la base de datos al dispositivo. Para alimentar varios dispositivos de Ubidots en Crimson 3.2, agrega en Connectors un conector Generic MQTT por dispositivo, cada uno con su propio Publication Topic.

2B. Ruta B: publica en una UbiFunction

En la ruta B, el conector Generic MQTT publica el JSON completo de Crimson en una UbiFunction, y la función escribe los valores en Ubidots. La función conserva los tags de texto como texto, usa la marca de tiempo de Crimson como la hora de cada valor y lee la etiqueta del dispositivo desde el tópico. La ruta B no se ha probado en hardware Red Lion; lee primero la nota sobre reconexiones en Solución de problemas.

Crea la función decodificadora

  1. En Ubidots, ve a Dev Center → Functions y haz clic en +.

  2. Pon crimson-decoder en Name, POST en Method y Python 3.14 Lite en Runtime.

  3. Reemplaza el código de ejemplo por el código de abajo, pon tu token de Ubidots en TOKEN y guarda la función.

  4. Copia la etiqueta de la función desde el final de la URL de su endpoint HTTPS, /prv/<your-username>/<function-label>. La etiqueta puede ser distinta del nombre, por ejemplo con guiones bajos.

import json
import re
from datetime import datetime

import requests

BASE_URL = "https://industrial.api.ubidots.com"
TOKEN = "PUT-YOUR-TOKEN-HERE"
DEFAULT_DEVICE = "crimson"

# Crimson agrega estas claves a cada mensaje; no son tags.
SKIP = {"device", "cid"}


def label(name):
# Etiquetas de Ubidots: minúsculas, números, - y _. "Group1.Tag1" -> "group1-tag1", "Tag2 [0]" -> "tag2-0"
text = re.sub(r"[^a-z0-9_-]+", "-", str(name).lower())
return text.strip("-")[:50]


def to_number(value):
if isinstance(value, bool):
return int(value)
if isinstance(value, (int, float)):
return value
if isinstance(value, str) and value.lower() in ("true", "false"):
return 1 if value.lower() == "true" else 0
return None


def timestamp_ms(value):
# Numeric Only envía segundos Unix; las demás codificaciones envían ISO 8601 ("2018-12-05T18:14:52.000Z")
if isinstance(value, (int, float)) and not isinstance(value, bool):
return int(value * 1000)
if isinstance(value, str):
try:
return int(datetime.fromisoformat(value.replace("Z", "+00:00")).timestamp() * 1000)
except ValueError:
return None
return None


def flatten(tags, prefix=""):
# Carpetas, tag sets con etiqueta y arreglos llegan como objetos anidados; sus nombres se unen con "-".
for name, value in tags.items():
if name in SKIP:
continue
full = f"{prefix}-{name}" if prefix else str(name)
if isinstance(value, dict) and "Value" in value: # Send Properties: el dato está en "Value"
yield full, value["Value"], value.get("Units") or ""
elif isinstance(value, dict):
yield from flatten(value, full)
else:
yield full, value, ""


def main(args):
payload = args.get("payload") or {}
if isinstance(payload, str):
payload = json.loads(payload)

# Tópico: /prv/<username>/<function-label>/<device-label>; el Topic Suffix de un tag set puede aportar el último nivel.
# Los niveles vacíos se omiten, así que un sufijo con o sin "/" propio da el mismo dispositivo.
parts = [part for part in args["topic"].split("/") if part]
device_label = label(parts[3]) if len(parts) > 3 else DEFAULT_DEVICE

ts = timestamp_ms(payload.get("timestamp"))
dots = {}

def add(name, value, units=""):
key = label(name)
if not key:
return
number = to_number(value)
if number is not None:
dot = {"value": number}
if units:
dot["context"] = {"units": units}
elif isinstance(value, str):
dot = {"value": 1, "context": {"text": value}} # tag de texto: el texto va en el contexto del punto
else:
return
if ts:
dot["timestamp"] = ts
dots[key] = dot

tags = payload.get("tags")
if isinstance(tags, dict):
for name, value, units in flatten(tags):
add(name, value, units)
else:
# Force Into Root: los tags quedan en el nivel superior junto a connected y timestamp
for name, value in payload.items():
if name not in SKIP | {"tags", "timestamp", "connected", "historic", "adhoc"} and not isinstance(value, dict):
add(name, value)

if "connected" in payload: # true en cada envío, false en el mensaje de última voluntad
add("connected", payload["connected"])

if not dots:
return {"status": "ignored"}

response = requests.post(
f"{BASE_URL}/api/v1.6/devices/{device_label}/",
headers={"X-Auth-Token": TOKEN, "Content-Type": "application/json"},
json=dots,
timeout=10,
)
return {"status": response.status_code, "text": response.text}

Apunta el conector a la función

Campo

Valor

Host Name 1

functions.ubidots.com

Client ID

Cualquier nombre único para este dispositivo

Publication Topic

/prv/<your-username>/<function-label>/<device-label>, por ejemplo /prv/acme/crimson-decoder/line-1

Subscription Topic

Déjalo vacío

Force into Root

Disabled

Data Encoding

Standard

User Name

Tu nombre de usuario de Ubidots

Password

Tu token de Ubidots


Nota: el endpoint de funciones recibe tu nombre de usuario como usuario MQTT y tu token como contraseña. Es al revés que en el broker de Ubidots de la ruta A, donde el token es el nombre de usuario.


En la pestaña Network, pon Transport Protocol en TLS y Connect via Port en 8883. Para enviar los tag sets a dispositivos distintos, termina el Publication Topic en la etiqueta de la función y dale a cada tag set un Topic Suffix con la etiqueta de su dispositivo, como /line-1 y /line-2. La función lee la etiqueta del dispositivo del último nivel del tópico.

3. Revisa los mensajes y los datos

El servidor web de Crimson, en los dispositivos con software Group 3 o superior, tiene una Debug Console que muestra cada mensaje MQTT que envía el conector, con su tópico y su JSON. Actívala en Web Server → Features → System Pages con Debug Console en Enabled with Commands, y pon Debug Output en Enabled en la pestaña Network del conector. Después de descargar la base de datos, abre el servidor web del dispositivo y elige System → Debug Console.

Pestaña Features de Web Server en Crimson con Debug Console en Enabled with Commands
Debug Console de Crimson con una publicación MQTT en /v1.6/devices/helloedge con changeValue, connected, officeTemp, timestamp y upDown

La captura de arriba es un mensaje de la ruta A desde Crimson 3.1: {"changeValue":0,"connected":1,"connectionInteger":4,"officeTemp":0,"testValue":0,"timestamp":1573231789,"upDown":0}. En Ubidots, ve a Devices → Devices: el dispositivo tiene una variable por clave, en minúsculas.

Solución de problemas

¿Por qué mis tags de Crimson no aparecen en Ubidots?

  • Ruta A, no llega nada. El broker no puede leer el mensaje anidado de Crimson ni los valores de texto. Revisa que Force into Root esté en Enabled y Data Encoding en Numeric Only, y que el Publication Topic sea /v1.6/devices/ seguido de una etiqueta de dispositivo en minúsculas.

  • El conector nunca se conecta. En la ruta A, el usuario es tu token y la contraseña va vacía; en la ruta B, el usuario es tu nombre de usuario y la contraseña es tu token. El puerto debe coincidir con el transporte: 8883 con TLS, 1883 con TCP.

  • Ruta B, conectado pero sin dispositivo. Abre los logs de la función. El tópico debe empezar por /prv/<your-username>/<function-label>/, con la etiqueta que aparece en la URL del endpoint, y el método de la función debe ser POST. Un 401 o 403 en los logs significa que el token del código está mal.

  • El tag Status se queda por debajo de 4. Los valores significan lo mismo que en el conector de Ubidots; consulta la tabla de Status en la guía de configuración del FlexEdge.

¿Por qué el conector se reconecta una y otra vez a functions.ubidots.com?

Según el manual Crimson 3.2 Software Guide, el conector Generic MQTT se suscribe a su Subscription Topic, o a crimson/generic/<client-id>/sub cuando ese campo está vacío ($crimson/… cuando Use Dollar Sign está en Yes). El endpoint de funciones acepta publicaciones bajo /prv/<your-username>/ y rechaza las suscripciones. Si el endpoint cierra la conexión por esa suscripción, el tag Status vuelve una y otra vez a 0 o 1. Usa la ruta A para tags numéricos, o pon un puente adelante: un broker Mosquitto local o un flujo de Node-RED que reciba los mensajes de Crimson y los reenvíe a functions.ubidots.com. Para una flota, el equipo de ventas de Ubidots puede asignar un broker dedicado a tu función.

Preguntas frecuentes

¿Qué JSON publica el conector Generic MQTT de Crimson?

El conector Generic MQTT publica un objeto device, un objeto tags con una clave por tag, connected y timestamp. Con Force into Root, cada valor sube al nivel superior. Con Numeric Only, true y false pasan a 1 y 0, y el timestamp a segundos Unix. Label Set envuelve cada tag set en su propio objeto, como set1.

¿Cómo aparecen los tags de texto en Ubidots?

En la ruta B, el decodificador escribe cada tag de texto como variable con valor 1, con el texto en el contexto del dot, bajo text, porque Ubidots no guarda texto como valor. Un widget de tabla o la lista de dots lo muestran. La ruta A descarta los tags de texto: Numeric Only no puede codificarlos.

¿La ruta A conserva las marcas de tiempo de Crimson?

No. En la ruta A, cada valor toma su hora de llegada a Ubidots, y la hora de Crimson llega como una variable timestamp aparte, en segundos Unix. Después de un corte, los datos del buffer quedan con la hora en que se reenvían. La ruta B usa la marca de tiempo de Crimson como hora de cada valor.

¿Ubidots puede escribir valores de vuelta en los tags de Crimson por Generic MQTT?

Esta guía no lo cubre. El conector Generic MQTT espera las escrituras en el JSON de Crimson, como {"tags":{"Tag1":100}}, y Ubidots envía valores simples en sus tópicos /lv. Usa en su lugar Tag Writes del conector Ubidots MQTT, que se explica en la guía de configuración del FlexEdge.

¿Qué versiones de Crimson incluyen el conector Generic MQTT?

Lo incluyen tanto Crimson 3.1 como Crimson 3.2. El conector Generic MQTT es anterior al conector Ubidots MQTT, que llegó en los builds 3.1.3119.001 y 3.2.0014.0 a finales de 2020, así que Generic MQTT también funciona en dispositivos que todavía usan un build anterior de Crimson.

Otras guías de Red Lion

¿Ha quedado contestada tu pregunta?