MISC-TN-026: Automated test equipment (ATE) monitoring with SBCSPG gateway, ThingsBoard IoT, and Fledge

From DAVE Developer's Wiki
Revision as of 15:29, 21 September 2023 by U0001 (talk | contribs) (Introduction)

(diff) ← Older revision | Approved revision (diff) | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
Info Box
SBCSPG-1.jpg Applies to SBCSPG
Cloud-computing-banner.jpg Applies to IoT
Warning-icon.png This technical note was validated against specific versions of hardware and software. It may not work with other versions. Warning-icon.png


History[edit | edit source]

Version Date Notes
1.0.0 February 2023 First public release

Introduction[edit | edit source]

In essence, this Technical Note (TN) is very similar to MISC-TN-024: Automated test equipment (ATE) monitoring with SBCSPG gateway and ThingsBoard IoT platform. There is a noticeable difference, however, as a different software stack was used on the edge device. In this case, Fledge was utilized.

Testbed[edit | edit source]

The edge device is the SBCSPG gateway running Debian Bullseye. To deploy this distribution onto the target, the same approach described here was used. Unlike Orca SBC, SBCSPG is based on a 32-bit ARM Cortex-A7 processor, though. As such, a different image was used.

To install Fledge, the apt-based approach described here was followed. It is worth to remember that some dependencies were handled manually. For instance, autoconf and libtool packages were installed manually.

Enabling the connection to the PLC[edit | edit source]

As described in MISC-TN-024, the PLC we want to talk to is connected to a different subnet, namely 192.168.30.0/24. For testing the connection to the PLC, after adding the required subnet configuration, the modbus command line tool was used, which is provided by the modbus_cli package. In the following example, the register mapped ad the address 300 is read.

root@sbcspg:/usr/local/fledge/python/fledge/plugins/north# ip addr add 192.168.30.253/24 dev eth0 label eth0:1

armbian@sbcspg:~/devel/fledge$ pip install modbus_cli
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: modbus_cli in /home/armbian/.local/lib/python3.9/site-packages (0.1.8)
Requirement already satisfied: colorama in /home/armbian/.local/lib/python3.9/site-packages (from modbus_cli) (0.4.6)
Requirement already satisfied: umodbus in /home/armbian/.local/lib/python3.9/site-packages (from modbus_cli) (1.0.4)
Requirement already satisfied: pyserial~=3.4 in /usr/local/lib/python3.9/dist-packages (from umodbus->modbus_cli) (3.5)

[notice] A new release of pip is available: 23.0 -> 23.0.1
[notice] To update, run: python3 -m pip install --upgrade pip
...
armbian@sbcspg:~$ ./.local/bin/modbus 192.168.30.42:502 300
Parsed 0 registers definitions from 1 files
300: 32 0x20

We then configured Fledge in order to read periodically a couple of PLC's registers. Please note that this is a no-code operation as it is carried out with the help of the native web-based Fledge UI. To access PLC exposed data, the Fledge's modbustcp South plugin was used. Please note that also we had to patch it manually to solve a bug that prevented it from working properly. The patch is detailed here. To make the change effective, we disabled and re-enabled the plugin via the web interface.

Installing the modbustcp South plugin.
Configuring the plugin
Configuring the plugin.
The plugin is enabled.
Fledge provides a native web interface to visualize collected data.


Enabling the connection to ThingsBoard IoT platform[edit | edit source]

In order to upload collected data to ThingsBoard platform, a simple North plugin was developed. To this end, the Microsoft Azure plugin was used as reference. The ThingsBoard North plugin is minimalist and unfit for a real-world production environment. Nevertheless, it was enough to perform the basic tests described in this document. Before testing this new plugin, the mosquitto-clients package was installed as the plugin invokes the mosquitto_pub command line tool.

root@sbcspg:/usr/local/fledge/python/fledge/plugins/north# apt install mosquitto mosquitto-clients
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  libcjson1 libdlt2 libev4 libmosquitto1 libwebsockets16
Suggested packages:
  apparmor
The following NEW packages will be installed:
  libcjson1 libdlt2 libev4 libmosquitto1 libwebsockets16 mosquitto mosquitto-clients
0 upgraded, 7 newly installed, 0 to remove and 8 not upgraded.
Need to get 715 kB of archives.
After this operation, 1,492 kB of additional disk space will be used.
Do you want to continue? [Y/n] 
Get:1 http://deb.debian.org/debian bullseye/main armhf libcjson1 armhf 1.7.14-1 [20.5 kB]
Get:2 http://deb.debian.org/debian bullseye/main armhf libdlt2 armhf 2.18.6-1+deb11u1 [46.1 kB]
Get:3 http://deb.debian.org/debian bullseye/main armhf libev4 armhf 1:4.33-1 [38.6 kB]
Get:4 http://deb.debian.org/debian bullseye/main armhf libmosquitto1 armhf 2.0.11-1 [83.5 kB]
Get:5 http://deb.debian.org/debian bullseye/main armhf libwebsockets16 armhf 4.0.20-2 [163 kB]
Get:6 http://deb.debian.org/debian bullseye/main armhf mosquitto armhf 2.0.11-1 [253 kB]
Get:7 http://deb.debian.org/debian bullseye/main armhf mosquitto-clients armhf 2.0.11-1 [110 kB]
Fetched 715 kB in 0s (1,817 kB/s)      
Selecting previously unselected package libcjson1:armhf.
(Reading database ... 72206 files and directories currently installed.)
Preparing to unpack .../0-libcjson1_1.7.14-1_armhf.deb ...
Unpacking libcjson1:armhf (1.7.14-1) ...
Selecting previously unselected package libdlt2:armhf.
Preparing to unpack .../1-libdlt2_2.18.6-1+deb11u1_armhf.deb ...
Unpacking libdlt2:armhf (2.18.6-1+deb11u1) ...
Selecting previously unselected package libev4:armhf.
Preparing to unpack .../2-libev4_1%3a4.33-1_armhf.deb ...
Unpacking libev4:armhf (1:4.33-1) ...
Selecting previously unselected package libmosquitto1:armhf.
Preparing to unpack .../3-libmosquitto1_2.0.11-1_armhf.deb ...
Unpacking libmosquitto1:armhf (2.0.11-1) ...
Selecting previously unselected package libwebsockets16:armhf.
Preparing to unpack .../4-libwebsockets16_4.0.20-2_armhf.deb ...
Unpacking libwebsockets16:armhf (4.0.20-2) ...
Selecting previously unselected package mosquitto.
Preparing to unpack .../5-mosquitto_2.0.11-1_armhf.deb ...
Unpacking mosquitto (2.0.11-1) ...
Selecting previously unselected package mosquitto-clients.
Preparing to unpack .../6-mosquitto-clients_2.0.11-1_armhf.deb ...
Unpacking mosquitto-clients (2.0.11-1) ...
Setting up libmosquitto1:armhf (2.0.11-1) ...
Setting up libev4:armhf (1:4.33-1) ...
Setting up libcjson1:armhf (1.7.14-1) ...
Setting up mosquitto-clients (2.0.11-1) ...
Setting up libdlt2:armhf (2.18.6-1+deb11u1) ...
Setting up libwebsockets16:armhf (4.0.20-2) ...
Setting up mosquitto (2.0.11-1) ...
Created symlink /etc/systemd/system/multi-user.target.wants/mosquitto.service → /lib/systemd/system/mosquitto.service.
Processing triggers for libc-bin (2.31-13+deb11u5) ...

The following box shows the code of the ThingsBoard plugin.

# -*- coding: utf-8 -*-

""" ThingsBoard North plugin"""
import asyncio
import time
import json
import sys
import os



from fledge.common import logger
from fledge.plugins.north.common.common import *

__author__ = "Andrea Marson"
__copyright__ = "Copyright (c) 2023 DAVE Srl"
__license__ = "Apache 2.0"
__version__ = "${VERSION}"

_LOGGER = logger.setup(__name__)

_CONFIG_CATEGORY_NAME = "THINGSBOARD"
_CONFIG_CATEGORY_DESCRIPTION = "ThingsBoard Python North Plugin"

_DEFAULT_CONFIG = {
    'plugin': {
         'description': 'ThingsBoard North Plugin',
         'type': 'string',
         'default': 'thingsboard',
         'readonly': 'true'
    },
    "tb_iot_platform_host": {
            "description": "ThingsBoard IoT platform host.",
            "type": "string",
            "default": "put the public name of your host here",
            "order": "2",
            "displayName": "ThingsBoard IoT platform host"
    },
    "tb_mqtt_topic": {
            "description": "MQTT topic",
            "type": "string",
            "default": "v1/devices/me/telemetry",
            "order": "3",
            "displayName": "MQTT topic",
            'readonly': 'true'
    },
    "tb_device_access_token": {
            "description": "Device's access token.",
            "type": "string",
            "default": "put your device's token here",
            "order": "4",
            "displayName": "Device's access token"
    },
    "source": {
            "description": "Source of data to be sent on the stream.",
            "type": "enumeration",
            "default": "readings",
            "options": ["readings"],
            "order": "5",
            "displayName": "Source",
            'readonly': 'true'
    }
}

def plugin_info():
    return {
        'name': 'thingsboard',
        'version': '2.1.0',
        'type': 'north',
        'interface': '1.0',
        'config': _DEFAULT_CONFIG
    }

def plugin_init(data):
    _LOGGER.info('Initializing ThingsBoard North Python Plugin')
    global thingsboard_north, config
    thingsboard_north = ThingsBoardNorthPlugin()
    config = data
    _LOGGER.info(f'config = {config}')
    return config

"""
Example of payload

[{'reading': {'base_joint_temperature_deg_C': 34, 'base_joint_current_mA': 2042}, 'asset_code': 'Modbus TCP', 'id': 35613, 'ts': '2023-02-22 16:33:49.961000+00:00', 'user_ts': '2023-02-22 16:33:47.126849+00:00'}, {'reading': {'base_joint_temperature_deg_C': 34, 'base_joint_current_mA': 2045}, 'asset_code': 'Modbus TCP', 'id': 35614, 'ts': '2023-02-22 16:33:49.961000+00:00', 'user_ts': '2023-02-22 16:33:48.126817+00:00'}, {'reading': {'base_joint_temperature_deg_C': 34, 'base_joint_current_mA': 2060}, 'asset_code': 'Modbus TCP', 'id': 35615, 'ts': '2023-02-22 16:33:49.961000+00:00', 'user_ts': '2023-02-22 16:33:49.126827+00:00'}]

Example of upload

mosquitto_pub -d -q 1 -h "$THINGSBOARD_HOST_NAME" -t "v1/devices/me/telemetry" -u "$ACCESS_TOKEN" -m '{"base_joint_temperature_deg_C":33}'
"""
async def plugin_send(data, payload, stream_id):
    try:
        _LOGGER.info(f'ThingsBoard North Python - plugin_send: {stream_id}')
        _LOGGER.info(f'data = {data}')
        _LOGGER.info(f'payload = {payload}')
        _LOGGER.info(f'host = {data["tb_iot_platform_host"]["value"]}')
        for reading in payload:
            _LOGGER.info(f'reading = {reading}')
            _LOGGER.info(f'reading[reading] = {reading["reading"]}')
            s = 'mosquitto_pub -d -q 1 -h "' + data["tb_iot_platform_host"]["value"] + '" -t "' + data["tb_mqtt_topic"]["value"] + '" -u "' + data["tb_device_access_token"]["value"] + '" -m \'' + str(reading["reading"]) + "\'"
            _LOGGER.info(f's = {s}')
            os.system(s)
    except asyncio.CancelledError as ex:
        _LOGGER.exception(f'Exception occurred in plugin_send: {ex}')
    else:
        _LOGGER.info('payload sent successfully')
        return True, payload[len(payload-1)]["id"], len(payload)

def plugin_shutdown(data):
    pass

# TODO: North plugin can not be reconfigured? (per callback mechanism)
def plugin_reconfigure():
    pass

class ThingsBoardNorthPlugin(object):
    """ North ThingsBoard Plugin """

Visualization of uploaded data[edit | edit source]

Similarly to what we did in MISC-TN-024, we created a simple dashboard to visualize in real-time on cloud side collected data as shown in the following example.

Visualization of uploaded data.