Manufacturing line simulator interfaced using PackML over MQTT.
PackML MQTT Simulator is a virtual line that interfaces using PackML implemented over MQTT. For use with the development of Industry 4.0 software solutions. The simulator implements the following PackML State model below and communicates over MQTT topics as defined by environmental variables. The simulator can run with either a basic MQTT topic structure or SparkPlugB.
The simulator supports the following topic and payload defintions:
To start and run the PackML simulation, you'll need an MQTT server running and accessible. Once available, the easiest approach is using docker to run the simulation using environmental variables to control the MQTT connection, Site, Area, and line.
Start your container with environmental variables.
$ docker run -it -e SITE=Site -e AREA=Area -e LINE=Line -e MQTT_URL=mqtt://broker.hivemq.com -m 30m ghcr.io/libremfg/packml-simulator
2020-06-22T03:13:49.301Z | info: Initializing
2020-06-22T03:13:49.817Z | info: Connected to mqtt://broker.hivemq.com:1883
2020-06-22T03:13:49.819Z | info: Site/Area/Line/Status/UnitModeCurrent : Production
Once up and running, use an MQTT client to publish to .../Command/Reset and .../Command/Start to get the simulated machine into the execute state. The default topic and payload is Custom as defined below.
$ docker run -it -e CLIENT_TYPE=sparkplugb -e SITE=Site -e AREA=Area -e LINE=Line -e MQTT_URL=mqtt://broker.hivemq.com -m 30m ghcr.io/libremfg/packml-simulator
2020-06-22T03:13:49.301Z | info: Initializing
2020-06-22T03:13:49.817Z | info: Connected to mqtt://broker.hivemq.com:1883
2020-06-22T03:13:49.819Z | info: Site/Area/Line/Status/UnitModeCurrent : Production
Once up and running, use an Sparkplug B device commands to publish to Command/Reset
and Command/Start
metrics to get the simulated machine into the execute state. The topic in the above example is: spBv1.0/Site/DCMD/Area/Line
.
$ npm i
...
added 421 packages from 213 contributors and audited 421 packages in 12.337s
found 0 vulnerabilities
$ export LINE=Line
$ node --max-old-space-size=20 ./src/index.js
2020-06-22T03:13:49.301Z | info: Initializing
2020-06-22T03:13:49.817Z | info: Connected to mqtt://broker.hivemq.com:1883
2020-06-22T03:13:49.819Z | info: Site/Area/Line/Status/UnitModeCurrent : Production
$ npm i
...
added 421 packages from 213 contributors and audited 421 packages in 12.337s
found 0 vulnerabilities
$ export LINE=Line
$ export CLIENT_TYPE=sparkplugb
$ node --max-old-space-size=20 ./src/index.js
2021-06-01T20:05:30.841Z | info: Initializing
2021-06-01T20:05:31.141Z | info: Connected to mqtt://broker.hivemq.com:1883
2021-06-01T20:05:31.142Z | info: Site/Area/Line/Status/UnitModeCurrentStr : Production
Please allow some time in between commands to enable the machine to get to the Idle state before issuing the Start command.
$ docker run --init -it --rm efrecon/mqtt-client pub -h broker.hivemq.com -u USERNAME -P PASSWORD -t "Site/Area/Line/Command/Reset" -m 1
$ docker run --init -it --rm efrecon/mqtt-client pub -h broker.hivemq.com -u USERNAME -P PASSWORD -t "Site/Area/Line/Command/Start" -m 1
The simulation consists of
- On Startup, the machine will automatically enter the Clearing and then Stopped state
- PackML UnitMode command and status
- PackML State Model with commands and status
- Machine Speed (ramping up/down and flicker)
- Setpoint Observed
- Status of current speed
- Machine Design Speed Respected
- Counters
- 1x Consumed
- 1x Produced
- 1x Defective
- Automatic machine suspension/unsuspension from Execute state
- Echo's command of Parameters, RemoteInterface, and Products back onto the status tags
The simulation uses probability dice rolls to determine actions.
Interface with the virtual line via the basic MQTT structure. The virtual line subscribes to <SITE>/<AREA>/<LINE>/Command/*
(see below) and publishes information to <SITE>/<AREA>/<LINE>/Status
and <SITE>/<AREA>/<LINE>/Admin
. <SITE>
, <AREA>
and <LINE>
are set using environmental variables.
Available Commands
Topic | Values | Function |
---|---|---|
<SITE>/<AREA>/<LINE>/Command/Clear |
1, 0 | Clear Command |
<SITE>/<AREA>/<LINE>/Command/Reset |
1, 0 | Reset Command |
<SITE>/<AREA>/<LINE>/Command/Start |
1, 0 | Start Command |
<SITE>/<AREA>/<LINE>/Command/Hold |
1, 0 | Hold Command |
<SITE>/<AREA>/<LINE>/Command/Unhold |
1, 0 | Unhold Command |
<SITE>/<AREA>/<LINE>/Command/Complete |
1, 0 | Complete Command |
<SITE>/<AREA>/<LINE>/Command/Stop |
1, 0 | Stop Command |
<SITE>/<AREA>/<LINE>/Command/Abort |
1, 0 | Abort Command |
<SITE>/<AREA>/<LINE>/Command/UnitMode |
String | Unit Mode Command (Production , Manual , Maintenance ) |
<SITE>/<AREA>/<LINE>/Command/MachSpeed |
Decimal | Machine Speed Command |
<SITE>/<AREA>/<LINE>/Command/Parameter/*n*/ID |
Integer | Parameter n ID |
<SITE>/<AREA>/<LINE>/Command/Parameter/*n*/Name |
String | Parameter n Name |
<SITE>/<AREA>/<LINE>/Command/Parameter/*n*/Unit |
String | Parameter n Unit |
<SITE>/<AREA>/<LINE>/Command/Parameter/*n*/Value |
Decimal | Parameter n Value |
<SITE>/<AREA>/<LINE>/Command/Product/*i*/ID |
Integer | Product n ID |
<SITE>/<AREA>/<LINE>/Command/Product/*i*/ProcessParameter/*j*/ID |
Integer | Product i Process Parameter j ID |
<SITE>/<AREA>/<LINE>/Command/Product/*i*/ProcessParameter/*j*/Name |
Integer | Product i Process Parameter j Name |
<SITE>/<AREA>/<LINE>/Command/Product/*i*/ProcessParameter/*j*/Unit |
Integer | Product i Process Parameter j Unit |
<SITE>/<AREA>/<LINE>/Command/Product/*i*/ProcessParameter/*j*/Value |
Integer | Product i Process Parameter j Value |
<SITE>/<AREA>/<LINE>/Command/Product/*i*/Ingredient/*j*/ID |
Integer | Product i Ingredient n ID |
<SITE>/<AREA>/<LINE>/Command/Product/*i*/Ingredient/*j*/Parameter/*k*/ID |
Integer | Product i Ingredient j Parameter k ID |
<SITE>/<AREA>/<LINE>/Command/Product/*i*/Ingredient/*j*/Parameter/*k*/Name |
Integer | Product i Ingredient j Parameter k Name |
<SITE>/<AREA>/<LINE>/Command/Product/*i*/Ingredient/*j*/Parameter/*k*/Unit |
Integer | Product i Ingredient j Parameter k Unit |
<SITE>/<AREA>/<LINE>/Command/Product/*i*/Ingredient/*j*/Parameter/*k*/Value |
Integer | Product i Ingredient j Parameter k Value |
Available Status'
Topic | Values | Function |
---|---|---|
<SITE>/<AREA>/<LINE>/Status/StateCurrent |
String | Current PackML State |
<SITE>/<AREA>/<LINE>/Status/StateCurrentStr |
Integer | Current PackML State as String |
<SITE>/<AREA>/<LINE>/Status/UnitMode |
Integer | Current PackML Model |
<SITE>/<AREA>/<LINE>/Status/UnitModeStr |
String | Current PackML Model as String |
<SITE>/<AREA>/<LINE>/Status/CurMachSpeed |
Decimal | Current Machine Speed |
<SITE>/<AREA>/<LINE>/Status/MachSpeed |
Decimal | Current Machine Speed Setpoint |
<SITE>/<AREA>/<LINE>/Status/Parameter/*n*/ID |
Integer | Parameter n ID |
<SITE>/<AREA>/<LINE>/Status/Parameter/*n*/Name |
String | Parameter n Name |
<SITE>/<AREA>/<LINE>/Status/Parameter/*n*/Unit |
String | Parameter n Unit |
<SITE>/<AREA>/<LINE>/Status/Parameter/*n*/Value |
Decimal | Parameter n Value |
<SITE>/<AREA>/<LINE>/Status/Product/*i*/ID |
Integer | Product n ID |
<SITE>/<AREA>/<LINE>/Status/Product/*i*/ProcessParameter/*j*/ID |
Integer | Product i Process Parameter j ID |
<SITE>/<AREA>/<LINE>/Status/Product/*i*/ProcessParameter/*j*/Name |
Integer | Product i Process Parameter j Name |
<SITE>/<AREA>/<LINE>/Status/Product/*i*/ProcessParameter/*j*/Unit |
Integer | Product i Process Parameter j Unit |
<SITE>/<AREA>/<LINE>/Status/Product/*i*/ProcessParameter/*j*/Value |
Integer | Product i Process Parameter j Value |
<SITE>/<AREA>/<LINE>/Status/Product/*i*/Ingredient/*j*/ID |
Integer | Product i Ingredient n ID |
<SITE>/<AREA>/<LINE>/Status/Product/*i*/Ingredient/*j*/Parameter/*k*/ID |
Integer | Product i Ingredient j Parameter k ID |
<SITE>/<AREA>/<LINE>/Status/Product/*i*/Ingredient/*j*/Parameter/*k*/Name |
Integer | Product i Ingredient j Parameter k Name |
<SITE>/<AREA>/<LINE>/Status/Product/*i*/Ingredient/*j*/Parameter/*k*/Unit |
Integer | Product i Ingredient j Parameter k Unit |
<SITE>/<AREA>/<LINE>/Status/Product/*i*/Ingredient/*j*/Parameter/*k*/Value |
Integer | Product i Ingredient j Parameter k Value |
Available Admin Status
Topic | Values | Function |
---|---|---|
<SITE>/<AREA>/<LINE>/Admin/MachDesignSpeed |
String | Current PackML State |
<SITE>/<AREA>/<LINE>/Admin/ProdConsumedCount/*i*/ID |
String | Consumed Counter ID |
<SITE>/<AREA>/<LINE>/Admin/ProdConsumedCount/*i*/Name |
String | Consumed Counter Name |
<SITE>/<AREA>/<LINE>/Admin/ProdConsumedCount/*i*/Unit |
String | Consumed Counter Units |
<SITE>/<AREA>/<LINE>/Admin/ProdConsumedCount/*i*/Count |
String | Consumed Counter Count since reset |
<SITE>/<AREA>/<LINE>/Admin/ProdConsumedCount/*i*/AccCount |
String | Consumed Counter Total Count |
<SITE>/<AREA>/<LINE>/Admin/ProdProcessedCount/*i*/ID |
String | Processed Counter ID |
<SITE>/<AREA>/<LINE>/Admin/ProdProcessedCount/*i*/Name |
String | Processed Counter Name |
<SITE>/<AREA>/<LINE>/Admin/ProdProcessedCount/*i*/Unit |
String | Processed Counter Units |
<SITE>/<AREA>/<LINE>/Admin/ProdProcessedCount/*i*/Count |
String | Processed Counter Count since reset |
<SITE>/<AREA>/<LINE>/Admin/ProdProcessedCount/*i*/AccCount |
String | Processed Counter Total Count |
<SITE>/<AREA>/<LINE>/Admin/ProdDefectiveCount/*i*/ID |
String | Defective Counter ID |
<SITE>/<AREA>/<LINE>/Admin/ProdDefectiveCount/*i*/Name |
String | Defective Counter Name |
<SITE>/<AREA>/<LINE>/Admin/ProdDefectiveCount/*i*/Unit |
String | Defective Counter Units |
<SITE>/<AREA>/<LINE>/Admin/ProdDefectiveCount/*i*/Count |
String | Defective Counter Count since reset |
<SITE>/<AREA>/<LINE>/Admin/ProdDefectiveCount/*i*/AccCount |
String | Defective Counter Total Count |
Refer to the Sparkplug B Payload and Topic Payload Definition Specification.
The simulator creates a device and listens to the device commands message (DCMD) topic with metrics representing the available commands without the <SITE>/<AREA>/<LINE>/
prefix. Consider the command topic <SITE>/<AREA>/<LINE>/Command/Reset
, when writing as a SparkplugB device command message use the metric name Command/Reset
. Publishing device command messages are published against spBv1.0/<SPARKPLUG_GROUP_ID>/DCMD/<SPARKPLUG_EDGE_NODE>/<LINE>
based on site environmental variables.
The simulator will also rebirth when requested at the node level by publishing to spBv1.0/<SPARKPLUG_GROUP_ID>/NCMD/<SPARKPLUG_EDGE_NODE>
with a metric Node Control/Rebirth
and a true value.
Below is an example of publishing to Igniition v8.1.5 SCADA with Cirrus Link Modules. The MQTT Engine was configured with the corresponding namespace filter for the simulation environmental variables.
The application is configured using the following environmental variables:
The ISA-95 Model site name of this line. SITE used as the parent topic in the MQTT structure. If this is unset, Site will be used.
The ISA-95 Model area name of this line. AREA used as the second topic in the MQTT structure. If this is unset, Area will be used.
The ISA-95 model line name of this line. LINE used as the third topic in the MQTT structure. If this is unset, hostname will be used.
The address of the MQTT server. If this is unset, mqtt://broker.hivemq.com will be used.
The port of the MQTT server. If left blank, the MQTT library will try and determine port based on protocol.
The name of the MQTT user with subscribe and publish permissions.
The password for the MQTT user with subscribe and publish permissions.
The client id to use when connecting to the broker. Defaults to hostname striped of special characters.
The topic and payload specification to use. Valid values are mqtt and sparkplugb. Default to mqtt.
For use with Sparkplug B specifcation. Defines the group_id. Default value is the SITE
environmental value or PackML Simluator if SITE
is not defined.
For use with Sparkplug B specifcation. Defines the edge_node_id. Default value is the AREA
environmental value or site_area_line if AREA
is not defined.
The tick speed of the simulation in milliseconds. This is optional. Default is 1000.
Use docker-compose to simulate multiple independent lines at once. E.g.
version: "2.4"
services:
greenville-packaging-line1:
image: ghcr.io/libremfg/packml-simulator
environment:
SITE: Greenville
AREA: Packaging
LINE: 'Line 1'
mem_limit: 30MB
greenville-packaging-line2:
image: ghcr.io/libremfg/packml-simulator
environment:
SITE: Greenville
AREA: Packaging
LINE: 'Line 2'
mem_limit: 30MB
greenville-cnc-line1:
image: ghcr.io/libremfg/packml-simulator
environment:
SITE: Greenville
AREA: CNC
LINE: 'Line 1'
CLIENT_TYPE: sparkplugb
mem_limit: 30MB
For any issue, there are fundamentally three ways an individual can contribute:
- By opening the issue for discussion: For instance, if you believe that you have uncovered a bug in, creating a new issue in the GitHub issue tracker is the way to report it.
- By helping to triage the issue: This can be done either by providing supporting details (a test case that demonstrates a bug), or providing suggestions on how to address the issue.
- By helping to resolve the issue: Typically, this is done either in the form of demonstrating that the issue reported is not a problem after all, or more often, by opening a Pull Request that changes some bit of something in the simulator in a concrete and reviewable manner.
-
2.0.6
- Fix host reference on shutdown
- Change to GitHub Container Registry
- Update CI/CD to build to GitHub Container Registry
- Bump Revision
-
2.0.5
- Bump Revision
- Change base docker image from node:12-alpine to node:20-alpine
- Change classes with single constructor to a function for maintainability
- Change multiple inline if statements to one per line for readabilty
- Change
var
toconst
orlet
where applicable - Refactor setInterval to reduce cognitive complexity
- Update docker metadata
- Update mqtt from 4.3.8 to 5.10.1
- Update winston from 3.13.0 to 3.15.0
- Update standard from 14.3.4 to 17.1.2
- Update sonarqube-scanner 2.9.1 to 4.2.3
- Update README
-
2.0.4
- Update README
- Update mqtt from 4.2.8 to 4.3.8
- Update sonarqube-scanner from 2.8.1 to 2.9.1
- Update sparkplug-client from 3.2.2 to 3.2.4
- Update winston from 3.3.3 to 3.13.0
- Bump Revision
-
2.0.3
- Update path-parse from 1.0.6 to 1.0.7
- Change README run command env. variable MQTT_HOST to MQTT_URL
- Bump Revision
-
2.0.2
- Update mqtt libary from 4.2.1 to 4.2.8
- Update sonarqube-scanner libary from 2.7.0 to 2.8.1
- Change simple switch statements for ifs
- Bump Revision
-
2.0.1
- Removed unsupported device commands
- Update Readme
- Bump Revision
-
2.0.0
- Add Sparkplug B Payload and Topic Support
- Add CLIENT_TYPE environmental variable
- Add SPARKPLUG_GROUP_ID environmental variable
- Add SPARKPLUG_EDGE_NODE environmental variable
- Add MQTT_CLIENT_ID environmental variable
- Add TICK to global configuration
- Add .../Status/StateCurrentStr topic for string name of state
- Add .../Status/UnitModeStr topic for string name of mode
- Changed topic payload for .../Status/StateCurrent to integer data type (use ../Status/StateCurrentStr` instead)
- Changed topic payload for .../Status/UnitMode to integer data type (use ../Status/UnitModeStr` instead)
- Change Command tags to boolean values (integer 0/1 still works)
- Fix UnitMode command
- Updated README
- Bump Revision
-
1.0.9
- Update lodash library from 4.17.19 to 4.17.21
- Update hosted-git-info from 2.8.8 to 2.8.9
-
1.0.8
- Add simulation TICK env variable
-
1.0.7
- Update ini library from 1.3.5 to 1.3.8
- Add docker container labels
-
1.0.6
- Update bl library to 1.2.3
-
1.0.5
- Add Helm chart to deploy to Kubernetes
-
1.0.4
- Add memory limits
- Changed default LINE to hostname
- Changed default clientId to MQTTv3.1.1 conforming hostname
-
1.0.3
- Add NODE_ENV=production to dockerfile
- Change CMD to use array for better SIGTERM handling
-
1.0.2
- Add an environmental variable for MQTT Port
- Fix typos
- Add logging of mqttClient errors
- Upgrade MQTT library to v4.2.1
- Upgrade winston library to v3.3.3
- Upgrade sonarqube-scanner library to v2.7.0
- Add port to connected message
- Update in code capitalization of PackML
-
1.0.1 Update docs
- Bump npm library versions
- Fix README subtitle markdown
- Fix image of state model
- Check for previous subscription before subscribe
- Fix docker-compose example
- Remove console.log
-
1.0.0. Initial Release