12 minute read
All events or subsequent changes in production are transmitted via MQTT in the following data model. This ensures that all participants are always informed about the latest status.
The data model in the MQTT Broker can be divided into four levels. In general, the higher the level, the lower the data frequency and the more the data is prepared.
If you do not know the idea of MQTT (important keywords: “broker”, “subscribe”, “publish”, “topic”), we recommend reading the wikipedia article first.
All MQTT messages consist out of one JSON with at least two elements in it:
Key | Data type/format | Description |
---|---|---|
timestamp_ms | int | the amount of milliseconds since the 1970-01-01 (also called UNIX timestamp in milliseconds) |
<valueName> | int, str, dict | a value that can be int, str, or even in dict format |
{
"timestamp_ms": 1588879689394,
"valueName": "str"
}
{
"timestamp_ms": 1588879689394,
"valueName": 24
}
{
"timestamp_ms": 1588879689394,
"valueName": {
"key1": "some text",
"key2": 12
}
}
Data from this level are all raw data, which are not yet contextualized(i.e., assigned to a machine). These are, in particular, all data from sensorconnect and cameraconnect.
Topic structure: `ia/raw/.+'
All raw data coming in via sensorconnect.
Topic: ia/raw/2020-0102/0000005898845/X01
This means that the transmitter with the serial number 2020-0102
has one ifm gateway connected to it with the serial number 0000005898845
. This gateway has the sensor connected to the first port X01
.
{
"timestamp_ms": ..., // int
"type": "IO-Link", // in case of IO-Link
"connected": 1, // 1 if connected
"<value1Name>": <convertedValue1>, //for example: "distance": 16,
"<value2Name>": <convertedValue2>,
...
"<valueNName>": <convertedValueN>
}
If the device is not known from one of the IODD-XML files, the received valueString is directly written into the JSON message:
{
"timestamp_ms": ...,
"type": "IO-Link", //in case of IO-Link
"connected": 1, // 1 in case of connected
"value_string": <unconvertedValue>
}
If the connection can not be established:
{
"timestamp_ms": ...,
"type": "IO-Link", //in case of IO-Link
"connected": 0, // 0 in case of not connected, also no value included in JSON
}
Topic structure: ia/rawImage/<TransmitterID>/<MAC Adress of Camera>
All raw data coming in via cameraconnect.
key | data type | description |
---|---|---|
image_id | str | a unique identifier for every image acquired (e.g. format:<MACaddress>_<timestamp_ms> ) |
image_bytes | str | base64 encoded image in JPG format in bytes |
image_height | int | height of the image in pixel |
image_width | int | width of the image in pixel |
image_channels | int | amount of included color channels (Mono: 1, RGB: 3) |
Topic: ia/rawImage/2020-0102/4646548
This means that the transmitter with the serial number 2020-0102 has one camera connected to it with the serial number 4646548.
{
"timestamp_ms": 214423040823,
"image": {
"image_id": "<MACaddress>_<timestamp_ms>",
"image_bytes": "3495ask484...",
"image_height": 800,
"image_width": 1203,
"image_channels": 3
}
}
im_bytes = base64.b64decode(incoming_mqtt_message["image"]["image_bytes"])
im_arr = np.frombuffer(im_bytes, dtype=np.uint8) # im_arr is a one-dimensional Numpy array
img = cv2.imdecode(im_arr, flags=cv2.IMREAD_COLOR)
cv2.imwrite(image_path, img)
In this level the data is already assigned to a machine.
Topic structure: ia/<customerID>/<location>/<AssetID>/<Measurement>
e.g. ia/dccaachen/aachen/demonstrator/count
.
An asset can be a step, machine, plant or line. It uniquely identifies the smallest location necessary for modeling the process.
By definition all topic names should be lower case only!
Topic: ia/<customerID>/<location>/<AssetID>/count
Here a message is sent every time something has been counted. This can be, for example, a good product or scrap.
count
in the JSON is an integer.
scrap
in the JSON is an integer, which is optional. It means scrap
pieces of count
are scrap. If not specified it is 0 (all produced goods are good).
key | data type | description |
---|---|---|
count | int | quantity of produced item |
{
"timestamp_ms": 1588879689394,
"count": 1
}
Topic: ia/<customerID>/<location>/<AssetID>/scrapCount
Here a message is sent every time products should be marked as scrap. It works as follows:
A message with scrap
and timestamp_ms
is sent. It starts with the count that is directly before timestamp_ms
. It is now iterated step by step back in time and step by step the existing counts are set to scrap until a total of scrap
products have been scraped.
scrap
, e.g. the count is 5 but only 2 more need to be scrapped, it will scrap exactly 2. Currently it would ignore these 2. see also #125scrap
in the JSON is an integer.
key | data type | description |
---|---|---|
scrap | int | Number of item from count that is considered as scrap . When scrap is equal to 0, that means all produced goods are good quality |
{
"timestamp_ms": 1588879689394,
"scrap": 1
}
Topic: ia/<customerID>/<location>/<AssetID>/barcode
key | data type | description |
---|---|---|
barcode | str | A message is sent here each time the barcode scanner connected to the transmitter via USB reads a barcode via barcodescanner |
{
"timestamp_ms": 1588879689394,
"barcode": "16699"
}
Topic: ia/<customerID>/<location>/<AssetID>/activity
key | data type | description |
---|---|---|
activity | bool | A message is sent here every time the machine runs or stops (independent whether it runs slow or fast, or which reason the stop has. This is covered in state) |
{
"timestamp_ms": 1588879689394,
"activity": True
}
Topic: ia/<customerID>/<location>/<AssetID>/detectedAnomaly
key | data type | description |
---|---|---|
detectedAnomaly | str | A message is sent here each time a stop reason has been identified automatically or by input from the machine operator (independent whether it runs slow or fast, or which reason the stop has. This is covered in state) |
{
"timestamp_ms": 1588879689394,
"detectedAnomaly": "maintenance"
}
Topic: ia/<customerID>/<location>/<AssetID>/addShift
key | data type | description |
---|---|---|
timestamp_ms_end | int | A message is sent here each time a new shift is started. The value represents a UNIX timestamp in milliseconds |
{
"timestamp_ms": 1588879689394,
"timestamp_ms_end": 1588879689395
}
Topic: ia/<customerID>/<location>/<AssetID>/addOrder
A message is sent here each time a new order is started.
key | data type | description |
---|---|---|
product_id | str | Represents the current product name |
order_id | str | Represents the current order name |
target_units | int | Represents the amount of target units to be produced (in the same unit as count) |
{
"product_id": "Beierlinger 30x15",
"order_id": "HA16/4889",
"target_units": 1
}
Topic: ia/<customerID>/<location>/<AssetID>/addProduct
A message is sent here each time a new product is added.
key | data type | description |
---|---|---|
product_id | str | Represents the current product name |
time_per_unit_in_seconds | float | Specifies the target time per unit in seconds |
{
"product_id": "Beierlinger 30x15",
"time_per_unit_in_seconds": 0.2
}
Topic: ia/<customerID>/<location>/<AssetID>/startOrder
A message is sent here each time a new order is started.
key | data type | description |
---|---|---|
order_id | str | Represents the order name |
{
"timestamp_ms": 1588879689394,
"order_id": "HA16/4889",
}
Topic: ia/<customerID>/<location>/<AssetID>/endOrder
A message is sent here each time a new order is started.
key | data type | description |
---|---|---|
order_id | str | Represents the order name |
{
"timestamp_ms": 1588879689394,
"order_id": "HA16/4889",
}
Topic: ia/<customerID>/<location>/<AssetID>/processValue
A message is sent here every time a process value has been prepared. Unique naming of the key.
key | data type | description |
---|---|---|
<valueName> | int or float | Represents a process value, e.g. temperature. |
<valueName>
is a integer or float, booleans like “true” or “false” are not possible. Please convert them to integer, e.g., “True” –> 1, “False” –> 0{
"timestamp_ms": 1588879689394,
"energyConsumption": 123456
}
Topic structure: ia/<customer>/<location>/<assetID>/productImage
/productImage
has the same data format as ia/rawImage
, only with a changed topic.
/productImage
can be acquired in two ways, either from ia/rawImage
or /rawImageClassification
. In the case of /rawImageClassification
,
only the Image part is extracted to /productImage
, while the classification information is stored in the relational database.
key | data type | description |
---|---|---|
image_id | str | a unique identifier for every image acquired (e.g. format:<MACaddress>_<timestamp_ms> ) |
image_bytes | str | base64 encoded image in JPG format in bytes |
image_height | int | height of the image in pixel |
image_width | int | width of the image in pixel |
image_channels | int | amount of included color channels (Mono: 1, RGB: 3) |
{
"timestamp_ms": 214423040823,
"image": {
"image_id": "<SerialNumberCamera>_<timestamp_ms>",
"image_bytes": "3495ask484...",
"image_heigth": 800,
"image_width": 1203,
"image_channels": 3
}
}
Topic structure: ia/<customer>/<location>/<assetID>/productTag
/productTag
is usually generated by contextualizing a processValue to a product.
key | data type | description |
---|---|---|
AID | str | lorem ipsum |
name | str | lorem ipsum |
value | int | lorem ipsum |
{
"timestamp_ms": 215348452385,
"AID": "14432504350",
"name": "torque",
"value": 2.12
}
See also Digital Shadow for more information how to use this message
Topic structure: ia/<customer>/<location>/<assetID>/productTagString
/productTagString
is usually generated by contextualizing a processValue to a product.
key | data type | description |
---|---|---|
AID | str | lorem ipsum |
name | str | lorem ipsum |
value | str | lorem ipsum |
{
"timestamp_ms": 1243204549,
"AID": "32493855304",
"name": "QualityClass",
"value": "Quality2483"
}
See also Digital Shadow for more information how to use this message
Topic structure: ia/<customer>/<location>/<assetID>/addParentToChild
/productTagString
is usually generated whenever a product is transformed into another product. It can be used multiple times for the same child to model that one product can consists out of multiple parents.
key | data type | description |
---|---|---|
childAID | str | The AID of the child |
parentAID | str | The AID of the parent |
{
"timestamp_ms": 124387,
"childAID": "23948723489",
"parentAID": "4329875"
}
See also Digital Shadow for more information how to use this message
This level contains only highly aggregated production data.
Topic: ia/<customerID>/<location>/<AssetID>/state
A message is sent here each time the asset changes status. Subsequent changes are not possible. Different statuses can also be process steps, such as “setup”, “post-processing”, etc. You can find a list of all supported states here
key | data type | description |
---|---|---|
state | int | Value of state according to this datamodel |
{
"timestamp_ms": 1588879689394,
"state": 10000
}
Topic: ia/<customerID>/<location>/<AssetID>/cycleTimeTrigger
A message should be sent under this topic whenever an assembly cycle is started.
currentStation
in the JSON is a string
lastStation
in the JSON is a string
sanityTime_in_s
in the JSON is a integer
key | data type | description |
---|---|---|
currentStation | str | |
lastStation | str | |
sanityTime_in_s | int |
{
"timestamp_ms": 1611170736684,
"currentStation": "1a",
"lastStation": "1b",
"sanityTime_in_s": 100
}
Topic: ia/<customerID>/<location>/<AssetID>/uniqueProduct
A message is sent here each time a product has been produced or modified. A modification can take place, for example, due to a downstream quality control.
There are two cases of when to send a message under the uniqueProduct
topic:
uniqueProduct
topic.key | data type | description |
---|---|---|
begin_timestamp_ms | int | Start time |
end_timestamp_ms | int | Completion time |
product_id | str | The product ID that is currently produced |
isScrap | bool | Information whether the current product is of poor quality and will be sorted out. Default value (if not specified otherwise) is false |
uniqeProductAlternativeID | str | lorem ipsum |
{
"begin_timestamp_ms": 1611171012717,
"end_timestamp_ms": 1611171016443,
"product_id": "test123",
"is_scrap": false,
"uniqueProductAlternativeID": "12493857-a"
}
See also Digital Shadow for more information how to use this message
Topic: ia/<customerID>/<location>/<AssetID>/scrapUniqueProduct
A message is sent here each time a unique product has been scrapped.
key | data type | description |
---|---|---|
UID | str | Unique ID of the current single product |
{
"UID": "161117101271788647991611171016443"
}
Topic: ia/<customerID>/<location>/<AssetID>/recommendations
Shopfloor insights are recommendations for action that require concrete and rapid action in order to quickly eliminate efficiency losses on the store floor.
key | data type/format | description |
---|---|---|
recommendationUID | int | Unique ID of the recommendation. Used to subsequently deactivate a recommendation (e.g. if it has become obsolete) |
recommendationType | int | The ID / category of the current recommendation. Used to narrow down the group of people |
recommendationValues | dict | Values used to form the actual recommendation set |
{
"timestamp_ms": 1588879689394,
"recommendationUID": 3556,
"recommendationType": 8996,
"enabled": True,
"recommendationValues":
{
"percentage1": 30,
"percentage2": 40
}
}
There are various different IDs that you can find in the MQTT messages. This section is designed to give an overview.
Name | data type/format | description |
---|---|---|
product_id | int | The type of product that should be produced in an order for a specific asset. Can be used to retrieve the target speed. |
order_id | int | Order ID, which provides the type of product (see product_id ) and the amount of pieces that should be produced. |
uniqeProductAlternativeID | int | In short: AID. Used to describe a single product of the type product_id in the order order_id . This is the ID that might be written on the product (e.g., with a physical label, lasered, etc.) and is usually the relevant ID for engineers and for production planning. It usually stays the same. |
UID | int | Short for unique product ID. Compared to the AID the UID changes whenever a product changes its state. Therefore, a product will change its UID everytime it is placed on a new asset. It is used mainly on the database side to lookup a specific product in a specific state. |
These IDs are linked together in the database.
Here is a scheme of the timescaleDB structure:
(open the image using the right click for a better resolution)