Skip to main content

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-gateway binary.
  • 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.retained keeps the last STATE of each host application, and the birth certificates.
  • mqtt.sparkplug.aware makes the gateway a Sparkplug Aware server. It needs mqtt.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:

UserPublishSubscribe
Edge node in G1spBv1//0.G1.>, $sparkplug.certificates.spBv1//0.G1.>spBv1//0.G1.NCMD.*, spBv1//0.G1.DCMD.>, spBv1//0.STATE.*
Host application h1spBv1//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​

  1. Connect a host application and an edge node.
  2. Connect a third client after the edge node sends its NBIRTH.
  3. 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.>.