Run Sparkplug B clients
This guide configures the gateway for Sparkplug B 3.0 edge nodes and host applications. Sparkplug needs QoS 1 wills, retained messages and, optionally, stored birth certificates. The gateway serves these only when the config file turns them on.
Before you start, you need:
- The
mq-gatewaybinary. - A NATS server with JetStream.
- A NATS user that can create streams and buckets.
- The Sparkplug group IDs of your edge nodes.
1. Write the config file
nats:
url: nats://nats.example.com:4222
user: gateway
password: env://GATEWAY_PASSWORD
bindings:
- { subjects: [spBv1//0.STATE.*, spBv1//0.*.NDEATH.*], stream: SPARKPLUG }
mqtt:
bindings: [SPARKPLUG]
retained: { bucket: MQTT_RETAINED }
sparkplug: { aware: true }
spBv1//0.STATE.*stores the STATE message of each host application. A host application publishes STATE at QoS 1 and uses it as its will. Without this binding, the gateway refuses the host application.spBv1//0.*.NDEATH.*stores the NDEATH will of each edge node.mqtt.retainedkeeps the last STATE of each host application, and the birth certificates.mqtt.sparkplug.awaremakes the gateway a Sparkplug Aware server. It needsmqtt.retained.
In a subject, spBv1.0 becomes spBv1//0, because . separates subject
tokens. mq-gateway binding writes the binding from MQTT filters:
mq-gateway binding --mqtt 'spBv1.0/STATE/+' --mqtt 'spBv1.0/+/NDEATH/+' --stream SPARKPLUG
The other Sparkplug messages use QoS 0 and need no binding. To store all
of them too, bind spBv1.0/# instead.
Sparkplug clients use clean sessions, so you need no sessions bucket.
2. Provision the stream and the bucket
mq-gateway generate --config sparkplug.yaml --format nats-cli > provision.sh
export SPARKPLUG_RETENTION=limits SPARKPLUG_REPLICAS=1 SPARKPLUG_MAX_BYTES=1GB SPARKPLUG_MAX_AGE=24h SPARKPLUG_DISCARD=old SPARKPLUG_MAX_CONSUMERS=20000
export KV_MQTT_RETAINED_REPLICAS=1 KV_MQTT_RETAINED_MAX_BYTES=100MB KV_MQTT_RETAINED_TTL=0
NATS_URL=nats://admin:secret@nats.example.com:4222 bash provision.sh
Keep the bucket TTL at 0, so that each birth certificate stays until the
next birth replaces it. Provision the streams and
buckets explains each limit.
3. Set the permissions
mq-gateway generate --config sparkplug.yaml --format nats-server > permissions.conf
Narrow $client_permissions for each user, as in Configure listeners and
auth. Keep the JetStream, KV and $SYS
subjects. For edge nodes in group G1 and a host application h1:
| User | Publish | Subscribe |
|---|---|---|
Edge node in G1 | spBv1//0.G1.>, $sparkplug.certificates.spBv1//0.G1.> | spBv1//0.G1.NCMD.*, spBv1//0.G1.DCMD.>, spBv1//0.STATE.* |
Host application h1 | spBv1//0.STATE.h1, spBv1//0.*.NCMD.*, spBv1//0.*.DCMD.> | spBv1//0.>, spBv1//0, $sparkplug.certificates.>, $sparkplug.certificates |
The host application subscribes to spBv1.0/#. A # filter also matches
its parent level, so the user needs spBv1//0 too.
An edge node must be able to publish on $sparkplug.certificates.>. If it
cannot, the gateway still delivers its births but stores no certificate. The
gateway then logs Sparkplug certificate not retained.
4. Start the gateway
mq-gateway check --config sparkplug.yaml
mq-gateway --config sparkplug.yaml
Check it works
- Connect a host application and an edge node.
- Connect a third client after the edge node sends its NBIRTH.
- Subscribe the third client to
$sparkplug/certificates/spBv1.0/G1/#.
The third client gets the NBIRTH and each DBIRTH as retained messages. Then it gets each new birth.
A filter that starts with a wildcard, such as #, never matches a
$sparkplug topic.
Next to another fleet
A Sparkplug plant and another fleet can share a gateway. Put each in its own
NATS account, with its own bindings under accounts:
mqtt: {}
accounts:
PLANT_A:
bindings:
- { subjects: [uagv.v2.*.*.connection], stream: VDA_CONNECTION }
mqtt:
bindings: [VDA_CONNECTION]
retained: { bucket: VDA_RETAINED }
sessions: { bucket: VDA_SESSIONS }
PLANT_B:
creds: /etc/mqgw/gw-plant-b.creds
bindings:
- { subjects: [spBv1//0.STATE.*, spBv1//0.*.NDEATH.*], stream: SPARKPLUG }
mqtt:
bindings: [SPARKPLUG]
retained: { bucket: SPARKPLUG_RETAINED }
sparkplug: { aware: true }
PLANT_A is the account of the nats user, so it needs no credential
here. generate prints a section for each account. Its names start with the
account name, such as PLANT_B_SPARKPLUG_RETENTION and
$PLANT_B_client_permissions. Set each <ACCOUNT>_CONTEXT variable to a
nats context of a user in that account.
NATS applications
A NATS application reads all Sparkplug messages on spBv1//0.>, and the
birth certificates on $sparkplug.certificates.spBv1//0.>.