O Eclipse Tahu é a implementação de referência open source da especificação Sparkplug, com bibliotecas e exemplos em Java, Python e C. Neste guia você vai aprender o que cada parte do repositório Tahu faz, como compilá-lo, quais armadilhas costumam pegar quem o usa pela primeira vez e como conectar um edge node baseado no Tahu a um broker MQTT real e ver os seus births e dados chegando.
O que o Eclipse Tahu é e o que não é
O Sparkplug é mantido pela Eclipse Foundation, e o Tahu é o projeto que transforma a especificação em código funcional. Ele oferece três coisas:
- A definição Protobuf dos payloads Sparkplug B,
sparkplug_b.proto, além do código gerado a partir dela para cada linguagem. - Bibliotecas auxiliares que montam e interpretam payloads: criação de payloads BIRTH e DEATH, inclusão de métricas com os tipos de dados corretos, tratamento dos números de sequência.
- Exemplos e ferramentas de compatibilidade que mostram um edge node e uma aplicação host mínimos e ajudam os fornecedores a verificar as suas implementações contra a especificação.
O que o Eclipse Tahu não é: ele não é um broker MQTT, não é um sistema SCADA e não é um produto de gateway. Todo exemplo do Tahu se conecta como um cliente MQTT comum a um broker fornecido por você. Essa separação é a essência do Sparkplug. O edge node e o host falam Sparkplug, e o broker MQTT no meio só precisa ser um servidor MQTT compatível.
O Tahu também é código de referência. Ele foi escrito para ser claro e correto, não para ser colocado sem alterações em um gateway de produção. Muitas equipes usam diretamente as definições Protobuf e os helpers de payload e escrevem o próprio tratamento de sessão em torno deles, que é exatamente o que faremos abaixo.
Um tour pelo repositório
O código-fonte fica no repositório do Eclipse Tahu no GitHub. Clone-o para explorar:
git clone https://github.com/eclipse-tahu/tahu.git
cd tahu
ls
A estrutura é organizada por linguagem. Os nomes das pastas mudaram entre versões, então trate esta tabela como um mapa e não como uma listagem exata, e consulte o README do branch que você clonar.
| Área | O que você encontra | Uso típico |
|---|---|---|
sparkplug_b (proto) |
A definição .proto dos payloads Sparkplug B |
Gerar bindings para qualquer linguagem |
java |
Biblioteca core, builders e decodificadores de payload, exemplos de edge e host, testes de compatibilidade | Gateways JVM e aplicações host |
python |
core com os helpers sparkplug_b.py e o sparkplug_b_pb2.py gerado, além de exemplos |
Scripts, simuladores, ferramentas de teste |
c |
Codificação de payload core construída sobre o nanopb, além de um cliente de exemplo | Gateways embarcados e dispositivos com recursos limitados |
javascript |
Helpers de codificação de payload para Node.js | Ferramentas baseadas em Node e fluxos no estilo Node-RED |
Java
A implementação em Java é a mais completa. Ela contém classes de modelo para payloads e métricas, codificadores e decodificadores e exemplos de nível mais alto de edge node e de host. Ela é compilada com Maven:
cd java
mvn clean install -DskipTests
Os artefatos resultantes podem ser usados a partir do seu próprio projeto Maven ou Gradle. Java é a escolha natural se você está escrevendo uma aplicação host ou integrando com um SCADA ou MES baseado em JVM.
Python
A pasta Python contém dois arquivos que você vai usar o tempo todo. O sparkplug_b_pb2.py é o módulo Protobuf gerado, e o sparkplug_b.py acrescenta helpers como getNodeBirthPayload, getDeviceBirthPayload, getDdataPayload, getNodeDeathPayload e addMetric, além de uma enumeração MetricDataType. A pasta de exemplos mostra um edge node simples que publica births, envia dados e responde a comandos.
C
A implementação em C codifica e decodifica payloads Sparkplug usando o nanopb, um pequeno runtime Protobuf projetado para microcontroladores. É o ponto de partida se você precisa de Sparkplug em um gateway Linux embarcado ou em um firmware com memória apertada. O cliente de exemplo combina o codificador com uma biblioteca MQTT; você o compila com o Makefile fornecido depois de instalar os headers de desenvolvimento dessa biblioteca.
Armadilhas comuns do Eclipse Tahu
A maioria dos problemas do primeiro dia com o Tahu são problemas de ambiente, e não de Sparkplug.
- O paho-mqtt 2.x quebra os exemplos Python mais antigos. Os exemplos Python do Tahu foram escritos para o paho-mqtt 1.x. Com o paho-mqtt 2.x,
mqtt.Client()exige uma versão da API de callbacks como primeiro argumento. Fixepip install "paho-mqtt<2"para os exemplos ou crie o client comomqtt.Client(mqtt.CallbackAPIVersion.VERSION1, client_id=...)para manter as assinaturas antigas dos callbacks. - Incompatibilidade do runtime Protobuf. Um
sparkplug_b_pb2.pygerado por umprotocantigo pode falhar com um pacoteprotobufnovo, exibindo "Descriptors cannot be created directly". Gere-o de novo comprotoc --python_out=. sparkplug_b.protousando um compilador atual. - Caminhos de importação. Os exemplos importam os helpers core inserindo um caminho relativo. Se você copiar um exemplo para outro lugar, copie também o
sparkplug_b.pye osparkplug_b_pb2.pypara junto dele. - Configurações de conexão fixas no código. Os exemplos apontam para
localhostpor padrão. Edite o host do broker, a porta, o group ID, o edge node ID e as credenciais no início do arquivo. - Group IDs compartilhados em brokers públicos. Os topics Sparkplug sempre começam com
spBv1.0, então em um broker público use um group ID aleatório para não colidir com os testes de outras pessoas.
Conectando um edge node Tahu a um broker MQTT
O script a seguir usa os helpers Python do Tahu com o paho-mqtt 2.x. Copie o sparkplug_b.py e o sparkplug_b_pb2.py da pasta Python core do Tahu para um diretório vazio, adicione este arquivo ao lado deles e instale as dependências com pip install "paho-mqtt>=2.0" protobuf.
import random
import time
import paho.mqtt.client as mqtt
from sparkplug_b import (
MetricDataType,
addMetric,
getDdataPayload,
getDeviceBirthPayload,
getNodeBirthPayload,
getNodeDeathPayload,
)
BROKER = "broker.connectmq.com"
PORT = 1883
GROUP = "tahu-demo-5mz8" # group ID aleatório para o broker público
NODE = "tahu-edge-01"
DEVICE = "pump-01"
CLIENT_ID = f"tahu-edge-{random.randint(1000, 9999)}"
def t(msg_type, device=None):
base = f"spBv1.0/{GROUP}/{msg_type}/{NODE}"
return f"{base}/{device}" if device else base
def publish_births(client):
nbirth = getNodeBirthPayload()
addMetric(nbirth, "Node Control/Rebirth", None, MetricDataType.Boolean, False)
client.publish(t("NBIRTH"), bytearray(nbirth.SerializeToString()), 0, False)
dbirth = getDeviceBirthPayload()
addMetric(dbirth, "Flow", None, MetricDataType.Float, 12.5)
addMetric(dbirth, "Pressure", None, MetricDataType.Float, 3.1)
addMetric(dbirth, "Running", None, MetricDataType.Boolean, True)
client.publish(t("DBIRTH", DEVICE), bytearray(dbirth.SerializeToString()), 0, False)
print("NBIRTH and DBIRTH published")
def on_connect(client, userdata, flags, reason_code, properties):
print("connected:", reason_code)
client.subscribe(t("NCMD"))
publish_births(client)
def on_message(client, userdata, msg):
print("command received on", msg.topic)
publish_births(client) # nesta demo, qualquer NCMD é tratado como pedido de rebirth
# O payload de death precisa ser criado antes do birth para que ambos tenham o mesmo bdSeq
death = getNodeDeathPayload()
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
client.on_connect = on_connect
client.on_message = on_message
client.will_set(t("NDEATH"), bytearray(death.SerializeToString()), 1, False)
client.connect(BROKER, PORT, 60)
client.loop_start()
try:
while True:
time.sleep(3)
ddata = getDdataPayload()
addMetric(ddata, "Flow", None, MetricDataType.Float, round(random.uniform(11, 14), 2))
addMetric(ddata, "Pressure", None, MetricDataType.Float, round(random.uniform(2.8, 3.4), 2))
client.publish(t("DDATA", DEVICE), bytearray(ddata.SerializeToString()), 0, False)
print("DDATA published")
except KeyboardInterrupt:
client.loop_stop()
client.disconnect()
A ordem de getNodeDeathPayload() e getNodeBirthPayload() importa porque os helpers do Tahu gerenciam o contador bdSeq internamente, e o NDEATH registrado como will precisa carregar o mesmo valor do NBIRTH que vem em seguida. Se a sua cópia dos helpers se comportar de outra forma, inspecione a métrica bdSeq nos dois payloads e ajuste.
Execute o script e assine o group em outro terminal:
mosquitto_sub -h broker.connectmq.com -p 1883 -i tahu-watch-5mz8 -t "spBv1.0/tahu-demo-5mz8/#" -v
Você vai ver os topics chegando com payloads binários. Para ler as métricas, abra o tráfego em um portal do ConnectMQ: o topic explorer ao vivo decodifica payloads Sparkplug B, seja Protobuf ou JSON, em métricas nomeadas com tipos de dados e valores. Isso torna rápido confirmar que o Tahu produziu o que você esperava antes de envolver um host SCADA. O broker que você acabou de usar é o servidor MQTT público (gratuito); ele serve para testes e protótipos e pode ser lido por qualquer pessoa, então mantenha nomes e valores reais de tags fora dele.
Do código de referência a um edge node real
Depois que o exemplo funcionar, um edge node de produção precisa de mais do que o Tahu oferece de fábrica:
- bdSeq persistente. Armazene o contador em disco para que ele seja incrementado entre reinícios do processo.
- Report by exception. Publique apenas os valores alterados, com bandas mortas para sinais analógicos ruidosos.
- Store and forward. Armazene os dados em buffer durante quedas do broker e reenvie-os com flags de histórico.
- Aliases. Habilite os aliases de métricas do Sparkplug em links restritos.
- Consciência do host primário. No Sparkplug 3.0, os edge nodes podem esperar a mensagem STATE do host primário antes de publicar os births.
- TLS e credenciais. Passe para a porta 8883 com credenciais por cliente.
Se você quer um script totalmente autocontido, sem os helpers do Tahu, nosso simulador de edge node Sparkplug B monta os payloads diretamente a partir do módulo Protobuf gerado e trata números de sequência e rebirths de forma explícita. Para os detalhes internos do payload, veja tipos de dados do Sparkplug B. A própria especificação é publicada pelo grupo de trabalho Eclipse Sparkplug.
Em produção, por exemplo nas linhas de envase de uma planta em Campinas, conecte os nodes baseados no Tahu a um broker privado. No ConnectMQ, crie um broker no portal, copie os YOUR_USERNAME, YOUR_PASSWORD e YOUR_CLIENT_ID gerados, defina o client ID no script, adicione client.username_pw_set(...) e client.tls_set() e conecte-se à porta 8883. O ConnectMQ pode então republicar os dados Sparkplug B decodificados em topics ISA-95 como connectmq/factory1/production/line1/cnc1/telemetry, que consumidores sem Sparkplug, como historiadores, dashboards ou um gêmeo digital da linha, conseguem ler como dados simples. A arquitetura mais ampla é tratada no nosso guia de IoT industrial com MQTT.
Conecte o Eclipse Tahu ao ConnectMQ
O Tahu entrega payloads corretos; você ainda precisa de um broker confiável entre a borda e o host. O ConnectMQ é um broker MQTT gerenciado com MQTT 3.1.1 e 5.0, TLS na porta 8883, decodificação de Sparkplug B e republicação ISA-95. Crie um broker no plano gratuito Serverless em app.connectmq.com, sem cartão de crédito, e aponte o seu edge node Tahu para ele em poucos minutos.
Perguntas frequentes
O Eclipse Tahu é um broker?
Não. O Eclipse Tahu fornece bibliotecas e exemplos de Sparkplug. Edge nodes e hosts construídos com ele se conectam como clientes MQTT a qualquer broker MQTT compatível.
Qual linguagem do Tahu devo usar?
Use Java para aplicações host e gateways JVM, Python para scripts, simuladores e testes, e C para gateways embarcados com orçamento de memória apertado.
Por que os exemplos Python do Tahu falham com o paho-mqtt 2.x?
O paho-mqtt 2.x exige uma versão da API de callbacks ao criar o client. Fixe o paho-mqtt abaixo da 2.0 para os exemplos ou passe mqtt.CallbackAPIVersion.VERSION1 para manter as assinaturas de callback deles.
O Tahu está pronto para produção?
Ele é código de referência focado em correção. Muitas equipes usam as suas definições Protobuf e helpers de payload em produção, acrescentando o próprio gerenciamento de sessão, buffering e segurança.



