Sparkplug Data
17 min
every message the node publishes or receives sits under the sparkplug b namespace, built from your group id, the message type, and your node id spbv1 0/{group id}/{message type}/{node id}\[/{device id}] for group id=plant1 and node id=line1 , a device named press 002 publishes on spbv1 0/plant1/ddata/line1/press 002 the device segment is the devicehub device name, or the digital twin instance's sparkplug device id; node level messages have no device segment message types type direction topic qos retained purpose nbirth node to broker spbv1 0/{group}/nbirth/{node} 0 no opens a session and declares node metrics dbirth node to broker …/dbirth/{node}/{device} 0 no declares one device's metrics, with names, aliases, and datatypes ddata node to broker …/ddata/{node}/{device} 0 no device metric values, referenced by alias ndata node to broker …/ndata/{node} 0 no node level metric values ddeath node to broker …/ddeath/{node}/{device} 0 no one device is no longer publishing ndeath node or broker …/ndeath/{node} 1 no the session ended ncmd host to node …/ncmd/{node} 1 subscription — command for the node dcmd host to node …/dcmd/{node}/{device} 1 subscription — command for one device state host to broker spbv1 0/state/{host id} 1 subscription set by the host host application liveness ndeath is registered as the mqtt will message when the node connects, at qos 1 and not retained, so the broker publishes it if the node disappears without warning — that is what makes an unplugged device visible to host applications on a clean shutdown the node publishes ndeath itself, so the message arrives once either way birth order host applications reject data for a node they have not seen born, so ordering is strict flowchart lr nb\[nbirth] > db\[dbirth per device] > dd\[ddata] the node holds its publish lock until the broker acknowledges each birth message, so no data message can overtake the birth set nothing is published at all while the birth set is being rebuilt sequence numbers two counters appear in payloads, and host applications check both seq orders messages within one session nbirth carries 0 , each following data or birth message increments by one, and the value wraps to 0 after 255 ndeath carries no seq at all the node consumes a sequence number only for a message it actually sends — a tag update that produces no publishable metric does not advance the counter, which is what keeps host applications from reporting a gap bdseq identifies the session itself the nbirth that opens a session and the ndeath that closes it carry the same value, and the next session uses the next value, wrapping after 255 it is stored at \<config path>/seqnum/\<group> \<node> bdseq txt , which must survive restarts — see deployment # a rebirth requested over ncmd reuses the current bdseq , because the mqtt session has not changed aliases birth messages declare every metric with a name, a numeric alias, and a datatype data messages then carry only the alias and the value, omitting names and datatypes entirely; a null value is sent as the alias with the null flag set aliases come from stable identities — the device and tag ids for devicehub, the device and metric key for digital twins — so a metric keeps its alias across a rebirth, and a host application can keep resolving in flight data after a topology change they are assigned per process, so a restarted node reassigns them and host applications must re read them from each new nbirth rather than caching them across sessions devicehub devices and tags each devicehub device becomes one sparkplug device, and each of its tags becomes one metric on that device the node reads device and tag metadata from the litmus edge api to build birth certificates, then publishes values as they arrive the sparkplug device id is the devicehub device name, trimmed of surrounding whitespace; a device with no name falls back to its litmus edge device id that name is the last segment of the device's topics, so renaming a device in devicehub changes its topic and host applications see a new device metric group in dbirth contents tags/\<tag name> one metric per tag, with the tag's datatype, an alias, and a typed initial value device properties/… device metadata id, name, description, driver id, name, description, and version, device type id and name, creation timestamp, and tag count device control/rebirth boolean command metric a host application can write to request this device's birth certificate again tag metrics keep the tag name as configured in devicehub, so a tag named bearing temp publishes as tags/bearing temp tag metadata entries defined in devicehub travel with the metric as properties, named metadata \<key> with non alphanumeric characters in the key replaced by datatypes litmus edge tag types map to sparkplug datatypes as follows matching is case insensitive litmus edge value type sparkplug datatype bit , bit(int) , bin , bool , int(bit) boolean uint8 , byte , octal , left byte , right byte uint8 uint16 , word uint16 uint32 , dword , usint , uint uint32 uint64 , lword , ulint , udint , ulong uint64 int8 , sint , int16 , short , float , real , float32 , flt32 , fl float int , int32 , int64 , lint , long , dint , double , float64 , lreal , number , decimal double string , char , date , time , json , hex , raw , blob , counter , timer , and other text like types string a tag whose count property is greater than 1 publishes as the matching array type instead booleanarray , uint32array , uint64array , floatarray , doublearray , or stringarray a tag with a value type the node does not recognize is left out of the birth certificate, so it never appears in the host application a tag whose name contains no alphanumeric characters, or is not valid utf 8, is also skipped, with an error logged naming the tag values and lifecycle tag updates arrive from the litmus edge nats broker and publish as ddata on the device's topic, carrying the alias declared at birth and the value each update publishes as it arrives; the node adds no batching delay of its own the metric timestamp is the event time supplied by litmus edge, so history in your host application reflects when the value was read rather than when it was published the node also subscribes to litmus edge lifecycle events event reaction device enabled , device connected publish dbirth for that device device removed , device disabled , device disconnected , device start failed publish ddeath for that device device created , device updated , tags created , tags updated , tags removed refresh metadata and republish the birth set if the advertised metric set changed paired events are de duplicated, so a device that reports both disabled and disconnected produces one ddeath litmus edge sometimes emits an event before the api reflects the change, so the node re checks shortly afterwards, comparing the new topology against the old one and publishing nothing when nothing changed host applications do not reliably retire a metric that simply disappears from a later birth certificate so when a tag set shrinks, the node publishes ddeath for the affected device first, then a fresh nbirth and dbirth with the current tags, and no data for that device in between the result is a brief gap rather than a stale tag that keeps reporting good quality digital twins each enabled digital twin instance becomes one sparkplug device, and each of its dynamic attributes becomes one metric unlike a devicehub tag, a twin attribute has no inherent datatype, so the node decides every metric's datatype from the twin's model before any value flows — and never changes it because of a runtime sample flowchart lr model\[model, hierarchy, schema, source tags] > dbirth\[dbirth contract] runtime\[runtime payloads] > ddata\[ddata values only] dbirth > host\[host application] ddata > host the birth certificate declares the metric names, aliases, and datatypes; runtime payloads then supply values for metrics that already exist a field that appears in a payload but not in the contract is ignored, which keeps a host application's tag list stable an instance is published only when it is enabled and has a topic one whose contract compiles to no metrics at all is skipped, and counted by le sparkplug digital twin quarantine total metric group in dbirth contents attributes/… one metric per dynamic attribute, at its path in the model hierarchy device properties/digital twin/… model and instance diagnostics device control/rebirth boolean command metric to request this device's birth certificate again a twin's sparkplug device id is namespaced separately from devicehub device names, so a twin and a device can share a display name without colliding how each metric gets its datatype four sources are tried in order the first that yields a scalar type wins, and the winner is recorded on the metric as the typesource property order source typesource notes 1 the devicehub tag the attribute subscribes to devicehub the intended path the tag's value type decides the sparkplug datatype 2 the attribute's own datatype field declared author intent beats a sample derived schema array becomes stringarray 3 the instance's exported json schema schema sample derived numbers and integers both become double 4 fallback untyped the metric is registered as string untyped is the honest "not stated anywhere" result rather than a guess values serialize as text, nothing is dropped, and no datatype is inferred from a name or a unit metric properties birth metrics carry flat, scalar properties so an operator can tell where a metric came from without server side lookups reading declareddatatype=json together with typesource=untyped , for instance, names exactly which field to fix in the model property meaning attributeid , attributename the model attribute behind the metric engunit the attribute's unit, when the model declares one typesource which of the four sources above set the datatype declareddatatype the raw datatype token the author wrote topicexpression the attribute's subscription expression runtimevaluepath the field inside the runtime payload holding the value, when it is not value contenttype json for metrics whose runtime payload is an object transformationname , transformationtype the configured transformation, when there is one sourcedeviceid , sourcedevicename , sourcetagname , sourcevaluetype , and related the devicehub tag behind a devicehub typed metric runtime values situation result field present and convertible published as the contract's datatype field absent skipped, other metrics still publish field explicitly null published as null for that metric value cannot convert to the birth datatype that one metric is dropped, the rest of the batch publishes no metric in the batch converts nothing is published, and no sequence number is consumed compatible shapes are coerced rather than rejected "true" , 0 , and 1 all satisfy a boolean , and "12 5" satisfies a double a value that cannot convert is dropped rather than sent, because a mismatched datatype makes a host application reject the whole payload drops are counted by le sparkplug digital twin attribute value mismatch total , labelled with what was expected and what arrived metric timestamps use the value's own timestamp when the payload carries one, then the payload's top level timestamp, then publish time changes to a model the node polls litmus edge for twin changes every 10 seconds, stretching to 60 seconds while nothing changes and returning to 10 seconds as soon as something does instance lifecycle events trigger a refresh immediately when a contract changes — an attribute added, removed, retyped, or moved — the node publishes ddeath for that device and then a fresh birth certificate, so the host application rebuilds its tag list instead of holding a stale one a change in values alone publishes data only commands ncmd and dcmd the node subscribes for commands on every connect, at qos 1 spbv1 0/{group}/ncmd/{node} for the node, and spbv1 0/{group}/dcmd/{node}/# for any of its devices it accepts three command metrics, each taking effect when its boolean value is true command metric sent on effect node control/rebirth ncmd refreshes metadata and republishes the full birth set nbirth followed by every dbirth node control/next server ncmd ends the mqtt session and connects to the next broker in the list device control/rebirth dcmd republishes that one device's dbirth every nbirth declares the two node commands, and every dbirth declares the device command, so a host application discovers them from the birth set a command metric may be addressed by name or by the alias declared at birth rebirth is how a host application recovers when it has lost track of the node's metrics, after its own restart or an alias it cannot resolve the node refreshes devicehub and digital twin metadata first, then publishes the birth set as one unit, with data publishing closed for that window so nothing arrives referencing aliases the host has not read yet the session's bdseq does not change, because the mqtt session has not changed overlapping requests are suppressed rather than queued while a birth set is publishing, further requests are counted by le sparkplug rebirth suppressed total{reason="active"} and dropped, so a host application requesting rebirths in a tight loop cannot stall the node next server moves the node to the next broker in mqtt servers it publishes ndeath , disconnects, and connects to the next entry, starting a new session with the next bdseq with a single broker configured, it reconnects to that same broker any other command metric is ignored and counted by le sparkplug ncmd total{type="unknown"} , with the metric name and value logged at debug level a malformed metric — no name and no alias — is logged as an error and skipped because commands are counted as they arrive, those counters show whether the node received a command a host application believes it sent signed 8 bit and 16 bit integers publish as `float`, and `int32`, `int64`, and `dint` publish as `double` if your host application expects integer datatypes for those tags, expect floating point metrics instead a wave of `untyped` metrics on a new instance means its attributes carry no type signal fix it in the model editor bind the attribute to a devicehub tag, or set its `datatype` to a real scalar `le sparkplug digital twin attribute fallback total` counts these per attribute writing values back to devices is not supported `dcmd` handles `device control/rebirth` only — there is no path from a sparkplug command to a devicehub tag write