MQTT: Sparkplug Simulation

  1. Table of Contents
  2. Overview
  3. Prerequisites
  4. To run this simulation, you must have installed the following optional modules as documented in the online documentation:

  5. Usage
  6. Simplest

    You should be familiar with MQTT, how to run MQTT simulations as documented in our MQTT Get Started page.

    To run the Sparkplug simulation, for a configured MQTT agent with the Bosch sensor, invoke the Edit->Configure->MQTT->Config File... menu from the MIMICView GUI, and select the sparkplug/mqtt-sparkplug.cfg file.

    Start the agent using the Agent->Start menu item.

    You should see published telemetry according to the Sparkplug standard. From any subscriber, you should see binary payload under the spBv1.0/# topic hierarchy. If you don't configure anything else, the simulated EON node has one sensor behind it, with one metric with tag XDK/temp of value 0, eg. in our demo Sparkplug client:

    DEBUG 2020-07-08 11:05:51,349 (sparkplug-demo) - Device 20:19:AB:F4:2D:CF/sensor1 metric XDK/temp = 0
    

    Variable Store

    The simulation is mostly data-driven via Variable Store variables as detailed in the mqtt-sparkplug.cfg file.

    These are the store variables that control the Sparkplug simulation:

    # Sparkplug MQTT publisher action script
    #
    # Everything is data driven as documented in the action script
    # action_sparkplug.cc.
    #
    # Section numbers referenced (in []) in the specification at
    # 
    https://s3.amazonaws.com/cirrus-link-com/Sparkplug+Topic+Namespace+and+State+ManagementV2.1+Apendix++Payload+B+format.pdf
    
    #
    # This configuration simulates an edge of network (EON) node [3, 3.2],
    # or MQTT Enabled Device(Sparkplug) [3.4] for each agent.
    #
    # Currently, we simulate a configurable number of devices behind each EON
    # node [3, 3.3]. MIMIC cycles through each device in sequence per it's
    # configured message frequency (interval configurable).
    # The Sparkplug topic namespace is followed [6].
    #
    # A set of metrics can be defined per device of the name
    # DEVICE,METRIC,TYPE
    # where
    # DEVICE is the device name, eg. sensor1, or *, the wildcard
    # METRIC is the metric name of the form system/tag
    # system is some system name, eg. XDK
    # tag is some tag, eg. temp
    # TYPE is a Sparkplug data type, eg. INT32
    # The set of metrics is space separated.
    #
    # Each metric is published per device and its value is gotten from the
    # agent store variable "DEVICE,METRIC", where DEVICE is the device name,
    # METRIC is the metric name of the form "system/tag".
    # system is some system name, eg. XDK
    # tag is some tag, eg. temp
    # TYPE is a Sparkplug data type, eg. INT32
    # The set of metrics is space separated.
    #
    # Each metric is published per device and its value is gotten from the
    # agent store variable "DEVICE,METRIC", where DEVICE is the device name,
    # METRIC is the metric name of the form "system/tag".
    #
    # The EON goes through the Sparkplug state machine as detailed for
    # SPARKPLUG_STATE below [7].
    #
    # Relies on these agent store variables
    #
    # SPARKPLUG_EON        serial number of the EON, could be persistent
    #
    #                      if it is not set, this defaults to mimic-AGENTNO
    #
    # SPARKPLUG_STATE      current state of the EON, should be non-persistent,
    #                      one of
    #                      INITIAL initial state, next to send NBIRTH
    #                      NBIRTH  NBIRTH sent, next to send DBIRTH for each device
    #                      DBIRTH  DBIRTH sent, next to send DDATA for each device
    #                      END     end state, next to send DDEATH for each device
    #                      DDEATH  DDEATH sent, next to send NDEATH
    #                      DEAD    NDEATH sent, should disconnect from here
    #
    # SPARKPLUG_DEVICES    number of devices behind the EON node, could be persistent
    #                      if it is not set, this defaults to 1
    #                      The simulated EON will cycle through the devices
    #                      in sequence one each per update cycle.
    #                      Thus, the frequency of device messages is the
    #                      frequency per agent (EON) divided by number of devices.
    #
    # SPARKPLUG_NEXTDEV    iterates over the devices, should be non-persistent
    #                      indicates the next device number to publish, and
    #                      post-increments after publishing this message
    #
    # SPARKPLUG_METRICS    the set of metrics for each device of the form
    #                      DEVICE,system/tag,TYPE[,optional-property,property-value]
    #                      as detailed above.
    #                      These metrics will be sent in DBIRTH and DDATA messages.
    #
    # SPARKPLUG_METRICS_MASK        defines the subset of the metrics to be
    #                      sent in this interval for the current device.
    #                      This is expected to be a small subset of the total set.
    #                      If this is not defined (default), all metrics are sent.
    #                      If set, only the specified metrics are sent in the
    #                      order specified for the current device.
    #                      This value is cleared after the metrics are sent.
    #                      The best way to set the value is to append to it.
    #                      Should be non-persistent.
    #                      This is meant to work only on "sporadic" messages,
    #                      ie. under the control of
    #                      mimic agent protocol msg MQTT client message set ... count ...
    #                      else there could be empty payloads sent in PUBLISH.
    #
    # SPARKPLUG_TEMPLATES  the set of templates for each device of the form
    #                      DEVICE,template-name,parameter-name,parameter-value
    #                      to add a single template with single parameter and
    #                      the first 2 metrics above.
    #
    # SPARKPLUG_DATASETS   the set of datasets for each device of the form
    #                      DEVICE,columns,colkey1,TYPE1,colkey2,TYPE2,...,rows
    #                      to add a single dataset with given columns and rows
    #
    # SPARKPLUG_FUDGE      make the metrics unpredictable by specified +/- value
    #
    # Global store variables:
    #
    # SPARKPLUG_DEBUG      turns debugging on or off. Only detected once.
    #                      if it is not set, defaults to off
    #
    # SPARKPLUG_UUID       UUID [15.1.1]
    #                      if it is not set, defaults to MyUUID
    #
    # SPARKPLUG_GROUP_ID   group_id [6.1.1]
    #
    # SPARKPLUG_SENSOR_NAME        global sensor name
    #                      it defines the edge_node_id in [6.1]
    #                      if it is not set, defaults to sensor1
    #                      the device name is then "sensor"+AGENTNO
    #                      Can be overriden per agent (EON).
    #
    # SPARKPLUG_METRICS    the global set of metrics by default of the form
    #                      system/tag,TYPE
    #                      for all devices as above. Is overridden per device.
    

    To see more detailed payload you'll need a Sparkplug-compliant subscriber client as detailed below.

    Values

    You can then build on this, by defining the variables via the Agent -> Variable Store... dialog for that agent. If you open that dialog for that selected device, then you will see the default values filled in, eg.:

    SPARKPLUG_DEVICES = 1
    SPARKPLUG_EON = the serial number of the device
    etc.
    

    If you want to have a value for XDK/temp, then you would define a variable, by selecting the agent node in that dialog, then press Add..., eg.

    XDK/temp = 10000
    

    gives in our client

    DEBUG 2020-07-08 11:16:05,483 (sparkplug-demo) - Device 20:19:AB:F4:2D:CF/sensor1 metric XDK/temp = 10000
    

    Scaling

    If you want to scale to more, say 10, sensors behind the EON, you would double-click on SPARKPLUG_DEVICES and change

    SPARKPLUG_DEVICES = 10
    

    which will define sensors sensor11 to sensor110 (sensor1 is the default sensor type name, and the sensor number just gets appended), which you can override with the global store variable SPARKPLUG_SENSOR_NAME in Edit -> Variable Store..., eg.

    SPARKPLUG_SENSOR_NAME = mysensor
    

    If you wanted other metrics, then you would add to the default, eg.

    SPARKPLUG_METRICS = *,XDK/temp,INT32
    

    for the single metric to be sent with tag XDK/temp of type INT32.

    Sample Lab

    We ship a sample lab configuration sparkplug-sample.cfg that configures a couple of EON nodes with different cases. To try it:

    • load it with File -> Open in MIMICview; You'll see 5 agents, with annotations (if you have the Annotations patch loaded from Update Wizard, else the ANNOTATION variable has the annotation to explain what it does). In order to use these, you need to:

    • set the IP address of the agent from 10.0.0.x to whatever address you want to use, eg. the native Ip address of your system. Use Edit -> Configure -> General -> IP Address...;

    • set the MQTT broker to your broker with Edit -> Configure -> MQTT -> Broker If you don't do this, you will get an error in the log window.

    • save the agent configuration with File -> Save or File -> Save As.

    • Now if you start the second agent, it has the 10 sensors, and you can control the temperature.

    • The first agent tests all types of the Sparkplug spec.

    • The third agent has datasets;

    • The fourth has templates.

    • The fifth agent has 100 sensors configured with it. If you use the copy/paste feature of MIMIC with the Edit -> Copy and Edit -> Paste menu items, and add 9 more sensors, eg. agents 6 through 14, then start them, you'll have a total of 10 EONs and 1000 sensors. You can then make one of them have a temperature higher than a threshold that you are monitoring with an application, eg. our open-source Sparkplug demo then you have 1000 sensors, one of which is behaving badly, and you have detected it.

    Online cloud-based SaaS Lab

    The Sparkplug simulation is the basis of our on-demand cloud-based MQTT Lab.

  7. Compatibility
  8. We have interoperated with

    • the Induction Automation Ignition platform. This shows the tags generated by the first 2 agents in the lab configuration sparkplug-sample.cfg:

      This assumes you have configured the MQTT Engine module in Ignition to subscribe to messages from a MQTT broker as detailed in this video from Induction Automation. You need to configure that broker for the simulated devices, just as you would for real devices.

      You can see more short videos in our Ignition Simulator Youtube playlist.

    • a NODE-RED based client, and

    • our open-source Python-based Sparkplug demo client. Eg.

      % ./sparkplug-thresh.py --host mqtt.eclipse.org -v
      DEBUG 2020-07-16 13:25:55,150 (sparkplug-thresh) - NBIRTH --> EON GAM01 online
      DEBUG 2020-07-16 13:25:56,152 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25heartbeat = 123.0
      DEBUG 2020-07-16 13:25:56,152 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25heartbeat
      DEBUG 2020-07-16 13:25:56,152 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25setptp = 123.0
      DEBUG 2020-07-16 13:25:56,152 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25setptp
      DEBUG 2020-07-16 13:25:56,152 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25discp = 123.0
      DEBUG 2020-07-16 13:25:56,152 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25discp
      DEBUG 2020-07-16 13:25:56,152 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25casep = 123.0
      DEBUG 2020-07-16 13:25:56,152 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25casep
      DEBUG 2020-07-16 13:25:56,152 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25j10suctp = 123.0
      DEBUG 2020-07-16 13:25:56,152 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25j10suctp
      DEBUG 2020-07-16 13:25:56,153 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25dra = 50.0
      DEBUG 2020-07-16 13:25:56,153 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25dra
      DEBUG 2020-07-16 13:25:56,153 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25draflo = 123.0
      DEBUG 2020-07-16 13:25:56,153 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25draflo
      DEBUG 2020-07-16 13:25:56,153 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25drasetpt = 123.0
      DEBUG 2020-07-16 13:25:56,153 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25drasetpt
      DEBUG 2020-07-16 13:25:56,153 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25tkdra = 123.0
      DEBUG 2020-07-16 13:25:56,153 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25tkdra
      DEBUG 2020-07-16 13:25:56,153 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25vfdspeed = 123.0
      DEBUG 2020-07-16 13:25:56,153 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25vfdspeed
      DEBUG 2020-07-16 13:25:56,153 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25vfdamps = 123.0
      DEBUG 2020-07-16 13:25:56,153 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25vfdamps
      DEBUG 2020-07-16 13:25:56,153 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25vfdcurrent = 123.0
      DEBUG 2020-07-16 13:25:56,153 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25vfdcurrent
      DEBUG 2020-07-16 13:25:56,153 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25vfdvolts = 123.0
      DEBUG 2020-07-16 13:25:56,154 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25vfdvolts
      DEBUG 2020-07-16 13:25:56,154 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25vfdhp = 123.0
      DEBUG 2020-07-16 13:25:56,154 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25vfdhp
      DEBUG 2020-07-16 13:25:56,154 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25vfdpower = 123.0
      DEBUG 2020-07-16 13:25:56,154 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25vfdpower
      DEBUG 2020-07-16 13:25:56,154 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25vfdinvolts = 123.0
      DEBUG 2020-07-16 13:25:56,154 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25vfdinvolts
      DEBUG 2020-07-16 13:25:56,154 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25vfdinamps = 123.0
      DEBUG 2020-07-16 13:25:56,154 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25vfdinamps
      DEBUG 2020-07-16 13:25:56,154 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25vfdcspeed = 123.0
      DEBUG 2020-07-16 13:25:56,154 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25vfdcspeed
      DEBUG 2020-07-16 13:25:56,154 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25u1strtimr = 123.0
      DEBUG 2020-07-16 13:25:56,154 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25u1strtimr
      DEBUG 2020-07-16 13:25:56,154 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25u2strtimr = 123.0
      DEBUG 2020-07-16 13:25:56,155 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25u2strtimr
      DEBUG 2020-07-16 13:25:56,155 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25u1vibib = 123.0
      DEBUG 2020-07-16 13:25:56,155 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25u1vibib
      DEBUG 2020-07-16 13:25:56,155 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25u2vibob = 123.0
      DEBUG 2020-07-16 13:25:56,155 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25u2vibob
      DEBUG 2020-07-16 13:25:56,155 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25plcpwrf = True
      DEBUG 2020-07-16 13:25:56,155 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25plcpwrf
      DEBUG 2020-07-16 13:25:56,155 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25plcfault = True
      DEBUG 2020-07-16 13:25:56,155 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25plcfault
      DEBUG 2020-07-16 13:25:56,155 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25moderemacc = True
      DEBUG 2020-07-16 13:25:56,155 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25moderemacc
      DEBUG 2020-07-16 13:25:56,155 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25rack1comm = True
      DEBUG 2020-07-16 13:25:56,155 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25rack1comm
      DEBUG 2020-07-16 13:25:56,155 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25rack2comm = True
      DEBUG 2020-07-16 13:25:56,156 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25rack2comm
      DEBUG 2020-07-16 13:25:56,156 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25rack3comm = True
      DEBUG 2020-07-16 13:25:56,156 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25rack3comm
      DEBUG 2020-07-16 13:25:56,156 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25siteman = True
      DEBUG 2020-07-16 13:25:56,156 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25siteman
      DEBUG 2020-07-16 13:25:56,156 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25hismp = True
      DEBUG 2020-07-16 13:25:56,156 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25hismp
      DEBUG 2020-07-16 13:25:56,156 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25maxsmp = True
      DEBUG 2020-07-16 13:25:56,156 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25maxsmp
      DEBUG 2020-07-16 13:25:56,156 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25ows = True
      DEBUG 2020-07-16 13:25:56,156 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25ows
      DEBUG 2020-07-16 13:25:56,156 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25hiupstrp = True
      DEBUG 2020-07-16 13:25:56,156 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25hiupstrp
      DEBUG 2020-07-16 13:25:56,156 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25charger = True
      DEBUG 2020-07-16 13:25:56,156 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25charger
      DEBUG 2020-07-16 13:25:56,157 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25lobat = True
      DEBUG 2020-07-16 13:25:56,157 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25lobat
      DEBUG 2020-07-16 13:25:56,157 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25dcinvrtrf = True
      DEBUG 2020-07-16 13:25:56,157 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25dcinvrtrf
      DEBUG 2020-07-16 13:25:56,157 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25pwrf = True
      DEBUG 2020-07-16 13:25:56,157 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25pwrf
      DEBUG 2020-07-16 13:25:56,157 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25mbtrip = True
      DEBUG 2020-07-16 13:25:56,157 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25mbtrip
      DEBUG 2020-07-16 13:25:56,157 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25loopcl = True
      DEBUG 2020-07-16 13:25:56,157 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25loopcl
      DEBUG 2020-07-16 13:25:56,157 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25gpelowp = True
      DEBUG 2020-07-16 13:25:56,157 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25gpelowp
      DEBUG 2020-07-16 13:25:56,157 (sparkplug-thresh) - DBIRTH --> Device GAM01/GAM01_test_PLC metric gam25cvpct = True
      DEBUG 2020-07-16 13:25:56,157 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25cvpct
      DEBUG 2020-07-16 13:26:59,493 (sparkplug-thresh) - DDATA --> Device GAM01/GAM01_test_PLC metric gam25dra = 100.0
      DEBUG 2020-07-16 13:26:59,493 (sparkplug-thresh) - Device GAM01/GAM01_test_PLC ignored metric gam25dra