tentacle-mqtt
tentacle-mqtt
Bridges NATS to MQTT using Sparkplug B protocol. Handles both reading (variables → MQTT) and writing (MQTT DCMD → variables).
Bidirectional Data Flow
Sources → NATS → tentacle-mqtt → Sparkplug B → MQTT Broker
↓
Variables ← NATS ← tentacle-mqtt ← DCMD ←──────────
Data sources feeding NATS can include:
tentacle-ethernetip→ EtherNet/IP PLC datatentacle-opcua-go→ OPC UA server datatentacle-modbus→ Modbus TCP device datatentacle-plc→ composed/processed variables
Dependencies
Uses @joyautomation/synapse for Sparkplug B protocol. See Sparkplug docs for synapse details.
Sparkplug B UDT Templates
When a variable has a udtTemplate defined (in tentacle-plc), tentacle-mqtt publishes it as a Sparkplug B Template Instance rather than a JSON string. Template definitions are published in NBIRTH.
DCMD Handling (Write Commands)
When Ignition or another Sparkplug client sends a DCMD:
- Synapse receives DCMD on
spBv1.0/{group}/DCMD/{edgeNode}/{deviceId} - Emits
dcmdevent with(topic, payload) - tentacle-mqtt extracts metric name/value from payload
- Publishes to NATS:
{projectId}/{variableId}with value as string - Scanner service (EtherNet/IP, Modbus, etc.) receives and writes to device
Key Code Pattern
// CORRECT - use (topic, payload) signature
node.events.on("dcmd", async (topic: any, payload: { metrics?: any[] }) => {
log.info(`Received DCMD for device ${topic.deviceId}`);
if (payload.metrics) {
for (const metric of payload.metrics) {
// Process metric.name and metric.value
}
}
});
// WRONG - this silently fails (payload ends up being the topic)
node.events.on("dcmd", async (payload) => { ... });
NATS Publishing
NATS requires Uint8Array, not strings:
// WRONG - silently fails or errors
nc.publish(subject, String(value));
// CORRECT
nc.publish(subject, new TextEncoder().encode(String(value)));
Configuration
Uses NATS KV bucket mqtt-config-{projectId} for:
- Which variables are enabled for MQTT
- Per-variable deadband settings
- Default deadband values
Key Files
| File | Purpose |
|---|---|
mqtt.ts | Main bridge logic, DCMD handling |
main.ts | Entry point, config loading |
types/config.ts | Configuration types |
types/mappings.ts | Sparkplug ↔ variable type conversions |