Summary
-
-
- Installation
- How to create a test certificate
- How to connect a cloud end-point
- How to send MQTT messages
- How to test the cloud connection?
- How to configure the local mqtt bind address and port
- How to trouble shoot device monitoring
- How to add self-signed certificate root to trusted certificates list?
- How to retrieve JWT token from Cumulocity?
- How to install and enable software management?
- How to connect an external device?
- How to access the logs on the device?
- How to install thin-edge.io on any Linux OS (no deb support)?
- How to restart your thin-edge.io device
- How to use apama software management plugin
- How to change temp path
- How to use thin-edge.io with your preferred init system
- How to monitor health of tedge daemons
- How to enable systemd watchdog monitoring for tedge services?
- How to add custom fragments to Cumulocity
- How to retrieve logs with the log plugin
- How to use Cumulocity Custom SmartREST 2.0 Templates with
thin-edge.io
- How to manage configuration files with Cumulocity
- How to install thin-edge manually with openrc
Overview
Why thin-edge.io
An open-source & cloud-agnostic IoT framework designed for resource-constrained Edge devices.
- Simple and secure device connectivity.
- Freedom of cloud platform.
- Freedom of programming language.
How to start
- The very first step is to install
thin-edge.io
and to connect your device to your IoT cloud, either Cumulocity IoT or Azure IoT (10 minutes). - You will then be able to send telemetry data to the cloud using a cloud-agnostic message format (5 minutes).
- The next step is to write your own telemetry component, using your preferred programming language, say Rust or Python.
Grow your skills
- Explore the tutorials and use-cases.
- Understand the architecture.
- Use the how-to guides on a daily basis.
- Refer to the reference guides for any in-depth details.
User Documentation
This part of the documentation is meant for users, that want to use thin-edge.io with the feature set that is provided. If you want to develop something on top of thin-edge.io, head over to the Developer Documentation. Even if you do not yet plan to develop for thin-edge.io some of the contents there might be of interest to you to get a deeper technical understanding.
Tutorials
- Connect my device to Cumulocity IoT
- Connect my device to Azure IoT
- Send Thin Edge Json data
- Monitor my device
- Manage my device software
Connect your device to Cumulocity IoT
The very first step to enable thin-edge.io
is to connect your device to the cloud.
- This is a 10 minutes operation to be done only once.
- It establishes a permanent connection from your device to the cloud end-point.
- This connection is secure (encrypted over TLS), and the two peers are identified by x509 certificates.
- Sending data to the cloud will then be as simple as sending data locally.
The focus is here on connecting to Cumulocity IoT. See this tutorial, if you want to connect Azure IoT instead.
Before you try to connect your device to Cumulocity IoT, you need:
- The url of the endpoint to connect (e.g.
eu-latest.cumulocity.com
). - Your credentials to connect Cumulocity:
- Your tenant identifier (e.g.
t00000007
), a user name and password. - None of these credentials will be stored on the device.
- These are only required once, to register the device.
- Your tenant identifier (e.g.
If not done yet, install thin-edge.io
on your device.
You can now use the tedge
command to:
- create a certificate for you device,
- make the device certificate trusted by Cumulocity,
- connect the device, and
- send your first telemetry data.
Configure the device
To connect the device to the Cumulocity IoT, one needs to set the URL of your Cumulocity IoT tenant and the root certificate as below.
Set the URL of your Cumulocity IoT tenant.
$ sudo tedge config set c8y.url your-tenant.cumulocity.com
Set the path to the root certificate if necessary. The default is /etc/ssl/certs
.
$ sudo tedge config set c8y.root.cert.path /etc/ssl/certs
This will set the root certificate path of the Cumulocity IoT. In most of the Linux flavors, the certificate will be present in /etc/ssl/certs. If not found download it from here.
Connecting to Cumulocity server signed with self-signed certificate
If the Cumulocity IoT instance that you're connecting to, is signed with a self-signed certificate(eg: Cumulocity IoT Edge instance), then the path to that server certificate must be set as the c8y.root.cert.path as follows:
$ sudo tedge config set c8y.root.cert.path /path/to/the/self-signed/certificate
Note: This is the certificate chain of the server and not the device's certificate kept at /etc/tedge/device-certs directory.
If the Cumulocity server's certificate chain file isn't available locally, it can be downloaded using a web browser or using some other third-party tools like openssl command as follows (to be adjusted based on your env):
openssl s_client -connect <hostname>:<port> < /dev/null 2>/dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'
Create the certificate
The tedge cert create
command creates a self-signed certificate which can be used for testing purpose.
A single argument is required: an identifier for the device. This identifier will be used to uniquely identify your devices among others in your cloud tenant. This identifier will be also used as the Common Name (CN) of the certificate. Indeed, this certificate aims to authenticate that this device is actually the device with that identity.
$ sudo tedge cert create --device-id my-device
You can then check the content of that certificate.
$ sudo tedge cert show
Device certificate: /etc/tedge/device-certs/tedge-certificate.pem
Subject: CN=my-device, O=Thin Edge, OU=Test Device
Issuer: CN=my-device, O=Thin Edge, OU=Test Device
Valid from: Tue, 09 Feb 2021 17:16:52 +0000
Valid up to: Tue, 11 May 2021 17:16:52 +0000
Thumbprint: CDBF4EC17AA02829CAC4E4C86ABB82B0FE423D3E
You may notice that the issuer of this certificate is the device itself.
This is a self-signed certificate.
To use a certificate signed by your Certificate Authority,
see the reference guide of tedge cert
.
Make the device trusted by Cumulocity
For a certificate to be trusted by Cumulocity, one needs to add the certificate of the signing authority to the list of trusted certificates. In the Cumulocity GUI, navigate to "Device Management/Management/Trusted certificates" in order to see this list for your Cumulocity tenant.
Here, the device certificate is self-signed and has to be directly trusted by Certificate. This can be done:
- either with the GUI: upload the certificate from your device (
/etc/tedge/device-certs/tedge-certificate.pem
) to your tenant "Device Management/Management/Trusted certificates". - or using the
tedge cert upload c8y
command.
$ sudo tedge cert upload c8y --user <username>
To upload the certificate to cumulocity this user needs to have "Tenant management" admin rights. If you get an error 503 here, check the appropriate rights in cumulocity user management.
Connect the device
Now, you are ready to run tedge connect c8y
.
This command configures the MQTT broker:
- to establish a permanent and secure connection to the cloud,
- to forward local messages to the cloud and vice versa.
Also, if you have installed tedge_mapper
, this command starts and enables the tedge-mapper-c8y systemd service.
At last, it sends packets to Cumulocity to check the connection.
If your device is not yet registered, you will find the digital-twin created in your tenant after tedge connect c8y
!
$ sudo tedge connect c8y
Checking if systemd is available.
Checking if configuration for requested bridge already exists.
Validating the bridge certificates.
Creating the device in Cumulocity cloud.
Saving configuration for requested bridge.
Restarting mosquitto service.
Awaiting mosquitto to start. This may take up to 5 seconds.
Enabling mosquitto service on reboots.
Successfully created bridge connection!
Sending packets to check connection. This may take up to 2 seconds.
Connection check is successful.
Checking if tedge-mapper is installed.
Starting tedge-mapper-c8y service.
Persisting tedge-mapper-c8y on reboot.
tedge-mapper-c8y service successfully started and enabled!
Enabling software management.
Checking if tedge-agent is installed.
Starting tedge-agent service.
Persisting tedge-agent on reboot.
tedge-agent service successfully started and enabled!
Sending your first telemetry data
Sending data to Cumulocity is done using MQTT over topics prefixed with c8y
.
Any messages sent to one of these topics will be forwarded to Cumulocity.
The messages are expected to have a format specific to each topic.
Here, we use tedge mqtt pub
a raw Cumulocity SmartRest message to be understood as a temperature of 20 Celsius.
$ tedge mqtt pub c8y/s/us 211,20
To check that this message has been received by Cumulocity, navigate to "Device Management/Devices/All devices/<your device id>/Measurements". You should observe a "temperature measurement" graph with the new data point.
Next Steps
You can now:
- learn how to send various kind of telemetry data using the cloud-agnostic Thin-Edge-Json data format,
- or have a detailed view of the topics mapped to and from Cumulocity if you prefer to use directly Cumulocity specific formats and protocols.
- learn how to add custom fragments to cumulocity.
Connect your device to Azure IoT
The very first step to enable thin-edge.io is to connect your device to the cloud.
- This is a 10 minutes operation to be done only once.
- It establishes a permanent connection from your device to the cloud end-point.
- This connection is secure (encrypted over TLS), and the two peers are identified by x509 certificates.
- Sending data to the cloud will then be as simple as sending data locally.
The focus is here on connecting the device to Azure IoT. See this tutorial, if you want to connect Cumulocity IoT instead.
Before you try to connect your device to Azure IoT, you need:
- Create a Azure IoT Hub in Azure portal as described here.
- Install
thin-edge.io
on your device.
You can now use tedge
command to:
- create a certificate for your device,
- register the device on Azure IoT Hub,
- configure the device,
- connect the device, and
- send your first telemetry data.
Create the certificate
The tedge cert create
command creates a self-signed certificate which can be used for testing purpose.
A single argument is required: an identifier for the device. This identifier will be used to uniquely identify your devices among others in your cloud tenant. This identifier will be also used as the Common Name (CN) of the certificate. Indeed, this certificate aims to authenticate that this device is the device with that identity.
$ sudo tedge cert create --device-id my-device
Show certificate details
You can then check the content of that certificate.
$ sudo tedge cert show
Device certificate: /etc/tedge/device-certs/tedge-certificate.pem
Subject: CN=my-device, O=Thin Edge, OU=Test Device
Issuer: CN=my-device, O=Thin Edge, OU=Test Device
Valid from: Tue, 09 Mar 2021 14:10:30 +0000
Valid up to: Thu, 10 Mar 2022 14:10:30 +0000
Thumbprint: 860218AD0A996004449521E2713C28F67B5EA580
You may notice that the issuer of this certificate is the device itself.
This is a self-signed certificate.
The Thumbprint is the Sha1sum of the certificate. This is required for registering the
device using the self-signed certificate on Azure IoT Hub.
To use a certificate signed by your Certificate Authority,
see the reference guide of tedge cert
.
Register the device on Azure IoT Hub
For a device to be trusted by Azure, one needs to add the self-signed certificate thumbprint to the Azure IoT Hub Portal. In the Azure IoT Hub Portal, navigate to "Explores"->"IoT Devices" click on "+ New", this will open a new blade "Create a device".
Here provide the configuration parameters that are required to create the device as described below.
- Device ID: Should be the same as the Subject of the certificate.
- Authentication type: Select X.509 Self-Signed option.
- Provide the Primary Thumbprint that was displayed in
tedge cert show
. - Use the same for the Secondary Thumbprint as well (Since we are using a single certificate).
- Provide the Primary Thumbprint that was displayed in
- Set "Connect this device to an IoT Hub" to Enable.
- Then save the configuration. Upon successfully saved the configuration a new device has been created on the IoT Hub. The new device can be seen on the IoT Hub portal by navigating to "Explores"->"IoT Devices".
More info about registering a device can be found here
Configure the device
To connect the device to the Azure IoT Hub, one needs to set the URL/Hostname of the IoT Hub and the root certificate of the IoT Hub as below.
Set the URL/Hostname of your Azure IoT Hub.
sudo tedge config set az.url your-iot-hub-name.azure-devices.net
The URL/Hostname can be found in the Azure web portal, clicking on the overview section of your IoT Hub.
Set the path to the root certificate if necessary. The default is /etc/ssl/certs
.
sudo tedge config set az.root.cert.path /etc/ssl/certs/Baltimore_CyberTrust_Root.pem
This will set the root certificate path of the Azure IoT Hub. In most of the Linux flavors, the certificate will be present in /etc/ssl/certs. If not found download it from here.
Connect the device
Now, you are ready to get your device connected to Azure IoT Hub with tedge connect az
.
This command configures the MQTT broker:
- to establish a permanent and secure connection to the Azure cloud,
- to forward local messages to the cloud and vice versa.
Also, if you have installed tedge_mapper
, this command starts and enables the tedge-mapper-az systemd service.
At last, it sends packets to Azure IoT Hub to check the connection.
$ sudo tedge connect az
Checking if systemd is available.
Checking if configuration for requested bridge already exists.
Validating the bridge certificates.
Saving configuration for requested bridge.
Restarting mosquitto service.
Awaiting mosquitto to start. This may take up to 5 seconds.
Enabling mosquitto service on reboots.
Successfully created bridge connection!
Sending packets to check connection. This may take up to 2 seconds.
Connection check is successful.
Checking if tedge-mapper is installed.
Starting tedge-mapper-az service.
Persisting tedge-mapper-az on reboot.
tedge-mapper-az service successfully started and enabled!
Sending your first telemetry data
Sending data to Azure is done using MQTT over topics prefixed with az
.
Any messages sent on the topic will be forwarded to Azure.
Here, we use tedge mqtt pub az/messages/events/
a message to be understood as a temperature of 20 Degree.
$ tedge mqtt pub az/messages/events/ '{"temperature": 20}'
To view the messages that were sent from the device to the cloud, follow this document.
More info about sending telemetry to Azure can be found here
Next Steps
You can now:
- learn how to send various kind of telemetry data using the cloud-agnostic Thin-Edge-Json data format,
- or have a detailed view of the topics mapped to and from Azure if you prefer to use directly Azure specific formats and protocols.
Send Thin Edge JSON data
Once your Thin Edge device is configured and connected to an IoT cloud provider, you can start sending measurements. Refer to Connecting to Cumulocity or tutorials for other cloud providers to learn how to connect your Thin Edge device to an IoT cloud provider.
In this tutorial, we'll see how different kinds of measurements are represented in Thin Edge JSON format and how they can be sent to the connected cloud provider. For a more detailed specification of this data format, refer to Thin Edge JSON Specification.
Sending measurements
A simple single-valued measurement like a temperature measurement, can be represented in Thin Edge JSON as follows:
{ "temperature": 25 }
with the key-value pair representing the measurement type and the numeric value of the measurement.
This measurement can be sent from the Thin Edge device to the cloud by publishing this message to the tedge/measurements
MQTT topic.
Processes running on the Thin Edge device can publish messages to the local MQTT broker using any MQTT client or library.
In this tutorial, we'll be using the tedge mqtt pub
command line utility for demonstration purposes.
The temperature measurement described above can be sent using the tedge mqtt pub
command as follows:
$ tedge mqtt pub tedge/measurements '{ "temperature": 25 }'
The first argument to the tedge mqtt pub
command is the topic to which the measurements must be published to.
The second argument is the Thin Edge JSON representation of the measurement itself.
When connected to a cloud provider, a message mapper component for that cloud provider would be running as a daemon,
listening to any measurements published to tedge/measurements
.
The mapper, on receipt of these Thin Edge JSON measurements, will map those measurements to their equivalent
cloud provider native representation and send it to that cloud.
For example, when the device is connected to Cumulocity, the Cumulocity mapper component will be performing these actions.
To check if these measurements have reached Cumulocity, login to your Cumulocity dashboard and navigate to
Device Management => Devices => All devices =>
Complex measurements
You can represent measurements that are far more complex than the single-valued ones described above using the Thin Edge JSON format.
A multi-valued measurement like three_phase_current
that consists of L1
, L2
and L3
values,
representing the current on each phase can be represented as follows:
{
"three_phase_current": {
"L1": 9.5,
"L2": 10.3,
"L3": 8.8
}
}
Here is another complex message consisting of single-valued measurements: temperature
and pressure
along with a multi-valued coordinate
measurement, all sharing a single timestamp captured as time
.
{
"time": "2020-10-15T05:30:47+00:00",
"temperature": 25,
"current": {
"L1": 9.5,
"L2": 10.3,
"L3": 8.8
},
"pressure": 98
}
The time
field is not a regular measurement like temperature
or pressure
but a special reserved field.
Refer to Thin Edge JSON Specification for more details on the kinds of telemetry
data that can be represented in Thin Edge JSON format and the reserved fields like time
used in the above example.
Sending measurements to child devices
Note: Currently this feature supports Cumulocity IoT only.
If valid Thin Edge JSON measurements are published to the tedge/measurements/<child-id>
topic,
the measurements are recorded under a child device of your thin-edge.io device.
Given your desired child device ID is child1
, publish a Thin Edge JSON message to the tedge/measurements/child1
topic:
$ tedge mqtt pub tedge/measurements/child1 '{ "temperature": 25 }'
Then, you will see a child device with the name child1
is created in your Cumulocity IoT tenant,
and the measurement is recorded in Measurements
of the child1
device.
Error detection
If the data published to the tedge/measurements
topic are not valid Thin Edge JSON measurements, those won't be
sent to the cloud but instead you'll get a feedback on the tedge/errors
topic, if you subscribe to it.
The error messages published to this topic will be highly verbose and may change in the future.
So, use it only for debugging purposes during the development phase and it should not be used for any automation.
You can use the tedge mqtt sub
command to subscribe to the error topic as follows:
$ tedge mqtt sub tedge/errors
Thin Edge Alarm
Alarms on thin-edge.io can be used to create alerts, represent state changes etc. For example, an alarm can be raised when a certain measurement value breaches some threshold (like high temperature) or when an unexpected event occurs in the system (like a sensor failure).
A typical alarm cycle starts by the raising of an alarm by some monitoring process which alerts a system/human of an event needing some action. Once some action is taken, the alarm is cleared explicitly by that system/human.
Every alarm is uniquely identified by its type and severity. That is, for a given alarm type, alarms of varying severities are treated as independent alarms and hence, must be acted upon separately. For an alarm of a given type and severity, only the last known state is considered relevant. Thin-edge.io doesn't keep a history of all its state changes but only reacts to the last one it receives.
Raising an alarm
An alarm can be raised on thin-edge.io by sending an MQTT message in Thin Edge JSON format to certain MQTT topics.
The scheme of the topic to publish the alarm data is as follows:
tedge/alarms/<severity>/<alarm-type>
The payload format must be as follows:
{
"text": "<alarm text>",
"time": "<Timestamp in ISO-8601 format>"
}
Note: These messages must be sent with MQTT retained flag enabled and with QOS > 1 to ensure guaranteed processing by thin-edge.io. Enabling the retained flag ensures that the alarm stays persisted with the MQTT broker until its state changes again. These retained messages will make sure that the thin-edge.io processes or any other third-party processes subscribed to these alarms will get those, even if they were down at the moment the alarm was raised. If multiple messages are sent to the same alarm topic, the last alarm is considered to have overwritten the previous one.
Here is a sample alarm raised for temperature_high
alarm type with critical
severity:
Topic:
tedge/alarms/critical/temperature_high
Payload:
{
"text": "Temperature is very high",
"time": "2021-01-01T05:30:45+00:00"
}
Note: Both the
text
field and thetime
field are optional. When atext
is not provided, it is assumed to be empty. Whentime
is not provided, thin-edge.io will use the current system time as thetime
of the alarm. When you want to skip both fields, use an empty json fragment{}
as the payload to indicate the same. An empty message can't be used for the same, as empty messages are used to clear alarms, which is discussed in the next section.
The <severity>
value in the MQTT topic can only be one of the following values:
- critical
- major
- minor
- warning
There are no such restrictions on the <alarm-type>
value.
Thin-edge.io doesn't keep any history of all alarms raised on an alarm topic.
Clearing alarms
An already raised alarm can be cleared by sending an empty message with retained flag enabled to the same alarm topic on which the original alarm was raised.
Note: Using the retained flag is a must while clearing the alarm as well, without which the alarm won't be cleared properly.
If alarms of different severities exist for a given alarm type, they must all be cleared separately as they're all treated as independent alarms.
Cloud data mapping
If the device is connected to some supported IoT cloud platform, any alarms raised locally on thin-edge.io will be forwarded to the connected cloud platform as well. The mapping of thin-edge alarms data to its respective cloud-native representation will be done by the corresponding cloud mapper process. For example, if the device is connected to Cumulocity IoT cloud platform, the Cumulocity cloud mapper process will translate the thin-edge alarm JSON data to its equivalent Cumulocity SmartREST representation.
Warning: As of now, alarm data mapping is supported only on Cumulocity IoT cloud platform.
Cumulocity cloud data mapping
The Cumulocity mapper will convert Thin Edge JSON alarm into Cumulocity SmartREST messages and send it to Cumulocity via MQTT.
For example the temperature_high
alarm with critical
severity described in the earlier sections will be converted to the following Cumulocity SmartREST message:
301,temperature_high,"Temperature is very high",2021-01-01T05:30:45+00:00
... and is published to c8y/s/us
topic which will get forwarded to the connected Cumulocity cloud instance.
Find more information about SmartREST representations for alarms in Cumulocity here
Find more information about alarms data model in Cumulocity here
Thin Edge Event
Events on thin-edge.io can be used to trigger signals when some event happens in the system. For example, a person entering a room or someone logging into a machine/website can all be represented as events. Events are stateless and hence are processed as and when they occur. They don't represent state but can be used to represent state changes. An event can't be updated/cleared once its triggered, unlike alarms that are cleared explicitly after processing.
Every event is uniquely identified by its type. If multiple events are raised for a given type, thin-edge.io will process them all separately in the order in which they were raised.
Sending an event
An event can be triggered on thin-edge.io by sending an MQTT message in Thin Edge JSON format to certain MQTT topics.
The scheme of the topic to publish the event data is as follows:
tedge/events/<event-type>
The payload format must be as follows:
{
"text": "<event text>",
"time": "<Timestamp in ISO-8601 format>"
}
Here is a sample event triggered for a login_event
event type:
Topic:
tedge/events/login_event
Payload:
{
"text": "A user just logged in",
"time": "2021-01-01T05:30:45+00:00"
}
Note: Both the
text
field and thetime
field are optional.
When the message
field is not provided, the event-type
from the MQTT topic will be used as the message as well if the connected cloud mandates one.
When the time
field is not provided, thin-edge.io will use the current system time as the time
of the event.
When you want to skip both fields, use an empty payload to indicate the same.
There are no such restrictions on the <event-type>
value.
Cloud data mapping
If the device is connected to some supported IoT cloud platform, an event that is triggered locally on thin-edge.io will be forwarded to the connected cloud platform as well. The mapping of thin-edge events data to its respective cloud-native representation will be done by the corresponding cloud mapper process. For example, if the device is connected to Cumulocity IoT cloud platform, the Cumulocity cloud mapper process will translate the thin-edge event JSON data to its equivalent Cumulocity SmartREST representation.
Warning: As of now, event data mapping is supported only on Cumulocity IoT cloud platform.
Cumulocity cloud data mapping
The Cumulocity mapper will convert Thin Edge JSON events into its Cumulocity SmartREST equivalent if the payload only contains either a text
field or time
field.
For example the login_event
described in the earlier sections will be converted to the following Cumulocity SmartREST message:
400,login_event,"A user just logged in",2021-01-01T05:30:45+00:00
... and is published to c8y/s/us
topic which will get forwarded to the connected Cumulocity cloud instance.
If the event JSON payload contains fields other than text
and time
, or when the payload size is more than 16K irrespective of its contents, it will be converted to Cumulocity JSON format.
The Cumulocity JSON mapping of the same event would be as follows:
{
"type":"login_event",
"text":"A user just logged in",
"time":"2021-01-01T05:30:45+00:00",
"source": {
"id":"<c8y-device-id>"
}
}
Note: Mapped events will be sent to Cumulocity via MQTT if the incoming Thin Edge JSON event payload size is less than 16K bytes. If higher, HTTP will be used.
Find more information about events data model in Cumulocity here.
Monitor your device with collectd
With thin-edge.io device monitoring, you can collect metrics from your device and forward these device metrics to IoT platforms in the cloud.
Using these metrics, you can monitor the health of devices and can proactively initiate actions in case the device seems to malfunction. Additionally, the metrics can be used to help the customer troubleshoot when problems with the device are reported.
Thin-edge.io uses the open source component collectd
to collect the metrics from the device.
Thin-edge.io translates the collected metrics from their native format to the thin-edge.io JSON format
and then into the cloud-vendor specific format.
Enabling monitoring on your device is a 3-steps process:
Install mosquitto
client library
Since thin-edge.io uses the MQTT plugin of collectd
, one needs to install the mosquitto client library
(either libmosquitto1
or mosquitto-clients
).
sudo apt-get install libmosquitto1
or
sudo apt-get install mosquitto-clients
Install collectd
Device monitoring is not enabled by default when you install thin edge.
You will have to install and configure collectd
first.
To install collectd, follow the collectd installation process that is specific to your device. On a Debian or Ubuntu linux:
sudo apt-get install collectd-core
Configure collectd
TLDR; Just want it running
Thin-edge.io provides a basic collectd
configuration
that can be used to collect cpu, memory and disk metrics.
Simply copy that file to the main collectd configuration file and restart the daemon (it might be good to keep a copy of the original configuration).
sudo cp /etc/collectd/collectd.conf /etc/collectd/collectd.conf.backup
sudo cp /etc/tedge/contrib/collectd/collectd.conf /etc/collectd/collectd.conf
sudo systemctl restart collectd
Collectd.conf
Unless you opted for the minimal test configuration provided with thin-edge,
you will have to update the
collectd.conf
configuration file
(usually located at /etc/collectd/collectd.conf
)
Important notes You can enable or disable the collectd plugins of your choice, but with some notable exceptions:
- MQTT must be enabled.
- Thin-edge.io expects the collectd metrics to be published on the local MQTT bus. Hence, you must enable the MQTT write plugin of collectd.
- The MQTT plugin is available on most distribution of
collectd
, but this is not the case on MacOS using homebrew. If you are missing the MQTT plugin, please recompilecollectd
to include the MQTT plugin. See https://github.com/collectd/collectd for details. - Here is a config snippet to configure the MQTT write plugin:
LoadPlugin mqtt <Plugin mqtt> <Publish "tedge"> Host "localhost" Port 1883 ClientId "tedge-collectd" </Publish> </Plugin>
- RRDTool and CSV might be disabled
- The risk with these plugins is to run out of disk space on a small device.
- With thin-edge.io the metrics collected by
collectd
are forwarded to the cloud, hence it makes sense to disable Local storage. - For that, simply comment out these two plugins:
#LoadPlugin rrdtool #LoadPlugin csv
- Cherry-pick the collected metrics
Collectd
can collect a lot of detailed metrics, and it doesn't always make sense to forward all these data to the cloud.- Here is a config snippet that uses the
match_regex
plugin to select the metrics of interest, filtering out every metric emitted by the memory plugin other than the used metric":
PreCacheChain "PreCache" LoadPlugin match_regex <Chain "PreCache"> <Rule "memory_free_only"> <Match "regex"> Plugin "memory" </Match> <Match "regex"> TypeInstance "used" Invert true </Match> Target "stop" </Rule> </Chain>
Enable thin-edge monitoring
To enable monitoring on your device, you have to launch the tedge-mapper-collectd
daemon process.
sudo systemctl enable tedge-mapper-collectd
sudo systemctl start tedge-mapper-collectd
This process subscribes to the collectd/#
topics to read the monitoring metrics published by collectd
and emits the translated measurements in thin-edge.io JSON format to the tedge/measurements
topic.
You can inspect the collected and translated metrics, by subscribing to these topics:
The metrics collected by collectd
are emitted to subtopics named after the collectd plugin and the metric name:
$ tedge mqtt sub 'collectd/#'
[collectd/raspberrypi/cpu/percent-active] 1623076679.154:0.50125313283208
[collectd/raspberrypi/memory/percent-used] 1623076679.159:1.10760866126707
[collectd/raspberrypi/cpu/percent-active] 1623076680.154:0
[collectd/raspberrypi/df-root/percent_bytes-used] 1623076680.158:71.3109359741211
[collectd/raspberrypi/memory/percent-used] 1623076680.159:1.10760866126707
The tedge-mapper-collectd
translates these collectd measurements into the thin-edge.io JSON format,
grouping the measurements emitted by each plugin:
tedge mqtt sub 'tedge/measurements'
[tedge/measurements] {"time":"2021-06-07T15:38:59.154895598+01:00","cpu":{"percent-active":0.50251256281407},"memory":{"percent-used":1.11893578135189}}
[tedge/measurements] {"time":"2021-06-07T15:39:00.154967388+01:00","cpu":{"percent-active":0},"df-root":{"percent_bytes-used":71.3110656738281},"memory":{"percent-used":1.12107875001658}}
From there, if the device is actually connected to a cloud platform like Cumulocity, these monitoring metrics will be forwarded to the cloud.
tedge mqtt sub 'c8y/#'
[c8y/measurement/measurements/create] {"type": "ThinEdgeMeasurement","time":"2021-06-07T15:40:30.155037451+01:00","cpu":{"percent-active": {"value": 0.753768844221106}},"memory":{"percent-used": {"value": 1.16587699972141}},"df-root":{"percent_bytes-used": {"value": 71.3117904663086}}}
[c8y/measurement/measurements/create] {"type": "ThinEdgeMeasurement","time":"2021-06-07T15:40:31.154898577+01:00","cpu":{"percent-active": {"value": 0.5}},"memory":{"percent-used": {"value": 1.16608109197519}}}
If your device is not connected yet see:
Trouble shooting
See here for how to trouble shoot device monitoring?
Manage the softwares on your devices from Cumulocity cloud
This document describes how to manage the software modules that are installed on a thin-edge device from the cloud using the software management feature of thin-edge.io.
Note: This tutorial shows the Debian based distributions apt package manager use-case powered by our official apt plugin. Other package managers can be supported by adding a plugin. Refer to this document on how to write a plugin to support software management for any other software type.
Important: As of now, software management feature is supported only from Cumulocity cloud, which supports only
install
anddelete
as an action of c8y_SoftwareUpdate operation.
Three components are required on your devices to enable software management:
-
Software management mapper for Cumulocity cloud acts as a proxy between the cloud and the device. This translates the cloud specific message type into device specific type and vice-versa.(Example: Cumulocity smart-rest to/from thin-edge json) The messages from cloud will be translated and forwarded to the
tedge_agent
and messages fromtedge_agent
will be translated and sent to cumulocity cloud. You can find this process with the nametedge_mapper c8y
inps
once it starts. -
Software management agent The thin-edge software management agent is the one that calls the plugins. You can find this process with the name
tedge_agent
inps
once it starts. -
Software management plugin Plugins are the interfaces that call the package manager (example: apt/apt-get) to do the software management operations (Install, Remove or update) You can find them in /etc/tedge/sm-plugins. As of now there is only one (apt) plugin is supported.
Enable software management feature
Find more information about how to install and enable software management.
Managing the device software repository on Cumulocity cloud
Managing the software packages installed on the devices from your Cumulocity tenant is a two steps operation.
- Populate the software repository with all the software packages and versions you plan to install.
- Trigger software update operations on the devices, to install specific packages from the repository.
Find more information about managing the device software
Adding new software into the software repository of your tenant
-
In the Software repository page, click Add software at the right of the top menu bar.
-
In the resulting dialog box,
- to add a new software, enter a name for the software (and confirm it by clicking Create new in the resulting window), a description and its version.
- to add a new version, select the software for which you want to add a new version from the dropdown list in the Software field and enter a version of the package. The version is optional and can be left with a white space, meaning the latest version.
Note: The version field format is
package_version::plugin_type_name
.The plugin type name that is provided here is used to pick the appropriate plugin among those installed in /etc/tedge/sm-plugins.Note 2: If the postfix
::plugin_type_name
is left empty, adefault
plugin will be used if defined or if only a single plugin is installed. -
Optionally, you can define the device type filter when adding a new software.
-
thin-edge.io ships a default plugin supporting
debian
packages from bothapt
repositories as well as remote locations. If you prefer to use packages from anapt
repository, select the Provide a file path option and give an empty space (' ').If you would like to use other sources (eg. file uploaded to your cloud or an external source), provide the full url to the file.
If you would like to upload your binaries, select
Upload a binary
option and upload the file to Cumulocity software repository.Note: Bear in mind that some external remotes may require additional authentication which is not supported at the moment.
-
Press
Add Software
button.
Deleting software or software version
One can remove a software module or a specific version of it from the software repository. Find more information about how to delete the software or the specific software version
Managing software on a device
Find more information about how to manage the software on a device.
From the Cumulocity cloud Software
tab of a device, software can be
Note: Software profiles are not supported as of now on thin-edge.
Note: Thin-edge treats install and update same.
Note: Once the above mentioned operation is selected, one should click on Apply changes to confirm operation.
Default plugin
When there are multiple plugins installed on the device, one can set one of them as a default plugin. If there is only one plugin installed on the device, then implicitly this will be the default plugin.
Usage of default plugin
When the default plugin is set, then the software operation does not need to provide an explicit type of the software, then the default will be used. In Cumulocity, one can then simply provide the package to update without having to annotate the version field with its type.
Configuring the default plugin
Default plugin can be configured using the thin-edge cli command tedge
.
For example set apt
plugin as a default plugin
sudo tedge config set software.plugin.default apt
Write my software management plugin
thin-edge.io Software Management natively supports APT (Debian) packages. However, there are many package management systems in the world, and you may want to have a plugin that is suitable for your device. For such a demand, we provide the Package Manager Plugin API to write a custom Software Management plugin in your preferred programming language.
In this tutorial, we will look into the Package Manager Plugin API, and learn how to write your own plugin with a docker plugin shell script example.
Create a plugin
Create a docker file in the directory /etc/tedge/sm-plugins/. A plugin must be an executable file located in that directory.
Filename: /etc/tedge/sm-plugins/docker
#!/bin/sh
COMMAND="$1"
IMAGE_NAME="$2"
case "$COMMAND" in
list)
docker image list --format '{{.Repository}}\t{{.Tag}}' || exit 2
;;
install)
docker pull $IMAGE_NAME || exit 2
;;
remove)
docker rmi $IMAGE_NAME || exit 2
;;
prepare)
;;
finalize)
;;
update-list)
exit 1
;;
esac
exit 0
Info: the filename will be used as a plugin type to report the software list to a cloud. If you name it
docker.sh
, you will seedocker.sh
as a plugin type in cloud.
If you execute ./docker list
, you will see this kind of output.
alpine 3.14
eclipse-mosquitto 2.0-openssl
...
The Software Management Agent runs executable plugins with a special argument, like list
.
Let's call the pre-defined argument such as list
, install
, and remove
a command here.
As you can see from this example, a plugin should be an executable file
that accepts the commands and outputs to stdout and stderr.
Hence, you can implement a plugin in your preferred language.
Here is the table of the commands that you can use in a plugin.
Command | Input arguments | Expected output | Description |
---|---|---|---|
list | - | lines with tab separated values | Returns the list of software modules that have been installed with this plugin. |
prepare | - | - | Executes the provided actions before a sequence of install and remove commands. |
finalize | - | - | Executes the provided actions after a sequence of install and remove commands. |
install | NAME [--version VERSION] [--file FILE] | - | Executes the action of installation. |
remove | NAME [--version VERSION] | - | Executes the action of uninstallation. |
update-list | COMMAND NAME [--version VERSION] [--file FILE] | - | Executes the list of install and remove commands. |
The order of the commands invoked by the Software Management Agent is:
prepare
-> update-list
or [install
, remove
] ->finalize
info: There is no guarantee of the order between
install
andremove
. If you need a specific order, useupdate-list
command instead.
In the following sections, we will dive into each command and other rules deeply.
Input, Output, and Errors
Before we dive into each command, we should clarify the basic rules of plugins.
Input
The command themselves and further required arguments must be given as command-line arguments.
The only exception is update-list
, which requires stdin input.
Output
The stdout and stderr of the process running a plugin command are captured by the Software Management Agent.
Exit status
The exit status of plugins are interpreted by sm-agent as follows:
- 0: success.
- 1: usage. The command arguments cannot be interpreted, and the command has not been launched.
- 2: failure. The command failed and there is no point to retry.
- 3: retry. The command failed but might be successful later (for instance, when the network will be back).
List
The list
command is responsible to return the list of the installed software modules.
Rules:
- This command takes no arguments.
- The list is returned using CSV with tabulations as separators,
including:
- name: the name of the software module, e.g.
mosquitto
. This name is the name that has been used to install it and that needs to be used to remove it. - version: the version currently installed.
This is a string that can only be interpreted in the context of the plugin.
>Note: If the version is not present for a module, then list can return only the module name without trailing tabulation.
Given that your plugin is named
docker
, then the Software Management Agent calls
- name: the name of the software module, e.g.
sudo /etc/tedge/sm-plugins/docker list
to report the list of software modules installed.
Important: the Software Management Agent executes a plugin using
sudo
and astedge-agent
user.
docker
should output in the CSV with tabulations as separators like
alpine 3.14
eclipse-mosquitto 2.0-openssl
rust 1.51-alpine
with exit code 0
(successful).
In most cases, the output of the list
command is multi-lines.
The line separator should be \n
.
A plugin must return a CSV line per software module, using a tabulation \t
as separator.
If there is no version field then only the module name will be returned.
In the docker file example, the following command outputs CSV structures with tabulations as separator.
docker image list --format '{{.Repository}}\t{{.Tag}}'
Prepare
The prepare
command is invoked by the sm-agent before a sequence of install and remove commands.
Rules:
- It takes no argument and no output is expected.
- If the
prepare
command fails, then the whole Software Management operation is cancelled.
For many plugins, this command has nothing specific to do, and can simply return with a 0
exit status.
In some plugin types, this prepare
command can help you.
For example, assume that you want to implement a plugin for APT,
and want to run apt-get update
always before calling the install
command.
In this example, the prepare
command is the right place to invoke apt-get update
.
Finalize
The finalize
command closes a sequence of install and removes commands started by a prepare command.
Rules:
- It takes no argument and no output is expected.
- If the
finalize
command fails, then the whole Software Management operation is reported as failed, even if all the atomic actions have been successfully completed.
Similar to the prepare
plugin, you must define the command even if you want nothing in the finalize
command.
The command can be used in several situations. For example,
- remove any unnecessary software module after a sequence of actions.
- commit or roll back the sequence of actions.
- restart any processes using the modules, e.g. restart the analytics engines if the modules have changed.
Install
The install
command installs a software module, possibly of some expected version.
A plugin must be executable in the below format.
$ myplugin install NAME [--module-version VERSION] [--file FILE]
This command takes 1 mandatory argument and has 2 optional flags.
- NAME: the name of the software module to be installed, e.g.
mosquitto
. (Mandatory) - VERSION: the version to be installed. e.g.
1.5.7-1+deb10u1
. The version can be blank, so it's recommended to define the behaviour if a version is not provided. For example, always installs the "latest" version if a version is not provided. (Optional) - FILE: the path to the software to be installed. (Optional)
The installation phase may fail due to the following reasons. An error must be reported if:
- The module name is unknown.
- There is no version for the module that matches the constraint provided by the
--module-version
option. - The file content provided by
--file
option:- is not in the expected format,
- doesn't correspond to the software module name,
- has a version that doesn't match the constraint provided by the
--module-version
option (if any).
- The module cannot be downloaded.
- The module cannot be installed.
At the API level, there is no command to distinguish install or upgrade.
Back to the first docker example, it doesn't address the case with version. Let's expand the example file as below.
Filename: /etc/tedge/sm-plugins/docker
#!/bin/sh
COMMAND="$1"
IMAGE_NAME="$2"
VERSION_FLAG="$3"
IMAGE_TAG="$4"
case "$COMMAND" in
list)
docker image list --format '{{.Repository}}\t{{.Tag}}' || exit 2
;;
install)
if [ $# -eq 2 ]; then
docker pull $IMAGE_NAME || exit 2
elif [ $# -eq 4 ] && [ $VERSION_FLAG = "--module-version" ]; then
docker pull $IMAGE_NAME:$IMAGE_TAG || exit 2
else
echo "Invalid arguments"
exit 1
fi
;;
remove)
if [ $# -eq 2 ]; then
docker rmi $IMAGE_NAME || exit 2
elif [ $# -eq 4 ] && [ $VERSION_FLAG = "--module-version" ]; then
docker rmi $IMAGE_NAME:$IMAGE_TAG || exit 2
else
echo "Invalid arguments"
exit 1
fi
;;
prepare)
;;
finalize)
;;
update-list)
exit 1
;;
esac
exit 0
Pay attention to the exit statuses.
In case of invalid arguments, the plugin returns 1
.
If a command is executed but fails, the plugin returns 2
.
Each exit status is defined here.
If the given NAME is mosquitto
, and the given VERSION is 1.5.7-1+deb10u1
,
the Software Management Agent calls
sudo /etc/tedge/sm-plugins/docker install mosquitto --module-version 1.5.7-1+deb10u1
Then, the plugin executes
docker pull mosquitto:1.5.7-1+deb10u1
Remove
The remove
command uninstalls a software module,
and possibly its dependencies if no other modules are dependent on those.
A plugin must be executable in the below format.
$ myplugin remove NAME [--module-version VERSION]
This command takes 1 mandatory argument and 1 optional argument with a flag.
- NAME: the name of the software module to be removed, e.g.
mosquitto
. (Mandatory) - VERSION: the version to be installed. e.g.
1.5.7-1+deb10u1
. The version can be blank, so it's recommended to define the behaviour if a version is not provided. For example, uninstall a software module regardless of its version if a version is not provided. (Optional)
The uninstallation phase can be failed due to several reasons. An error must be reported if:
- The module name is unknown.
- The module cannot be uninstalled.
Back to the first docker plugin example,
if the NAME is mosquitto
, and the VERSION is 1.5.7-1+deb10u1
,
the Software Management Agent calls
sudo /etc/tedge/sm-plugins/docker remove mosquitto --module-version 1.5.7-1+deb10u1
Then, the plugin executes
docker rmi mosquitto:1.5.7-1+deb10u1
Update-list
The update-list
command accepts a list of software modules and associated operations as install
or remove
.
This basically achieves the same purpose as original commands install and remove,
but gets passed all software modules to be processed in one command.
This can be needed when an order of processing software modules is relevant.
In other words, you can choose a combination of the install
or remove
commands or this update-list
command up to your requirement.
If you don't want to use update-list
, the plugin must return 1
like the first docker plugin example.
case "$COMMAND" in
...
update-list)
exit 1
;;
esac
Let's expand the first docker plugin example to use update-list
.
First, learn what is the input of update-list
.
The Software Management Agent calls a plugin as below. Note that each argument is tab separated:
$ sudo /etc/tedge/sm-plugins/docker update-list <<EOF
install name1 version1
install name2 path2
remove name3 version3
remove name4
EOF
The point is that it doesn't take any command-line argument, but the software action list is sent through stdin.
The behaviour of operations install
and remove
is the same as for original commands install
and remove
.
The above input is equivalent to the use of original commands (install
and remove
):
$ /etc/tedge/sm-plugins/docker install name1 --module-version version1
$ /etc/tedge/sm-plugins/docker install name2 --file path2
$ /etc/tedge/sm-plugins/docker remove "name 3" --module-version version3
$ /etc/tedge/sm-plugins/docker remove name4
To make the docker plugin accept a list of install and remove actions, let's change the file as below. Note that this example works only in bash.
Filename: /etc/tedge/sm-plugins/docker
#!/bin/bash
COMMAND="$1"
case "$COMMAND" in
list)
docker image list --format '{{.Repository}}\t{{.Tag}}' || exit 2
;;
install)
echo docker pull "$2:$3"
;;
remove)
echo docker rmi "$2:$3"
;;
prepare)
;;
finalize)
;;
update-list)
while IFS=$'\t' read -r ACTION MODULE VERSION FILE
do
bash -c "$0 $ACTION $MODULE $VERSION"
done
;;
esac
exit 0
You can find that install
and remove
are replaced by update-list
.
update-list
should define the behaviour to read line by line for the case install
and remove
.
Also, update-list
must be fail-fast.
That example exists immediately if one of the commands fails.
Project references
You can also refer to:
- the specification of the Package Manager Plugin API.
- the APT plugin written in Rust.
- the example Docker plugin written in POSIX standard shell script. This plugin can install/remove docker containers using docker image tags. This plugin is not to be used in production without necessary enhancements. It is to be used only as a reference to write your own plugin.
thin-edge.io Supported Operations
Supported Operations concepts
Device operations
IoT devices often do more than just send data to the cloud. They also do things like:
- receive triggers from the operator
- reboot on demand
- install or remove software
These operations are supported by Cumulocity IoT and other cloud providers.
On thin-edge.io
the support for one such operation can be added using the thin-edge.io
Supported Operations API.
thin-edge.io
Supported Operations API
The Supported Operations utilises the file system to add and remove operations. A special file placed in /etc/tedge/operations
directory will indicate that an operation is supported.
The specification for the operation files is described in thin-edge.io
specifications repositorysrc/supported-operations/README.md
Supported operations are declared in the cloud specific subdirectory of /etc/tedge/operations
directory.
Custom Supported Operations
thin-edge.io
supports custom operations by using configuration files and plugin mechanism similar to what software management agent does.
The main difference between custom operations and native operations is that custom operations are have to be defined in configuration files and provide their own implementation in a callable plugin
executable.
As per specification the configuration file needs to be a toml
file which describes the operation.
thin-edge.io
stores the operations configuration files in the /etc/tedge/operations/<cloud-provider>/
directory.
thin-edge.io
List of Supported Operations
thin-edge.io
supports natively the following operations:
- Software Update
- Software Update Log Upload
- Restart
The list is growing as we support more operations, but is not exhaustive and we encourage you to contribute to the list.
How to use Supported Operations
Listing current operations
You can obtain the current list of supported operations by listing the content of the /etc/tedge/operations
directory.
This directory should have permissions set to 755
and the owner to tedge
.
This directory will contain a set subdirectories based on cloud providers currently supported eg:
$ ls -l /etc/tedge/operations
drwxr-xr-x 2 tedge tedge 4096 Jan 01 00:00 az
drwxr-xr-x 2 tedge tedge 4096 Jan 01 00:00 c8y
From the above you can see that there are two cloud providers supported by thin-edge.io
.
The directories should be readable by thin-edge.io
user - tedge
- and should have permissions 755
.
To list all currently supported operations for a cloud provider, run:
$ ls -l /etc/tedge/operations/c8y
-rw-r--r-- 1 tedge tedge 0 Jan 01 00:00 c8y_Restart
To list all currently supported operations, run:
The operations files should have permissions 644
and the owner tedge
.
$ sudo ls -lR /etc/tedge/operations
/etc/tedge/operations:
drwxr-xr-x 2 tedge tedge 4096 Jan 01 00:00 az
drwxr-xr-x 2 tedge tedge 4096 Jan 01 00:00 c8y
/etc/tedge/operations/az:
-rw-r--r-- 1 tedge tedge 0 Jan 01 00:00 Restart
/etc/tedge/operations/c8y:
-rw-r--r-- 1 tedge tedge 0 Jan 01 00:00 c8y_Restart
Adding new operations
To add new operation we need to create new file in /etc/tedge/operations
directory.
Before we create that file we have to know which cloud provider we are going to support (it is possible to support multiple cloud providers, but we won't cover this here).
We will add operation Restart
for our device which can be triggered from Cumulocity IoT called, in Cumulocity IoT this operations name is c8y_Restart
.
This operation will do the reboot of our device when we receive trigger from the operator. thin-edge.io
device will receive an MQTT message with certain payload and we already have a handler for that payload in the tedge-mapper-c8y
.
To add new operation we will create a file in /etc/tedge/operations/c8y
directory:
sudo -u tedge touch /etc/tedge/operations/c8y/c8y_Restart
Note: We are using
sudo -u
to create the file because we want to make sure that the file is owned bytedge
user.
Now the new operation will be automatically added to the list and the list will be sent to the cloud.
Removing supported operations
To remove supported operation we can remove the file from /etc/tedge/operations/c8y
directory. eg:
sudo rm /etc/tedge/operations/c8y/c8y_Restart
Now the operation will be automatically removed from the list and the list will be sent to the cloud.
Working with custom operations
We will use the thin-edge.io
Supported Operations API to add custom operations. Our new operation is going to be capability to execute shell commands on the device.
Let's create the operation configuration file:
We need to tell thin-edge.io
how to handle the operation and how to execute it.
Adding new custom operation
In Cumulocity IoT we know that there is an operation call c8y_Command which allows us to send commands to the device and get the result back to the cloud, let's create the configuration file for our new operation:
First we create a file with the name of the operation:
sudo -u tedge touch /etc/tedge/operations/c8y/c8y_Command
Note: the needs to be readable by
thin-edge.io
user -tedge
- and should have permissions644
.
In this example we want thin-edge.io
to pick up a message on specific topic and execute the command on the device, our topic is c8y/s/ds
.
We also know that the message we expect is going to use SmartRest template 511
and our plugin is located in /etc/tedge/operations/command
.
Then we need to add the configuration to the file (/etc/tedge/operations/c8y/c8y_Command
):
[exec]
topic = "c8y/s/ds"
on_message = "511"
command = "/etc/tedge/operations/command"
And now the content of our command plugin:
#!/usr/bin/sh
mosquitto_pub -t c8y/s/us -m 501,c8y_Command
OUTPUT=$(echo $1)
mosquitto_pub -t c8y/s/us -m 503,c8y_Command,"$OUTPUT"
This simple example will execute the command echo $1
and send the result back to the cloud.
Note: The command will be executed with tedge-mapper permission level so most of the system level commands will not work.
List of currently supported operations parameters
topic
- The topic on which the operation will be executed.on_message
- The SmartRest template on which the operation will be executed.command
- The command to execute.
How-to Guides
- How to install thin-edge.io?
- How to create a test certificate?
- How to connect a cloud end-point?
- How to use
tedge mqtt
module? - How to test connection to cloud?
- How to test the cloud connection?
- How to configure the local mqtt bind address and port?
- How to trouble shoot device monitoring?
- How to add self-signed certificate root to trusted certificates list?
- How to retrieve JWT token from Cumulocity?
- How to install and enable software management?
- How to connect an external device?
- How to access the logs on the device?
- How to install thin-edge.io on any Linux OS (no deb support)?
- How to restart your thin-edge.io device
- How to manage apama software artefatcs with apama plugin?
- How to change temp path
- How to use thin-edge.io with your preferred init system
- How to monitor health of tedge daemons
- How to enable watchdog using systemd?
- How to add custom fragments to Cumulocity
- How to retrieve logs with the log plugin
- How to add C8Y SmartRest Templates
- How to manage configuration files with Cumulocity
- How to install thin-edge manually with openrc
How to install thin-edge.io
?
Installation with get-thin-edge_io.sh script
There are two possibilities to install thin-edge.io, the easiest way is to use the installation script with this command:
curl -fsSL https://raw.githubusercontent.com/thin-edge/thin-edge.io/main/get-thin-edge_io.sh | sudo sh -s
You can execute that command on your device and it will do all required steps for an initial setup.
If you prefer to have a little more control over the installation or the script did not work for you, please go on with the following steps.
Manual installation steps
To install thin edge package it is required to use curl
to download the package and dpkg
to install it.
Dependency installation
thin-edge.io has single dependency and it is mosquitto
used for communication southbound and northbound e.g. southbound, devices can publish measurements; northbound, gateway may relay messages to cloud.
mosquitto
can be installed with your package manager. For apt the command may look as following:
apt install mosquitto
Note: Some OSes may require you to use
sudo
to install packages.
sudo apt install mosquitto
thin-edge.io
installation
When all dependencies are in place you can proceed with installation of thin-edge.io cli
and thin-edge.io mapper
service.
Upgrading thin-edge.io
If you already have thin-edge.io
on your device to upgrade thin-edge.io
follow the steps below, there is no need to remove old version.
Note: To successfully upgrade
thin-edge.io
all thin-edge.io components should be stopped, eg:tedge-mapper
andtedge-agent
:systemctl stop tedge-mapper-c8y systemctl stop tedge-agent
Package download
thin-edge.io package is in thin-edge.io repository on GitHub: thin-edge.io.
To download the package from github repository use following command (use desired version):
curl -LJO https://github.com/thin-edge/thin-edge.io/releases/download/<package>_<version>_<arch>.deb
where:
version
-> thin-edge.io version in x.x.x format
arch
-> architecture type (amd64, armhf, arm64)
Eg:
curl -LJO https://github.com/thin-edge/thin-edge.io/releases/download/0.5.0/tedge_0.5.0_armhf.deb
and for mapper
:
curl -LJO https://github.com/thin-edge/thin-edge.io/releases/download/0.5.0/tedge_mapper_0.5.0_armhf.deb
Package installation
Now, we have downloaded the package we can proceed to installation. First we will install cli tool tedge
.
Note: Some OSes may require you to use
sudo
to install packages and therefore all following commands may needsudo
.
To install tedge
use following command:
dpkg -i tedge_<version>_<arch>.deb
Eg:
dpkg -i tedge_0.5.0_armhf.deb
To install mapper for thin-edge.io do:
dpkg -i tedge_mapper_<version>_<arch>.deb
Eg:
dpkg -i tedge_mapper_0.5.0_armhf.deb
Next steps
How to register?
Create self-signed certificate
To create new certificate you can use tedge cert create
thin-edge.io command:
sudo tedge cert create --device-id alpha
Note:
tedge cert
requiressudo
privilege. This command provides no output on success.
sudo tedge cert create
will create certificate in a default location (/etc/tedge/device-certs/
).
To use a custom location, refer to tedge config
.
Now you should have a certificate in the /etc/tedge/device-certs/
directory.
$ ls /etc/tedge/device-certs/
/etc/tedge/device-certs/tedge-certificate.pem
Errors
Certificate creation fails due to invalid device id
If non-supported characters are used for the device id then the cert create will fail with below error:
Error: failed to create a test certificate for the device +.
Caused by:
0: DeviceID Error
1: The string '"+"' contains characters which cannot be used in a name [use only A-Z, a-z, 0-9, ' = ( ) , - . ? % * _ ! @]
Certificate already exists in the given location
If the certificate already exists you may see following error:
Error: failed to create a test certificate for the device alpha.
Caused by:
A certificate already exists and would be overwritten.
Existing file: "/etc/tedge/device-certs/tedge-certificate.pem"
Run `tedge cert remove` first to generate a new certificate.
Warning! Removing a certificate can break the bridge and more seriously delete a certificate that was a CA-signed certificate.
Follow the instruction to remove the existing certificate and issue tedge cert remove
:
sudo tedge cert remove
and try tedge cert create
once again.
Next steps
How to connect?
Connect to Cumulocity IoT
To create northbound connection a local bridge shall be established and this can be achieved with tedge
cli and following commands:
Note:
tedge connect
requiressudo
privilege.
Configure required parameters for thin-edge.io with tedge config set
:
sudo tedge config set c8y.url example.cumulocity.com
Tip: If you you are unsure which parameters are required for the command to work run the command and it will tell you which parameters are missing. For example, if we issue
tedge connect c8y
without any configuration following advice will be given:$ tedge connect c8y` ... Error: failed to execute `tedge connect`. Caused by: Required configuration item is not provided 'c8y.url', run 'tedge config set c8y.url <value>' to add it to config.
This message explains which configuration parameter is missing and how to add it to configuration, in this case we are told to run
tedge config set c8y.url <value>
.
The next step is to have the device certificate trusted by Cumulocity. This is done by uploading the certificate of the signee.
You can upload root certificate via Cumulocity UI or with tedge cert upload
as described below.
Note: This command takes parameter
user
, this is due to upload mechanism to Cumulocity cloud which uses username and password for authentication.After issuing this command you are going to be prompted for a password. Users usernames and passwords are not stored in configuration due to security.
$ sudo tedge cert upload c8y –-user <username>
Password:
where:
username
-> user in Cumulocity with permissions to upload new certificates
To create bridge use tedge connect
:
$ sudo tedge connect c8y
Checking if systemd is available.
Checking if configuration for requested bridge already exists.
Validating the bridge certificates.
Creating the device in Cumulocity cloud.
Saving configuration for requested bridge.
Restarting mosquitto service.
Awaiting mosquitto to start. This may take up to 5 seconds.
Enabling mosquitto service on reboots.
Successfully created bridge connection!
Sending packets to check connection. This may take up to 2 seconds.
Connection check is successful.
Checking if tedge-mapper is installed.
Starting tedge-mapper-c8y service.
Persisting tedge-mapper-c8y on reboot.
tedge-mapper-c8y service successfully started and enabled!
Enabling software management.
Checking if tedge-agent is installed.
Starting tedge-agent service.
Persisting tedge-agent on reboot.
tedge-agent service successfully started and enabled!
Errors
Connection already established
If connection has already been established following error may appear:
$ sudo tedge connect c8y
Checking if systemd is available.
Checking if configuration for requested bridge already exists.
Error: failed to create bridge to connect Cumulocity cloud.
Caused by:
Connection is already established. To remove existing connection use 'tedge disconnect c8y' and try again.
To remove existing connection and create new one follow the advice and issue tedge disconnect c8y
:
$ sudo tedge disconnect c8y
Removing Cumulocity bridge.
Applying changes to mosquitto.
Cumulocity Bridge successfully disconnected!
Stopping tedge-mapper-c8y service.
Disabling tedge-mapper-c8y service.
tedge-mapper-c8y service successfully stopped and disabled!
Stopping tedge-agent service.
Disabling tedge-agent service.
tedge-agent service successfully stopped and disabled!
Note:
tedge disconnect c8y
also stops and disable tedge-mapper service if it is installed on the device.
And now you can issue tedge connect c8y
to create new bridge.
Connection check warning
Sample output of tedge connect when this warning occurs:
$ sudo tedge connect c8y
Checking if systemd is available.
Checking if configuration for requested bridge already exists.
Validating the bridge certificates.
Creating the device in Cumulocity cloud.
Saving configuration for requested bridge.
Restarting mosquitto service.
Awaiting mosquitto to start. This may take up to 5 seconds.
Enabling mosquitto service on reboots.
Successfully created bridge connection!
Sending packets to check connection. This may take up to 2 seconds.
ERROR: Local MQTT publish has timed out.
Warning: Bridge has been configured, but Cumulocity connection check failed.
Checking if tedge-mapper is installed.
Starting tedge-mapper-c8y service.
Persisting tedge-mapper-c8y on reboot.
tedge-mapper-c8y service successfully started and enabled!
Enabling software management.
Checking if tedge-agent is installed.
Starting tedge-agent service.
Persisting tedge-agent on reboot.
tedge-agent service successfully started and enabled!
This warning may be caused by some of the following reasons:
- No access to Internet connection
Local bridge has been configured and is running but the connection check has failed due to no access to the northbound endpoint.
- Cumulocity tenant not available
Tenant couldn't be reached and therefore connection check has failed.
- Check bridge
Bridge configuration is correct but the connection couldn't be established to unknown reason.
To retry start with tedge disconnect c8y
removing this bridge:
sudo tedge disconnect c8y
When this is done, issue tedge connect c8y
again.
File permissions
Sample output:
$ tedge connect c8y
Checking if systemd is available.
Checking if configuration for requested bridge already exists.
Validating the bridge certificates.
Saving configuration for requested bridge.
Error: failed to create bridge to connect Cumulocity cloud.
Caused by:
0: File Error. Check permissions for /etc/tedge/mosquitto-conf/tedge-mosquitto.conf.
1: failed to persist temporary file: Permission denied (os error 13)
2: Permission denied (os error 13)
tedge connect cannot access location to create the bridge configuration (/etc/tedge/mosquitto-conf
), check permissions for the directory and adjust it to allow the tedge connect to access it.
Example of incorrect permissions:
$ ls -l /etc/tedge
dr--r--r-- 2 tedge tedge 4096 Mar 30 15:40 mosquitto-conf
You should give it the permission 755.
$ ls -l /etc/tedge
drwxr-xr-x 2 tedge tedge 4096 Mar 30 15:40 mosquitto-conf
mosquitto and systemd check fails
Sample output:
$ sudo tedge connect c8y
Checking if systemd is available.
Checking if configuration for requested bridge already exists.
Validating the bridge certificates.
Saving configuration for requested bridge.
Restarting mosquitto service.
Error: failed to create bridge to connect Cumulocity cloud.
Caused by:
Service mosquitto not found. Install mosquitto to use this command.
mosquitto server has not been installed on the system and it is required to run this command, refer to How to install thin-edge.io? to install mosquitto and try again.
Next steps
How to use tedge mqtt
pub and sub?
thin-edge.io cli provides a convenient way to debug and aid development process.
Publish
Command tedge mqtt pub
can be used to publish MQTT messages on a topic to the local mosquitto server.
Example:
tedge mqtt pub 'tedge/measurements' '{ "temperature": 21.3 }'
tedge mqtt pub
supports setting of QoS for MQTT messages:
tedge mqtt pub 'tedge/measurements' '{ "temperature": 21.3 }' --qos 2
tedge mqtt pub
supports publishing a MQTT message with retain flag:
tedge mqtt pub --retain --qos 1 tedge/alarms/critical/high_temperature '{"message": "Temperature is critical"}'
Note: By default the mqtt message will be published with retain flag set to false.
Subscribe
Command tedge mqtt sub
can be used to ease debugging of of MQTT communication on local bridge. You can subscribe to topic of your choosing:
tedge mqtt sub tedge/errors
Or you can subscribe to any topic on the server using wildcard (#
) topic:
tedge mqtt sub '#'
Now use tedge mqtt pub 'tedge/measurements' '{ "temperature": 21.3 }'
to publish message on tedge/measurements
topic with payload { "temperature": 21.3 }
.
All messages from sub command are printed to stdout
and can be captured to a file if you need to:
tedge mqtt sub '#' > filename.mqtt
Wildcard (#
) topic is used by MQTT protocol as a wildcard and will listen on all topics
How to test the connection to cloud?
We provide a way to test the connection from your device to a cloud provider. You can call this connection check function by
sudo tedge connect <cloud> --test
It returns exit code 0 if the connection check is successful, otherwise, 1.
This test is already performed as part of the tedge connect <cloud>
command.
What does the test do?
The connection test sends a message to the cloud and waits for a response. The subsequent sections explain the cloud-specific behaviour.
For Cumulocity IoT
The test publishes a SmartREST2.0 static template message for device creation 100
to the topic c8y/s/us
.
If the device-twin is already created in your Cumulocity,
the device is supposed to receive 41,100,Device already existing
on the error topic c8y/s/e
.
So, the test subscribes to c8y/s/e
topic and if it receives the expected message on the topic, the test is marked successful.
The connection test sends maximum two of SmartREST2.0 100
requests.
This is because the first 100
request can be considered a successful device creation request if the device-twin does not exist in Cumulocity yet.
For Azure IoT Hub
The test subscribes to the topic az/twin/res/
.
Then, it publishes an empty string to the topic az/twin/GET/?$rid=1
.
If the connection check receives a message containing 200
(status success), the test is marked successful.
The connection test sends the empty string only once.
Next steps
How to configure the local port and bind address in mosquitto?
Configuring a mosquitto port and bind address in thin-edge.io is a three-step process.
Note: The mqtt.port and the mqtt.bind_address can be set/unset independently.
Step 1: Disconnect thin-edge.io edge device
The thin edge device has to be disconnected from the cloud using the tedge
command
tedge disconnect c8y/az
Step 2: Set and verify the new mqtt port and bind address
Use the tedge
command to set the mqtt.port and mqtt.bind_address with a desired port and bind address as below.
tedge config set mqtt.port 1024
tedge config set mqtt.bind_address 127.0.0.1
Note: The bind_address is the address of the one of the device interface. For example this can be get as
ifconfig | grep inet
or set it to0.0.0.0
This will make sure that all the mqtt clients use the newer port and the bind address that has been set once the device is connected to the cloud as in step 3.
Verify the port and the bind address configured/set
Use the tedge
command to print the mqtt port and bind address that has been set as below.
tedge config get mqtt.port
tedge config get mqtt.bind_address
Step 3: Connect the thin edge device to cloud
Use the tedge
command to connect to the desired cloud as below.
tedge connect c8y
#or
tedge connect az
This will configure all the services (mosquitto, tedge-mapper-c8y.service, tedge-mapper-az.service, tedge-agent.service) to use the newly set port and the bind address.
Note: The step 1 and 2 can be followed in any order.
Update to use default port and bind address
Use the tedge
command to set the default port (1883) and default bind address (localhost) as below.
tedge config unset mqtt.port
tedge config unset mqtt.bind_address
Once the port or the bind address is reverted to default, the step 1 and 3 has to be followed to use the default port or the default bind address.
Error case
The below example shows that we cannot set a string value for the port number.
tedge config set mqtt.port '"1234"'
Error: failed to set the configuration key: mqtt.port with value: "1234".
Caused by:
Conversion from String failed
Updating the mqtt port and bind address (host) in collectd & for collectd-mapper
Update the collectd.conf
with the new port and host in <Plugin mqtt>
.
Then, restart the collectd service.
sudo systemctl restart collectd.service
After changing the mqtt port and host, then connect to the cloud using tedge connect c8y/az
.
Then (Steps 1-3) the collectd-mapper has to be restarted to use the newly set port and bind address (host).
Restart the tedge-mapper-collectd service.
sudo systemctl restart tedge-mapper-collectd.service
How to trouble shoot device monitoring
To install and configure monitoring on your device, see the tutorial Monitor your device with collectd.
Is collectd running?
sudo systemctl status collectd
If not, launch collected
sudo systemctl start collectd
Is collectd publishing MQTT messages?
tedge mqtt sub 'collectd/#'
If no metrics are collected, please check the MQTT configuration
Is the tedge-mapper-collectd.service
running?
sudo systemctl status tedge-mapper-collectd.service
If not, launch tedge-mapper-collectd.service as below
sudo systemctl start tedge-mapper-collectd.service
Are the collectd metrics published in Thin Edge JSON format?
tedge mqtt sub 'tedge/measurements'
Are the collectd metrics published to Cumulocity IoT?
tedge mqtt sub 'c8y/#'
If not see how to connect a device to Cumulocity IoT
Are the collectd metrics published to Azure IoT?
tedge mqtt sub 'az/#'
If not see how to connect a device to Azure IoT
How to add self-signed certificate to trusted certificates list
Overview
If the server you are trying to connect thin-edge.io
to is presenting a certificate with a root that is not currently trusted, then you can add the server's root certificate to the list of trusted root certificates.
For the most part the store will be filled with certificates from your TLS/SSL provider, but when you want to use self-signed certificates you may need to update your local certificate store.
Below are instructions on how to add new CA certificate and update the certificate store.
Please note: Provided instructions are for supported OSes and may not apply to the flavour you are running, if you need help with other OS please consult appropriate documentation.
Ubuntu and Raspberry Pi OS
If you do not have the
ca-certificates
package installed on your system, install it with your package manager.sudo apt install ca-certificates
To add a self-signed certificate to the trusted certificate repository on thin-edge.io system:
Create a /usr/local/share/ca-certificates/
directory if it does not exist on your computer:
sudo mkdir /usr/local/share/ca-certificates/
The directory should be owned by root:root
and have 755
permissions set for it. The certificates files should be 644
.
Copy your root certificate (in PEM
format with .crt
extension) to the created directory:
sudo cp <full_path_to_the_certificate> /usr/local/share/ca-certificates/
Install the certificates:
$ sudo update-ca-certificates
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.
To check the certificate was correctly installed:
sudo ls /etc/ssl/certs | grep <certificate_name>
Additionally you can check correctness of the installed certificate:
sudo cat /etc/ssl/certs/ca-certificates.crt | grep -f <full_path_to_the_certificate>
How to retrieve a JWT Token to authenticate on Cumulocity
Overview
In order to authenticate HTTP requests on Cumulocity, a device can retrieve a JWT token using MQTT.
Retrieving the token
Follow the below steps in order to retrieve the token from the Cumulocity cloud using MQTT.
Subscribe to c8y/s/dat
topic
$ tedge mqtt sub c8y/s/dat --no-topic
Publish an empty message on c8y/s/uat
topic
$ tedge mqtt pub c8y/s/uat ''
After a while the token will be published on the subscribed topic c8y/s/dat
in the below format
71,[Base64 encoded JWT token]
Install and enable the software management feature
Note: As of now, this feature is supported only on devices with debian based distributions, which use the apt package manager(Ex: RaspberryPi OS , Ubuntu, Debian), from Cumulocity cloud.
Below steps show how to download, install and enable thin-edge software management feature.
Download and install software management packages on the device
As a prerequisite, install tedge and tedge_mapper if not installed already.
The thin-edge software management packages are in repository on GitHub: thin-edge.io.
To download the package from github repository use the following command (use desired version):
curl -LJO https://github.com/thin-edge/thin-edge.io/releases/download/<package>_<version>_<arch>.deb
where:
version
-> thin-edge.io software management components version in x.x.x format
arch
-> architecture type (amd64, armhf)
Download tedge_apt_plugin
and tedge_agent
curl -LJO https://github.com/thin-edge/thin-edge.io/releases/download/0.5.0/tedge_apt_plugin_0.5.0_armhf.deb
curl -LJO https://github.com/thin-edge/thin-edge.io/releases/download/0.5.0/tedge_agent_0.5.0_armhf.deb
Once the packages are downloaded, proceed to installation.
To install tedge_apt_plugin
and tedge_agent
on thin-edge device do:
sudo dpkg -i tedge_apt_plugin_<version>_<arch>.deb
sudo dpkg -i tedge_agent<version>_<arch>.deb
Note: Software management feature will be enabled after installation if the device is connected to the Cumulocity cloud using
tedge connect c8y
.
Start and enable the software management feature
Using tedge connect c8y
The tedge connect c8y
will automatically start and enable the software management feature.
Find more about how to connect thin-edge device to cloud
Once the thin-edge device is successfully connected to Cumulocity cloud, the Software option will be enabled and the list of softwares that are installed on the device will be visible as shown in the figure below.
Note: Disconnecting thin-edge device from cloud with
tedge disconnect c8y
command will stop and disable the software management feature.
Manually enabling and disabling software management feature
For debugging purpose or to disable/enable the software management services, one can start/stop manually as shown below.
Starting the services
sudo systemctl start tedge-agent.service
sudo systemctl start tedge-mapper-c8y.service
Stopping the services
sudo systemctl stop tedge-agent.service
sudo systemctl stop tedge-mapper-c8y.service
Connecting an external device to thin-edge.io
With thin-edge.io
you can enable connection for external devices to your thin-edge.io
enabled device with the use of a few commands.
Note: Currently, only one additional listener can be defined.
Configuration
External devices connection can be setup by using the tedge
cli tool making some changes to the configuration.
The following configurations option are available for you if you want to add an external listener to thin-edge.io:
mqtt.external.port
Mqtt broker port, which is used by the external mqtt clients to publish or subscribe. Example: 8883
mqtt.external.bind_address
IP address / hostname, which the mqtt broker limits incoming connections on. Example: 0.0.0.0
mqtt.external.bind_interface
Name of network interface, which the mqtt broker limits incoming connections on. Example: wlan0
mqtt.external.capath
Path to a file containing the PEM encoded CA certificates that are trusted when checking incoming client certificates. Example: /etc/ssl/certs
mqtt.external.certfile
Path to the certificate file, which is used by external MQTT listener. Example: /etc/tedge/server-certs/tedge-certificate.pem
mqtt.external.keyfile
Path to the private key file, which is used by external MQTT listener. Example: /etc/tedge/server-certs/tedge-private-key.pem
If none of these options is set, then no external listener is set. If one of these options is set, then default values are inferred by the MQTT server (Mosquitto). For instance, the port defaults to 1883 for a non-TLS listener, and to 8883 for a TLS listener.
These settings can be considered in 2 groups, listener configuration and TLS configuration.
Configure basic listener
To configure basic listener you should provide port and/or bind address which will use default interface. To change the default interface you can use mqtt.external.bind_interface configuration option.
To set them you can use tedge config
as so:
tedge config set mqtt.external.port 8883
To allow connections from all IP addresses on the interface:
tedge config set mqtt.external.bind_address 0.0.0.0
Configure TLS on the listener
To configure the external listener with TLS additional settings are available: mqtt.external.capath
mqtt.external.certfile
mqtt.external.keyfile
To enable MQTT over TLS, a server side certificate must be configured using the 2 following settings:
tedge config set mqtt.external.certfile /etc/tedge/server-certs/tedge-certificate.pem
tedge config set mqtt.external.keyfile /etc/tedge/server-certs/tedge-private-key.pem
To fully enable TLS authentication clients, client side certificate validation can be enabled:
tedge config set mqtt.external.capath /etc/ssl/certs
Note: Providing all 3 configuration will trigger thin-edge.io to require client certificates.
The thin-edge logs
The logs that are useful for debugging thin-edge.io break down into logs that are created by thin-edge itself and by third party components.
Thin-edge logs
On a thin-edge device different components like mappers, agent, and plugins run. The log messages of these components can be accessed as below. The logs here capture INFO, WARNING, and ERROR messages.
Cloud mapper logs
The thin-edge cloud mapper component that sends the measurement data to the cloud can be accessed as below.
Tedge Cumulocity mapper
The log messages of the Cumulocity mapper component that sends the measurement data from the thin-edge device to the Cumulocity cloud can be accessed as below
journalctl -u tedge-mapper-c8y.service
Note: Run
tedge_mapper --debug c8y
to log more debug messages
Tedge Azure mapper
The log messages of the Azure mapper component that sends the measurement data from the thin-edge device to the Azure cloud can be accessed as below.
journalctl -u tedge-mapper-az.service
Note: Run
tedge_mapper --debug az
to log more debug messages
Device monitoring logs
The thin-edge device monitoring component logs can be found as below
Collectd mapper logs
The log messages of the collectd mapper that sends the monitoring data to the cloud can be accessed as below
journalctl -u tedge-mapper-collectd.service
Note: Run
tedge_mapper --debug collectd
to log more debug messages
Software Management logs
This section describes how to access the software management component logs
Software update operation log
For every new software operation (list/update), a new log file will be created at /var/log/tedge/agent
.
For each plugin command
like prepare, update-list (install, remove), finalize, and list,
the log file captures exit status, stdout, and stderr
messages.
Tedge Agent logs
The agent service logs can be accessed as below
journalctl -u tedge-agent.service
For example: tedge-agent logs plugin calls finalize and list.
tedge-agent : TTY=unknown ; PWD=/tmp ; USER=root ; COMMAND=/etc/tedge/sm-plugins/apt finalize
tedge-agent : TTY=unknown ; PWD=/tmp ; USER=root ; COMMAND=/etc/tedge/sm-plugins/apt list
Note: Run
tedge_agent --debug
to log more debug messages
Thirdparty component logs
Thin-edge uses the third-party components Mosquitto
as the mqtt broker and Collectd
for monitoring purpose.
The logs that are created by these components can be accessed on a thin-edge device as below.
Mosquitto logs
Thin-edge uses Mosquitto
as the mqtt broker
for local communication as well as to communicate with the cloud.
The Mosquitto
logs can be found in /var/log/mosquitto/mosquitto.log
.
Mosquitto
captures error, warning, notice, information, subscribe, and unsubscribe messages.
Note: Set
log_type debug
orlog_type all
on /etc/mosquitto/mosquitto.conf, to capture more debug information.
Collectd logs
Collectd
is used for monitoring the resource status of a thin-edge device.
Collectd logs all the messages at /var/log/syslog
.
So, the collectd specific logs can be accessed using the journalctl
as below
journalctl -u collectd.service
How to install thin-edge.io
on any Linux OS (no deb support)?
thin-edge.io
on supported platforms
thin-edge.io
can be installed on a range of platforms, a platform is defined as a set of hardware architecture and OS, more details can be found in Supported Platforms document.
Out of the box thin-edge.io
uses deb packages for an automated installation (Installation Guide), you can install it yourself on any Linux system as long as you follow the guidelines below.
Installation on 'unsupported platforms'
Obtaining binaries
The prebuilt binaries can be obtained from thin-edge.io
repository releases.
By default thin-edge.io
is built with 3 architectures in mind: amd64 (x86_64)
, arm64 (aarch64)
and armhf
with gnulibc bindings, so if you are looking to install thin-edge.io
on a different platform you have to build your own binaries from source which you can do easily if you follow the Building thin-edge.io
guide.
Note: By default
thin-edge.io
is built withGNU libc
, but it is possible to usemusl
instead.
Full installation of thin-edge.io
requires the following components:
- tedge
- tedge-mapper
- tedge-agent
Extracting binaries from deb packages
Required packages:
- ar
- tar
Currently all binaries provided with releases are packaged into deb
packages.
deb
packages can be extracted to get the binaries for installation (example):
ar -x tedge_<version>_amd64.deb | tar -xf data.tar.xz
ar -x tedge_agent_<version>_amd64.deb | tar -xf data.tar.xz
ar -x tedge_mapper_<version>_amd64.deb | tar -xf data.tar.xz
Which should give you usr
and/or lib
directory where you can find binaries.
After extracting all packages, you should now adjust permissions on those files:
chown root:root /usr/bin/tedge
chown root:root /usr/bin/tedge_agent
chown root:root /usr/bin/tedge_mapper
and then move your binaries to the appropriate directory, eg:
mv ./lib/ ./bin/ /
If building from source
If you have built the binaries from source you should install them on the target in: /usr/bin/
.
systemd
unit files for tedge_mapper
and tedge_agent
can be found in the repository at configuration/init/systemd/tedge-*
and should be installed on the target in: lib/systemd/system/tedge-*
.
Configuring the system and systemd-units
thin-edge.io
relies on certain system configuration and systemd process management, when installing from deb package all of that is setup automatically but with manual installation a set of steps has to be performed.
On most Linux distribution it should suffice to execute them as root
to do the setup, but in some cases (eg, your system uses useradd
instead of adduser
package) more detailed instructions are documented:
After following steps for all the components installed thin-edge.io
should be operational.
How to restart your thin-edge.io device
If your device is running thin-edge.io, you can restart it from the cloud. This guide shows how to trigger a restart operation from different cloud providers.
Cumulocity
Go to your device's homepage on c8y, and find the "Control" button.
In the top right corner, you will find the "More" button, click it and select, "Restart device".
Azure
TBD
Apama Software Management Plugin
The apama plugin can be used to install and manage apama artefacts. This plugin can be used to install an apama project on a device as well as inject monitor files into an already installed project.
Download and Install Apama Plugin
Note: This plugin expects an apama installation on the device which is managed as a System V service. If Apama is not installed or if the System V init script is not installed, follow the Apama installation instructions here before installing/using the apama plugin.
Apama plugin is delivered as a debian package which can be downloaded from the releases section of thin-edge.io repository on GitHub.
Example command for downloading the 0.5.0
version of the plugin for armhf
architecture (Adjust the version and architecture values as per your requirements):
curl -LJO https://github.com/thin-edge/thin-edge.io/releases/download/0.5.0/tedge_apama_plugin_0.5.0_armhf.deb
Once the debian package is downloaded, install it with the dpkg
command:
sudo dpkg -i tedge_apama_plugin_0.5.0_armhf.deb
Once the plugin is installed on the device, you can install apama projects and mon files using Cumulocity software management feature.
Install Apama artefacts from Cumulocity
Before an apama project or a mon files can be installed on the device using the software management feature in Cumulocity, these project files or monitor files need to be added to the Cumulocity software repository first.
There's some naming convention that you need to follow while creating software entries for apama artefacts in the software repository.
For apama projects:
- Name must be suffixed with
::project
as inmy-demo-project::project
- Version must be suffixed with
::apama
as in1.0::apama
or just::apama
if you don't need a version number. - The uploaded binary must be a
zip
file that contains theproject
directory. If a directory namedproject
is not found at the root level in the zip, it's considered invalid.
For apama monitor file:
- Name must be suffixed with
::mon
as inMyDemoMonitor::mon
- Version must be suffixed with
::apama
as in2.0::apama
or just::apama
if you don't need a version number. - The uploaded binary must be a
mon
file with.mon
extension
Once the software modules are added in the software repository, these can be installed on the device just like any other software from the Software
tab of the device in Cumulocity device UI.
Testing Apama Plugin
Here are some test apama artefacts that you can use to test this plugin:
- Demo apama project zip
- Demo apama monitor file
Add these binaries as software packages in Cumulocity software repository by following the instructions in the previous section. Once added, this apama project can be installed on any target device. You can test if the project got successfully installed by running the following Apama command:
/opt/softwareag/Apama/bin/apama_env engine_inspect -m
And you can expect an output like this:
Monitors
========
Name Num Sub Monitors
---- ----------------
TedgeDemoMonitor 1
You can find more information on this apama project here
Once the project installation is validated successfully, you can install the demo monitor file as well just like you installed the project from Cumulocity.
Once the installation succeeds, you can validate if this monitor file got injected successfully by running the same engine_inspect
command and you should get an output like this with a second monitor in the list named TedgeTestMonitor
:
Monitors
========
Name Num Sub Monitors
---- ----------------
TedgeDemoMonitor 1
TedgeTestMonitor 1
How to change temp path
The tedge
command can be used to change the temp path. By default the directory used is /tmp
.
To change the temp path, run:
sudo tedge config set tmp.path /path/to/directory
Note that the directory must be available to tedge-agent
user and tedge-agent
group.
For example:
# create a directory (with/without sudo)
mkdir ~/tedge_tmp_dir
# give ownership to tedge-agent
sudo chown tedge-agent:tedge-agent ~/tedge_tmp_dir
# reconnect to cloud.
To revert the path back to its default value:
sudo tedge config unset tmp.path
How to use thin-edge.io with your preferred init system
thin-edge.io works seamlessly with systemd
on the CLI commands tedge connect
and tedge disconnect
.
However, not all OS support systemd
.
You might want to use another init system like OpenRC
, BSD
, init.d
with thin-edge.io.
This guide explains how to configure thin-edge.io to use another init system.
How to set a custom init system configuration
Create a file system.toml
owned by root:root
in /etc/tedge
directory.
sudo touch /etc/tedge/system.toml
Open your editor and copy and paste the following toml contents. This is an example how to configure OpenRC as the init system for thin-edge.io. We have example configurations for BSD, OpenRC, and systemd under thin-edge.io/configuration/contrib/system.
[init]
name = "OpenRC"
is_available = ["/sbin/rc-service", "-l"]
restart = ["/sbin/rc-service", "{}", "restart"]
stop = ["/sbin/rc-service", "{}", "stop"]
enable = ["/sbin/rc-update", "add", "{}"]
disable = ["/sbin/rc-update", "delete", "{}"]
is_active = ["/sbin/rc-service", "{}", "status"]
Then, adjust the values with your preferred init system. To get to know the rules of the configuration file, please refer to Init System Configuration File.
After you finish creating your own configuration file, it's good to limit the file permission to read-only.
sudo chmod 444 /etc/tedge/system.toml
Now tedge connect
and tedge disconnect
will use the init system that you specified!
Default settings
If the custom configuration file /etc/tedge/system.toml
is not in place,
tedge connect
and tedge disconnect
will use /bin/systemctl
as the init system.
Reference document
How to monitor health of tedge daemons
The health of tedge daemon processes like tedge-mapper
, tedge-agent
etc can be monitored via MQTT.
These daemons expose MQTT health endpoints which you can query to check if the process is still active or not.
The health endpoints conform to the following topic scheme, listening for health check requests:
tedge/health-check/<tedge-daemon-name>
expecting empty messages, triggering the health check.
The daemon will then respond back on the topic:
tedge/health/<tedge-daemon-name>
with the following payload:
{ "status": "up", "pid": <process id of the daemon> }
All daemons will also respond to health checks sent to the common health check endpoint tedge/health-check
.
Supported MQTT topic endpoints
The following endpoints are currently supported by various tedge daemons:
tedge/health/tedge-agent
tedge/health/tedge-mapper-c8y
tedge/health/tedge-mapper-az
tedge/health/tedge-mapper-collectd
All future tedge daemons will also follow the same topic naming scheme convention.
Mosquitto bridge health endpoints
The mosquitto bridge clients connecting thin-edge devices to the respective cloud platforms also report their health status as retained messages to tedge/health/<mosquitto-cloud-bridge>
topics.
The health check messages published by these clients are just numeric values 1
or 0
, indicating active and dead bridge clients respectively.
Here are the health endpoints of curently supported clouds, bridged with mosquitto:
Cloud | Health topic |
---|---|
Cumulocity | tedge/health/mosquitto-c8y-bridge |
Azure | tedge/health/mosquitto-az-bridge |
Explicit health check requests via tedge/health-check
topics is not supported by these bridge clients.
Since the health status messages are sent as retained messages, just subscribing to these health topics is sufficient to get the latest status.
Enabling systemd watchdog for thin-edge services
Introduction
The systemd watchdog feature enables systemd to detect when a service is unhealthy or unresponsive and attempt to fix it by restarting that service. To detect if a service is healthy or not, systemd relies on periodic health notifications from that service at regular intervals. If the service fails to send that notification within a time threshold, then systemd will assume that service to be unhealthy and restart it.
This document describes how the systemd watchdog mechanism can be enabled for thin-edge services.
Enabling the systemd watchdog feature for a tedge service
Enabling systemd watchdog for a thin-edge.io
service (tedge-agent, tedge-mapper-c8y/az/collectd) is a two-step process.
Step 1: Enable the watchdog feature in the systemd service file
For example, to enable the watchdog feature for tedge-mapper-c8y
service,
update the systemd service file as shown below:
Note: The systemd service file for tedge services are usually present in
/lib/systemd/system
directory, like/lib/systemd/system/tedge-mapper-c8y.service
.
Add tedge-watchdog.service
as an After
service dependency under [Unit]
section.
Add the watchdog interval as WatchdogSec=30
under [Service]
section.
Update the restart condition as Restart=always
under [Service]
section.
Here is the updated service file for tedge-mapper-c8y
service:
[Unit]
Description=tedge-mapper-c8y converts Thin Edge JSON measurements to Cumulocity JSON format.
After=syslog.target network.target mosquitto.service tedge-watchdog.service
[Service]
User=tedge-mapper
ExecStart=/usr/bin/tedge_mapper c8y
Restart=always
RestartPreventExitStatus=255
WatchdogSec=30
Step 2: Start the tedge-watchdog
service
The tedge-watchdog
service is responsible for periodically checking the health of
all tedge services for which the watchdog feature is enabled,
and send systemd watchdog notifications on their behalf to systemd.
Start and enable the tedge-watchdog
service as follows:
systemctl start tedge-watchdog.service
systemctl enable tedge-watchdog.service
Once started, the tedge-watchdog
service will keep checking the health of the monitored tedge services
by periodically sending health check messages to them within their configured WatchdogSec
interval.
The health check request for service is published to tedge/health-check/<service-name>
topic and
the health status response from that service is expected on tedge/health/<service-name>
topic.
Once the health status response is received from a particular service,
the tedge-watchdog
service will send the systemd notification to systemd on behalf of that monitored service.
Debugging
One can observe the message exchange between the service
and the watchdog
by subscribing to tedge/health/#
and tedge/health-check/#
topics.
For more info check here
Note: If the watchdog service does not send the notification to the systemd within
WatchdogSec
interval for a service, then systemd restarts that service by killing the old process and spawning a new one to replace it.
Note: Here is an example about using
systemd watchdog
feature.
How to add custom fragments to Cumulocity
Default fragments
By default your device will send the following information to Cumulocity:
"c8y_Agent": {
"name": "thin-edge.io",
"version": "x.x.x"
}
You can change the name
value using the tedge
command as follows:
sudo tedge config set device.type VALUE
Custom fragments
If you wish to add more fragments to Cumulocity, you can do so by populating /etc/tedge/device/inventory.json
An example inventory.json
looks something like this:
{
"c8y_RequiredAvailability": {
"responseInterval": 5
},
"c8y_Firmware": {
"name": "raspberrypi-bootloader",
"version": "1.20140107-1",
"url": "31aab9856861b1a587e2094690c2f6e272712cb1"
},
"c8y_Hardware": {
"model": "BCM2708",
"revision": "000e",
"serialNumber": "00000000e2f5ad4d"
}
}
To see the changes you need to restart the tedge-mapper. If you're using systemctl you can do:
sudo systemctl restart tedge-mapper-c8y.service
In the Cumulocity UI this will looks something like this:
For information on which fragments Cumulocity supports please see the Cumulocity API docs.
How to retrieve logs with the log plugin
You can now access any type of logs directly from your Cumulocity UI, using the
c8y_log_plugin
daemon. To get started install the c8y_log_plugin
via the
debian package.
If you have not installed via the debian package, make sure you have the following:
- run
sudo c8y_log_plugin --init
- a
c8y-log-plugin.service
file in/lib/systemd/system/c8y-log-plugin.service
- a
c8y_log_plugin
binary in/usr/bin/c8y_log_plugin
- check if
/etc/tedge/c8y/c8y-log-plugin.toml
was created
After the device is connected to Cumulocity, this plugin needs to be started and enabled as follows:
sudo systemctl start c8y-log-plugin
sudo systemctl enable c8y-log-plugin
If you go to Cumulocity, you should see that you are able to see the logs tab
and you can request "software-management" logs.
However, you are not limited to only thin-edge logs.
To add a new log type, you need to edit the c8y-log-plugin.toml
in /etc/tedge/c8y/c8y-log-plugin.toml
sudo nano /etc/tedge/c8y/c8y-log-plugin.toml
In this toml file you specify the log type and log path of the logs wished to be retrieved from Cumulocity UI. For example, if you wish to request thin-edge software logs and mosquitto logs an example toml file would be:
files = [
{ type = "software-management", path = "/var/log/tedge/agent/software-*" },
{ type = "mosquitto", path = "/var/log/mosquitto/mosquitto.log" }
]
Note that path
need not be a complete path. It can be a full path to a log
file or a glob pattern.
For example the "software-management" type is a glob pattern that groups
any file inside "/var/log/tedge/agent/" that starts with "software-".
The type
key in the toml is the name of the log with you will see in the
Cumulocity UI:
How to use Cumulocity Custom SmartREST 2.0 Templates
Custom SmartRest Templates can be used to extend the functionality of a device to support more operations than what the static SmartREST templates offer.
thin-edge.io
supports subscription to custom templates as documented here.
For every template that the device uses, it must publish all data to s/uc/<template-name>
topic and subscribe to s/dc/<template-name>
to receive data from the cloud, based on that template.
When these templates are configured with thin-edge.io
, subscriptions to all these relevant topics on Cumulocity cloud will be done by thin-edge.io
internally.
Local processes on the device can access these templates on the local MQTT broker by simply publishing to c8y/s/uc/<template-name>
and subscribing to c8y/s/dc/<template-name>
topics (note the c8y/
prefix in topics).
A template named $TEMPLATE_NAME
requires the following subscriptions to be added when connecting to Cumulocity:
s/dc/$TEMPLATE_NAME
s/uc/$TEMPLATE_NAME
This is not done automatically and the custom templates have to be declared using the tedge
command.
Checking existing templates
tedge config get c8y.smartrest.templates
Add new template to thin-edge configuration
To add new template to thin-edge.io
the tedge config
cli tool can be used as following:
tedge config set c8y.smartrest.templates template-1,template-2
Note: To add/append a new template to a device that's already configured with some, all the existing templates should also be declared along with the new one in the
tedge config set
command. For example, iftemplate-1
is already configured on the device, as following:$ tedge config get c8y.smartrest.templates ["template-1"]
To add new template to the set it is required to include current template, so the command would look like this:
tedge config set c8y.smartrest.templates template-1,template-2
Now when we get the configuration the both templates will be there:
$ tedge config get c8y.smartrest.templates ["template-1", "template-2"]
Removing templates from configuration
To remove all the templates, the unset
subcommand can used as follows:
tedge config unset c8y.smartrest.templates
To remove one of existing templates you can overwrite the existing c8y.smartrest.templates
with the new set which doesn't contain the unwanted template.
$ tedge config get c8y.smartrest.templates
["template-1", "template-2"]
tedge config set c8y.smartrest.templates template-1
$ tedge config get c8y.smartrest.templates
["template-1"]
How to manage configuration files with Cumulocity
With thin-edge.io
, you can manage config files on a device by using the Cumulocity configuration management feature as a part of Device Management.
If you are new to the Cumulocity Configuration Management feature, we recommend you to read the Cumulocity user guide along with this how-to guide.
Installation of c8y_configuration_plugin
To enable the feature, first you need to install the c8y_configuration_plugin
binary on your device.
Using the get-thin-edge_io.sh
script on Debian based distributions (Recommended)
If your device supports apt
as a package manager,
you can install all thin-edge.io
packages including the c8y_configuration_plugin
by the get-thin-edge_io.sh
script.
If you have already used the get-thin-edge_io.sh
script,
this package is installed, by default.
curl -fsSL https://raw.githubusercontent.com/thin-edge/thin-edge.io/main/get-thin-edge_io.sh | sudo sh -s
Using the c8y_configuration_plugin
Debian package on Debian based distributions
For Debian based distributions, we provide the c8y_configuration_plugin_<version>_<arch>.deb
package as a release asset here.
In case that you didn't use the get-thin-edge_io.sh
script, you can download the c8y_configuration_plugin_<version>_<arch>.deb
package on our Releases and install it.
sudo apt install ./path/to/package/c8y_configuration_plugin_<version>_<arch>.deb
Extracting from debian package on non-Debian based distributions
Get the c8y_configuration_plugin_<version>_<arch>.deb
from our Releases.
Then, run this command in the directory where the package is stored.
ar -x ./c8y_configuration_plugin_<version>_<arch>.deb | tar -xf ./data.tar.xz
The binary is extracted in <current directory>/usr/bin
.
For more details, refer to our guide Extracting from debian package.
Building from sources
Follow our guide Buiding thin-edge.io and Building from source.
cargo build --release -p c8y_configuration_plugin
A systemd
unit file for c8y_configuration_plugin
can be found in the repository at configuration/init/systemd/c8y-configuration-plugin.service
and should be installed on the target in: /lib/systemd/system/c8y-configuration-plugin.service
.
sudo cp <repository_root>/configuration/init/systemd/c8y-configuration-plugin.service /lib/systemd/system/c8y-configuration-plugin.service
Get started
Before starting anything, make sure your device is connected to Cumulocity.
Step 0
Unless you installed c8y_configuration_plugin
using the debian package,
you need one additional step to initialize the plugin. Run this command.
sudo c8y_configuration_plugin --init
Step 1
Open the file /etc/tedge/c8y/c8y-configuration-plugin.toml
and add entries for the configuration files that you'd like to manage from Cumulocity cloud in the following format:
files = [
{ path = '/etc/tedge/tedge.toml', type = 'tedge.toml'},
{ path = '/etc/tedge/mosquitto-conf/c8y-bridge.conf', type = 'c8y-bridge.conf' },
{ path = '/etc/tedge/mosquitto-conf/tedge-mosquitto.conf', type = 'tedge-mosquitto.conf' },
{ path = '/etc/mosquitto/mosquitto.conf', type = 'mosquitto.conf' },
{ path = '/etc/tedge/c8y/example.txt', type = 'example', user = 'tedge', group = 'tedge', mode = 0o444 }
]
path
is the full path to the configuration file.type
is a unique alias for each file entry which will be used to represent that file in Cumulocity UI.user
,group
andmode
are UNIX file permission settings to be used to create a configuration file. If not provided, the files will be created withroot
user. If the file exists already, its ownership will be retained.
For more details on this configuration file format, refer to the reference guide.
Note: You can also configure the
c8y-configuration-plugin.toml
from the cloud later.
Step 2
Start the configuration plugin process and enable it on boot by systemctl
(recommended).
sudo systemctl start c8y-configuration-plugin.service
sudo systemctl enable c8y-configuration-plugin.service
Alternatively, you can run the process directly.
sudo c8y_configuration_plugin
Step 3
Navigate to your Cumulocity Device Management and the desired device. Open its Configuration tab.
You can find c8y-configuration-plugin
and more are listed as supported configuration types, as declared in the plugin configuration file in step 1.
This is the configuration file of c8y_configuration_plugin
, where you can add file entries that you want to manage with Cumulocity.
Update c8y-configuration-plugin
from Cumulocity
To update any configuration file, create a local copy of that config file and then upload that file to the Cumulocity configuration repository with the appropriate configuration type.
The c8y-configuration-plugin.toml
file can also be updated from the cloud in a similar manner to add/remove further configuration file entries. The updated TOML file has to be uploaded with the configuration type: c8y-configuration-plugin.
Then, go back to the Configuration tab of your desired device in Cumulocity.
Click on the config file entry from the DEVICE SUPPORTED CONFIGURATIONS files list. You can choose the file that you uploaded from the AVAILABLE SUPPORTED CONFIGURATIONS section, and then apply that file to your device by clicking on the Send configuration to device button.
After the operation created gets marked SUCCESSFUL, reload the page. Then you can find new supported configuration types as you defined.
Note: All configuration updates are notified over
tedge/configuration_change/<config-type>
MQTT topic, giving the opportunity to software components installed on the device or a child device to react to these updates. For more details, refer to the Notifications section of the specification.
To get to know more about the c8y_configuration_plugin
, refer to Specifications of Device Configuration Management using Cumulocity.
How to install thin-edge.io manually with OpenRC
This tutorial will demo how to install thin-edge.io manually for a non-debian linux distribution that uses OpenRC as its init system. The aim of this tutorial is to show how to get started with Cumulocity IoT even if your current system is not supported by the default installation of thin-edge.io. For reference, this tutorial is done with the following system specs:
- Operating System: Linux gentoo
- Linux kernel version: 5.15.41-gentoo-x86_64
- Architecture: x86_64
- Init system: OpenRC
Prerequisites
If you wish to build binaries from source, you will to install rust from https://www.rust-lang.org/tools/install.
You will also need to have mosquitto installed. Check your package manager for an available version, or you can building from source. (If you build from source, add WITH_TLS=yes
flag to make).
Building from source
To build from source, download the Source code (zip) from the latest releases page.
Once downloaded, unzip it and enter the thin-edge.io directory and build the project with the --release
flag:
unzip thin-edge*.zip
cd thin-edge*/
cargo build --release
This will build the thin-edge.io binaries in the target/release directory. You will then need to move each binary to /usr/bin
or an equivalent location in $PATH.
A minimal thin-edge.io installation requires three components:
- tedge CLI
- tedge agent
- tedge mapper
sudo mv target/release/tedge /usr/bin
sudo mv target/release/tedge_agent /usr/bin
sudo mv target/release/tedge_mapper /usr/bin
You should now have access to the tedge
, tedge_agent
and tedge_mapper
binaries.
Extracting binaries from debian files
Download the debian files from the latest releases page. For a minimal configuration of thin-edge.io with Cumulocity IoT, you will need to download:
- tedge_{VERSION}_amd64.deb
- tedge_agent_{VERSION}_amd64.deb
- tedge_mapper_{VERSION}_amd64.deb
Next, unpack each deb file and copy the binary to /usr/bin
.
For tedge
debian package do:
ar -x tedge_*_amd64.deb | tar -xf data.tar.xz
This unpacks two directories usr/bin/
, move its contents to /usr/bin
sudo mv usr/bin/tedge /usr/bin
Note: Do the same for tedge_agent and tedge_mapper debian packages.
Step 1: Creating the tedge user
The next step is to create the tedge user. This is normally taken care by the debian package for the tedge
CLI tool.
To do this in Gentoo, for example, you can:
sudo groupadd --system tedge
sudo useradd --system --no-create-home -c "" -s /sbin/nologin -g tedge tedge
Now that we have created the tedge user, we need to allow the tedge user to call commands with sudo
without requiring a password:
sudo echo "tedge ALL = (ALL) NOPASSWD: /usr/bin/tedge, /etc/tedge/sm-plugins/[a-zA-Z0-9]*, /bin/sync, /sbin/init" >/etc/sudoers.d/tedge
Next, create the files and directories required by thin-edge.io and restart mosquitto too.
sudo rc-service mosquitto stop
sudo tedge --init
sudo rc-service mosquitto start
sudo tedge_agent --init
sudo tedge_mapper --init c8y
This should show the following output:
Note: if you do not restart mosquitto you will see a Connection refused error. Do not worry, this error can be ignored.
Ensure that running the init has created the following files and directories in /etc/tedge
:
Step 3: Creating mosquitto bridge
To create the mosquitto bridge simply run:
sudo echo "include_dir /etc/tedge/mosquitto-conf" >> /etc/mosquitto/mosquitto.conf
You can test that mosquitto
works by running:
sudo mosquitto --config-file /etc/mosquitto/mosquitto.conf
Step 4: Creating OpenRC service files
You will need service files for tedge_agent and tedge_mapper. For example:
Note that, for Cumulocity IoT, the
tedge connect
command expects three service files called: mosquitto, tedge-agent and tedge-mapper-c8y
For the tedge-agent
service an example file is the following:
FILE: /etc/init.d/tedge-agent
#!/sbin/runscript
start() {
ebegin "Starting tedge-agent"
start-stop-daemon --user tedge --start --background --exec tedge_agent
eend $?
}
stop() {
ebegin "Stopping tedge-agent"
start-stop-daemon --stop --exec tedge_agent
eend $?
}
For the tedge-mapper-c8y
service an example file is the following:
FILE: /etc/init.d/tedge-mapper-c8y
#!/sbin/runscript
start() {
ebegin "Starting tedge-mapper-c8y"
start-stop-daemon --user tedge --start --background --exec tedge_mapper c8y
eend $?
}
stop() {
ebegin "Stopping tedge-mapper-c8y"
start-stop-daemon --stop --exec tedge_mapper
eend $?
}
sudo chmod +x /etc/init.d/tedge-agent
sudo chmod +x /etc/init.d/tedge-mapper-c8y
Next, we need to add a system.toml
to /etc/tedge/
, telling it to use OpenRC. To do this create the following file:
FILE: /etc/tedge/system.toml
[init]
name = "OpenRC"
is_available = ["/sbin/rc-service", "-l"]
restart = ["/sbin/rc-service", "{}", "restart"]
stop = ["/sbin/rc-service", "{}", "stop"]
enable = ["/sbin/rc-update", "add", "{}"]
disable = ["/sbin/rc-update", "delete", "{}"]
is_active = ["/sbin/rc-service", "{}", "status"]
Limit the file's permission to read only:
sudo chmod 444 /etc/tedge/system.toml
Finally, add the thin-edge.io services to start after boot:
sudo rc-update add tedge-agent default
sudo rc-update add tedge-mapper-c8y default
We are finally ready to connect to Cumulocity!
Developer Documentation
The Developer Documentation for everybody who is interested in extending thin-edge.io. For more deeper interested users this also might be interesting, even if not required to operate thin-edge.io.
Architecture
Thin-edge.io is an open-source framework to develop lightweight, smart and secure connected devices.
Cloud agnostic, thin-edge.io provides the foundations for cloud connectivity and device management, a set of pre-packaged modules, plug & play connectors to cloud platforms, device certificate management, monitoring as well as built-in software and firmware management.
On top of these foundations, telemetry applications can be built using a combination of components provided by various IoT actors. The features provided by these components can be as diverse as low-level connectivity to IoT protocols, event-stream analytics, machine-learning-powered systems, or application specific processors.
Built around an extensible architecture, thin-edge.io can be extended in various programming languages. Here are the key aspects of the thin-edge.io architecture:
-
The components are processes exchanging messages over an MQTT bus.
-
The MQTT bus is connected to the cloud, forwarding the messages published on cloud specific topics.
-
A canonical data format let the components exchange telemetry data independently of the connected cloud. This is an optional feature, and the components are free to also use cloud specific data formats.
-
The mapper processes are responsible for translating the canonical data format into cloud specific messages and vice versa.
Thin Edge JSON format
Thin Edge JSON is a lightweight format used in thin-edge.io
to represent measurements data.
This format can be used to represent single-valued measurements, multi-valued measurements
or a combination of both along with some auxiliary data like the timestamp at which the measurement(s) was generated.
Single-valued measurements
Simple single-valued measurements like temperature or pressure measurement with a single value can be expressed as follows:
{
"temperature": 25
}
where the key represents the measurement type, and the value represents the measurement value. The keys can only have alphanumeric characters, and the "_" (underscore) character but must not start with an underscore. The values can only be numeric. String, Boolean or other JSON object values are not allowed.
Multi-valued measurements
A multi-valued measurement is a measurement that is comprised of multiple values. Here is the representation of a
three_phase_current
measurement that consists of L1
, L2
and L3
values, representing the current on each phase:
{
"three_phase_current": {
"L1": 9.5,
"L2": 10.3,
"L3": 8.8
}
}
where the key is the top-level measurement type and value is a JSON object having further key-value pairs representing each aspect of the multi-valued measurement. Only one level of nesting is allowed, meaning the values of the measurement keys at the inner level can only be numeric values. For example, a multi-level measurement as follows is NOT valid:
{
"three_phase_current": {
"phase1": {
"L1": 9.5
},
"phase2": {
"L2": 10.3
},
"phase3": {
"L3": 8.8
}
}
}
because the values at the second level(phase1
, phase2
and phase3
) are not numeric values.
Grouping measurements
Multiple single-valued and multi-valued measurements can be grouped into a single Thin Edge JSON message as follows:
{
"temperature": 25,
"three_phase_current": {
"L1": 9.5,
"L2": 10.3,
"L3": 8.8
},
"pressure": 98
}
The grouping of measurements is usually done to represent measurements collected at the same instant of time.
Auxiliary measurement data
When thin-edge.io
receives a measurement, it will add a timestamp to it before any further processing.
If the user doesn't want to rely on thin-edge.io
generated timestamps,
an explicit timestamp can be provided in the measurement message itself by adding the time value as a string
in ISO 8601 format using time
as the key name, as follows:
{
"time": "2020-10-15T05:30:47+00:00",
"temperature": 25,
"location": {
"latitude": 32.54,
"longitude": -117.67,
"altitude": 98.6
},
"pressure": 98
}
The time
key is a reserved keyword and hence can not be used as a measurement key.
The time
field must be defined at the root level of the measurement JSON and not allowed at any other level,
like inside the object value of a multi-valued measurement.
Non-numeric values like the ISO 8601 timestamp string are allowed only for such reserved keys and not for regular measurements.
Here is the complete list of reserved keys that has special meanings inside the thin-edge.io
framework
and hence must not be used as measurement keys:
Key | Description |
---|---|
time | Timestamp in ISO 8601 string format |
type | Internal to thin-edge.io |
Sending measurements to thin-edge.io
The thin-edge.io
framework exposes some MQTT endpoints that can be used by local processes
to exchange data between themselves as well as to get some data forwarded to the cloud.
It will essentially act like an MQTT broker against which you can write your application logic.
Other thin-edge processes can use this broker as an inter-process communication mechanism by publishing and
subscribing to various MQTT topics.
Any data can be forwarded to the connected cloud-provider as well, by publishing the data to some standard topics.
All topics with the prefix tedge/
are reserved by thin-edge.io
for this purpose.
To send measurements to thin-edge.io
, the measurements represented in Thin Edge JSON format can be published
to the tedge/measurements
topic.
Other processes running on the thin-edge device can subscribe to this topic to process these measurements.
If the messages published to this tedge/measurements
topic is not a well-formed Thin Edge JSON,
then that message won’t be processed by thin-edge.io
, not even partially,
and an appropriate error message on why the validation failed will be published to a dedicated tedge/errors
topic.
The messages published to this topic will be highly verbose error messages and can be used for any debugging during development.
You should not rely on the structure of these error messages to automate any actions as they are purely textual data
and bound to change from time-to-time.
More topics will be added under the tedge/
topic in future to support more data types like events, alarms etc.
So, it is advised to avoid any sub-topics under tedge/
for any other data exchange between processes.
Here is the complete list of topics reserved by thin-edge.io
for its internal working:
Topic | Description |
---|---|
tedge/ | Reserved root topic of thin-edge.io |
tedge/measurements | Topic to publish measurements to thin-edge.io |
tedge/measurements/<child-id> | Topic to publish measurements to thin-edge.io 's child device |
tedge/errors | Topic to subscribe to receive any error messages emitted by thin-edge.io while processing measurements |
Sending measurements to the cloud
The thin-edge.io
framework allows users forward all the measurements generated and published to
tedge/measurements
MQTT topic in the thin-edge device to any IoT cloud provider that it is connected to,
with the help of a mapper component designed for that cloud.
The responsibility of a mapper is to subscribe to the tedge/measurements
topic to receive all incoming measurements
represented in the cloud vendor neutral Thin Edge JSON format, to a format that the connected cloud understands.
Refer to Cloud Message Mapper Architecture for more details on the mapper component.
The tedge-mapper
The tedge-mapper is a key concept to support multiple cloud providers. The purpose is to translate messages written using the cloud-agnostic Thin Edge JSON format, into cloud-specific messages.
The tedge-mapper is composed of multiple cloud-specific mappers, such as Cumulocity mapper and Azure mapper.
Each mapper is responsible for its dedicated cloud.
These specific mappers are launched by the respective tedge connect
command.
For instance, tedge connect c8y
establishes a bridge to Cumulocity and launches a Cumulocity mapper
that translates the messages in the background.
A mapper subscribes to the reserved MQTT topic tedge/measurements
with the QoS level 1 (at least once).
The messages that arrive in the mapper should be formed in the Thin Edge JSON format.
The mapper verifies whether the arrived messages are correctly formatted,
in case the verification fails, the mapper publishes a corresponded error message
on the topic tedge/errors
with the QoS level 1 (at least once).
When the mapper receives a correctly formatted message, the message will be translated into a cloud-specific format.
Cumulocity mapper
The Cumulocity mapper translates Thin Edge JSON into Cumulocity's JSON via MQTT.
The translated messages are published on the topic c8y/measurement/measurements/create
from where they are forwarded to Cumulocity.
This mapper is launched by the tedge connect c8y
command, and stopped by the tedge disconnect c8y
command.
Example in Thin Edge JSON:
{
"temperature": 23
}
Translated into JSON via MQTT by the Cumulocity mapper:
{
"type": "ThinEdgeMeasurement",
"time": "2021-04-22T17:05:26.958340390+00:00",
"temperature": {
"temperature": {
"value": 23
}
}
}
You can see the Cumulocity mapper added the three things which are not defined before translation.
type
is added.time
is added.- Another hierarchy level is added, as required by the cumulocity data model.
String
temperature
is used as fragment and series.
(1) The type
is a mandatory field in the Cumulocity's JSON via MQTT manner,
therefore, the Cumulocity mapper always adds ThinEdgeMeasurement
as a type.
This value is not configurable by users.
(2) time
will be added by the mapper only when it is not specified in a received Thin Edge JSON message.
In this case, the mapper uses the device's local timezone. If you want another timezone, specify the time filed in Thin Edge JSON.
(3) The mapper uses a measurement name ("temperature" in this example) as both a fragment type and a fragment series in Cumulocity's measurements.
After the mapper publishes a message on the topic c8y/measurement/measurements/create
,
the message will be transferred to the topic measurement/measurements/create
by the MQTT bridge.
For child devices
The Cumulocity mapper collects measurements not only from the main device but also from child devices.
These measurements are collected under the tedge/measurements/<child-id>
topics and forwarded to Cumulocity to corresponding child devices created under the thin-edge.io
parent device.
(<child-id>
is your desired child device ID.)
The mapper works in the following steps.
- When the mapper receives a Thin Edge JSON message on the
tedge/measurements/<child-id>
topic, the mapper sends a request to create a child device under thethin-edge.io
parent device. The child device is named after the<child-id>
topic name, and the type isthin-edge.io-child
. - Publish corresponded Cumulocity JSON measurements messages over MQTT.
- The child device is created on receipt of the very first measurement for that child device.
If the incoming Thin Edge JSON message (published on tedge/measurements/child1
) is as follows,
{
"temperature": 23
}
it gets translated into JSON via MQTT by the Cumulocity mapper.
{
"type":"ThinEdgeMeasurement",
"externalSource":{
"externalId":"child1",
"type":"c8y_Serial"
},
"time":"2013-06-22T17:03:14+02:00",
"temperature":{
"temperature":{
"value":23
}
}
}
Azure IoT Hub mapper
Note: Child device measurements are not supported yet on Azure IoT Hub.
The Azure IoT Hub mapper takes messages formatted in the Thin Edge JSON as input.
It validates if the incoming message is correctly formatted Thin Edge JSON, then outputs the message.
The validated messages are published on the topic az/messages/events/
from where they are forwarded to Azure IoT Hub.
This mapper is launched by the tedge connect az
command, and stopped by the tedge disconnect az
command.
The Azure IoT Hub Mapper processes a message in the following ways.
- Validates if it is a correct Thin Edge JSON message or not.
- Validates the incoming message size is below 255 KB. The size of all device-to-cloud messages must be up to 256 KB. The mapper keeps 1 KB as a buffer for the strings added by Azure.
- (default) Adds a current timestamp if a timestamp is not included in an incoming message. To stop this behavior, please refer to the following instruction.
So, if the input is below,
{
"temperature": 23
}
the output of the mapper is
{
"temperature": 23,
"time": "2021-06-01T17:24:48.709803664+02:00"
}
Configure whether adding a timestamp or not
However, if you don't want to add a timestamp in the output of Azure IoT Hub Mapper, you can change the behavior by running this:
sudo tedge config set az.mapper.timestamp false
After changing the configuration, you need to restart the mapper service by
sudo systemctl restart tedge-mapper-az.service
Error cases
When some error occurs in a mapper process, the mapper publishes a corresponded error message
on the topic tedge/errors
with the QoS level 1 (at least once).
Here is an example if you publish invalid Thin Edge JSON messages on tedge/measurements
:
$ tedge mqtt pub tedge/measurements '{"temperature": 23,"pressure": 220'
$ tedge mqtt pub tedge/measurements '{"temperature": 23,"time": 220}'
Then, you'll receive error messages from the mapper on the topic tedge/errors
:
$ tedge mqtt sub tedge/errors
[tedge/errors] Invalid JSON: Unexpected end of JSON: {"temperature":23,"pressure":220
[tedge/errors] Not a timestamp: the time value must be an ISO8601 timestamp string in the YYYY-MM-DDThh:mm:ss.sss.±hh:mm format, not a number.
Topics used by tedge-mapper
-
Incoming topics
tedge/measurements
tedge/measurements/<child-id>
(for Cumulocity)
-
Outgoing topics
tedge/errors
(for errors)c8y/measurement/measurements/create
(for Cumulocity)az/messages/events/
(for Azure IoT Hub)
Software Management with thin-edge.io
With thin-edge.io you can ease the burden of managing packages on your device. Software Management operates end to end from a cloud down to the OS of your device and reports statuses accordingly.
Software management components
Software Management uses the following 3 components to perform software operations: Cloud Mapper, Agent, and Software Management Plugin.
You can find the diagrams which explain how those 3 components interact with each other from Software Management Agent Specification.
Cloud Mapper
The Cloud Mapper converts from/to cloud-specific format to/from cloud-agnostic format. It communicates with the dedicated IoT cloud platform and the Tedge Agent.
Tedge Agent
The Tedge Agent addresses cloud-agnostic software management operations e.g. listing current installed software list, software update, software removal. Also, the Tedge Agent calls an SM Plugin(s) to execute an action defined by a received operation.
The key points are that the Tedge Agent is always generic in cloud platforms and software types, and Cloud Mapper handles cloud-specific actions.
Software Management Plugin
The Software Management Plugin is dedicated to defining the behaviour of software actions (list, update, remove) per software type (apt, docker, etc.)
Related documents
- How to install and enable software management?
- Manage my device software
- Write my software management plugin
- The Software Management Plugin API
- Software Management Specification
Architecture FAQ
Design principles
The primary goal of thin-edge.io is to simplify the connection of edge devices to the cloud by providing a secure and reliable cloud connectivity as well as a device management agent. The primary goal of thin-edge.io is the ability to build IoT applications around a large diversity of components provided by independent actors.
For that purpose, thin-edge.io focuses on:
- Interoperability - Thin-edge.io lets the users integrate components producing or consuming telemetry data, northbound with cloud platforms, southbound with sensors as well as for east-west communication between analytics components.
- Flexibility - Thin-edge.io lets users integrate component provided by different IoT actors, not even originally designed with thin-edge.io in-mind, using various technologies and programming languages.
- Security - Thin-edge.io provides a secure and stable foundation for cloud connections, software/firmware updates, and remote device management.
- Reliability - Thin-edge.io components can survive in chaotic environments as network outages and process restarts happen.
- Efficiency - Thin-edge.io lets users build applications that can run on constrained device hardware and with limited bandwidth networks.
- Multi-cloud - Thin-edge.io enables users to connect their edge devices with multiple clouds. The actual cloud used can be decided at run-time by the end-user.
Why is thin-edge.io an executable binary and not a library?
Interoperability of software components can be addressed along very different approaches. Thin-edge.io uses dynamic and loose inter-process communication (IPC) using messages exchange over an MQTT bus.
In the past and even today, many clouds provide a library (SDK) to help you connect your code to the cloud.
In thin-edge.io we decided not to follow this approach because:
- Libraries are programming language dependent, and thus developing a library for a number of programming languages always excludes developers using other programming languages. Additionally the effort to support many libraries (C, C++, Rust, Python, etc) is huge, including adding new features, testing, documentation, examples, stackoverflow. Essentially we would create multiple small user groups instead of one large user group.
- Using an IPC mechanism (and not a library) makes it easier to dynamically plug together components during runtime (instead of recompiling the software). For example, it is easier to add additional protocol stacks (OPC/UA, modbus, ProfiNet, IO-Link, KNX, ...) to thin-edge.io during run-time.
- Linking libraries to existing code can be problematic for some developers, for example for licensing reasons. While thin-edge.io has a very user-friendly licensing (Apache 2.0), some developers prefer to reduce the number of libraries that they link to their software.
Why does thin-edge.io use MQTT for IPC?
MQTT is a lightweight and flexible messaging protocol widely used by IoT applications.
We were looking for a widely-used, performant IPC mechanism and we investigated a number of alternatives. In the end, we decided to use MQTT for the following reasons:
- The approach is used by other industrial IoT organisations and software, for example by Open Industry 4.0 Alliance.
- Existing components (like Node-RED or collectd ) that support MQTT can be easily integrated. In this case, thin-edge.io acts as an MQTT proxy: existing components connect to the local MQTT bus of thin-edge.io, and thin-edge.io routes the messages to different clouds in a secure and reliable manner.
- MQTT is message oriented and bi-directional, which matches well with the event oriented programming model of industrial IoT.
- MQTT is available on many platforms, including Linux and Windows.
- MQTT client libraries are available for 25+ programming languages (see MQTT.org])
- MQTT overhead is relatively small in terms of client libary size and network overhead.
- MQTT is message payload agnostic which enables sending not only JSON messages, but also text, CSV or binary data.
Alternatives considered where: DBus, gRPC and REST over HTTP.
Why does thin-edge.io use MQTT for cloud communication?
MQTT is a lightweight and flexible messaging protocol widely used by IoT applications. Nearly all the IoT cloud platforms provide an MQTT endpoint to consume and publish messages from a fleet of devices. Therefore, MQTT was an obvious choice for edge to cloud communication.
Using MQTT for cloud communication is not mandatory. You are free to add additional protocols beside MQTT: Because thin-edge.io has an internal bus, you can implement a bridge to another protocol (e.g. LWM2M or plain HTTPS). In that case, MQTT is used inside the edge devices, and another protocol is used for external communication.
Why is the thin-edge.io canonical format based on JSON?
Thin-Edge-Json, the cloud-agnostic message format of thin-edge.io, is based on JSON.
Supported by nearly all programming languages, JSON provides a nice compromise between simplicity and flexibility. Notably, it features duck typing, a flexible way to group different data fields that can be read by consumers with different expectations over the message content. For instance, a consumer expecting a temperature can process messages where the temperature measurements are produced along with other kinds of measurements.
Additionally, JSON is supported by most (if not all) cloud vendors, which makes the transformation easier.
JSON is also used by other (Industrial) IoT standards, including OPC/UA and LWM2M.
Why use Rust?
The command line interface, and the daemon processes of thin-edge.io are implemented in Rust, a language empowering everyone to build reliable and efficient software.
The main motivation to use Rust is security: Rust avoids many security vulnerabilities and threading issues at compile time. With the type system of Rust you write software that is free from typical security flaws: undefined behavior, data races or any memory safety issues.
The second motivation is efficiency. Rust software is typically as efficient as C/C++ software. One reason is that Rust does not have (by default) a garbage collector. Instead, memory lifetime is calculated at compile time.
Note that, even if the core of thin-edge.io is written in Rust, any programming language can be used to implement thin-edge.io components. For that, one just needs an MQTT library that lets them interact with the thin-edge.io MQTT broker.
thin-edge.io platform support
Common requirements for all systems are:
- minimum 16MB of RAM
- systemd (for production systems)
- mosquitto minimum version 1.6 (for security reasons we recommend the latest 1.x version)
- dpkg (if you want to use our prebuilt deb packages)
Level 1
Level 1 supported platforms are officially supported and are actively tested in the CI/CD.
- ARMv7 Raspberry Pi OS 10
- ARMv8 Raspberry Pi OS 10
- AMD64 Ubuntu 20.04
Level 2
Level 2 platforms are not officially supported and tested yet, but we know from our experiences that these systems used to work for some maintainers or users. If your os is not listed here, this does not mean it is not working, just give it a try. We are happy to hear about your experience in the Github discussions.
- Ubuntu 20.04 in WSL (only for development, not for running thin-edge.io due to missing systemd)
- AMD64 Debian 10
- ARMv6 Raspberry Pi OS 10 (needs to be built for this specific target, please refer to Issue-161)
- ARMv7 Raspberry Pi OS 11
- ARMv8 Raspberry Pi OS 11
Init System Configuration File
To support multiple init systems and service managers, tedge
requires the /etc/tedge/system.toml
file.
The file contains configurations about the init system and the supported actions.
The format of the file is:
[init]
name = "systemd"
is_available = ["/bin/systemctl", "--version"]
restart = ["/bin/systemctl", "restart", "{}"]
stop = ["/bin/systemctl", "stop", "{}"]
enable = ["/bin/systemctl", "enable", "{}"]
disable = ["/bin/systemctl", "disable", "{}"]
is_active = ["/bin/systemctl", "is-active", "{}"]
Placeholder
{}
will be replaced by a service name (mosquitto
, tedge-mapper-c8y
, tedge-mapper-az
, etc.).
For example,
restart = ["/bin/systemctl", "restart", "{}"]
will be interpreted as
/bin/systemctl restart mosquitto
Keys
- name: An identifier of the init system.
It is used in the output of
tedge connect
andtedge disconnect
. - is_available: The command to check if the init is available on your system.
- restart: The command to restart a service by the init system.
- stop: The command to stop a service by the init system.
- enable: The command to enable a service by the init system.
- disable: The command to disable a service by the init system.
- is_active: The command to check if the service is running by the init system.
Write my software management plugin
thin-edge.io Software Management natively supports APT (Debian) packages. However, there are many package management systems in the world, and you may want to have a plugin that is suitable for your device. For such a demand, we provide the Package Manager Plugin API to write a custom Software Management plugin in your preferred programming language.
In this tutorial, we will look into the Package Manager Plugin API, and learn how to write your own plugin with a docker plugin shell script example.
Create a plugin
Create a docker file in the directory /etc/tedge/sm-plugins/. A plugin must be an executable file located in that directory.
Filename: /etc/tedge/sm-plugins/docker
#!/bin/sh
COMMAND="$1"
IMAGE_NAME="$2"
case "$COMMAND" in
list)
docker image list --format '{{.Repository}}\t{{.Tag}}' || exit 2
;;
install)
docker pull $IMAGE_NAME || exit 2
;;
remove)
docker rmi $IMAGE_NAME || exit 2
;;
prepare)
;;
finalize)
;;
update-list)
exit 1
;;
esac
exit 0
Info: the filename will be used as a plugin type to report the software list to a cloud. If you name it
docker.sh
, you will seedocker.sh
as a plugin type in cloud.
If you execute ./docker list
, you will see this kind of output.
alpine 3.14
eclipse-mosquitto 2.0-openssl
...
The Software Management Agent runs executable plugins with a special argument, like list
.
Let's call the pre-defined argument such as list
, install
, and remove
a command here.
As you can see from this example, a plugin should be an executable file
that accepts the commands and outputs to stdout and stderr.
Hence, you can implement a plugin in your preferred language.
Here is the table of the commands that you can use in a plugin.
Command | Input arguments | Expected output | Description |
---|---|---|---|
list | - | lines with tab separated values | Returns the list of software modules that have been installed with this plugin. |
prepare | - | - | Executes the provided actions before a sequence of install and remove commands. |
finalize | - | - | Executes the provided actions after a sequence of install and remove commands. |
install | NAME [--version VERSION] [--file FILE] | - | Executes the action of installation. |
remove | NAME [--version VERSION] | - | Executes the action of uninstallation. |
update-list | COMMAND NAME [--version VERSION] [--file FILE] | - | Executes the list of install and remove commands. |
The order of the commands invoked by the Software Management Agent is:
prepare
-> update-list
or [install
, remove
] ->finalize
info: There is no guarantee of the order between
install
andremove
. If you need a specific order, useupdate-list
command instead.
In the following sections, we will dive into each command and other rules deeply.
Input, Output, and Errors
Before we dive into each command, we should clarify the basic rules of plugins.
Input
The command themselves and further required arguments must be given as command-line arguments.
The only exception is update-list
, which requires stdin input.
Output
The stdout and stderr of the process running a plugin command are captured by the Software Management Agent.
Exit status
The exit status of plugins are interpreted by sm-agent as follows:
- 0: success.
- 1: usage. The command arguments cannot be interpreted, and the command has not been launched.
- 2: failure. The command failed and there is no point to retry.
- 3: retry. The command failed but might be successful later (for instance, when the network will be back).
List
The list
command is responsible to return the list of the installed software modules.
Rules:
- This command takes no arguments.
- The list is returned using CSV with tabulations as separators,
including:
- name: the name of the software module, e.g.
mosquitto
. This name is the name that has been used to install it and that needs to be used to remove it. - version: the version currently installed.
This is a string that can only be interpreted in the context of the plugin.
>Note: If the version is not present for a module, then list can return only the module name without trailing tabulation.
Given that your plugin is named
docker
, then the Software Management Agent calls
- name: the name of the software module, e.g.
sudo /etc/tedge/sm-plugins/docker list
to report the list of software modules installed.
Important: the Software Management Agent executes a plugin using
sudo
and astedge-agent
user.
docker
should output in the CSV with tabulations as separators like
alpine 3.14
eclipse-mosquitto 2.0-openssl
rust 1.51-alpine
with exit code 0
(successful).
In most cases, the output of the list
command is multi-lines.
The line separator should be \n
.
A plugin must return a CSV line per software module, using a tabulation \t
as separator.
If there is no version field then only the module name will be returned.
In the docker file example, the following command outputs CSV structures with tabulations as separator.
docker image list --format '{{.Repository}}\t{{.Tag}}'
Prepare
The prepare
command is invoked by the sm-agent before a sequence of install and remove commands.
Rules:
- It takes no argument and no output is expected.
- If the
prepare
command fails, then the whole Software Management operation is cancelled.
For many plugins, this command has nothing specific to do, and can simply return with a 0
exit status.
In some plugin types, this prepare
command can help you.
For example, assume that you want to implement a plugin for APT,
and want to run apt-get update
always before calling the install
command.
In this example, the prepare
command is the right place to invoke apt-get update
.
Finalize
The finalize
command closes a sequence of install and removes commands started by a prepare command.
Rules:
- It takes no argument and no output is expected.
- If the
finalize
command fails, then the whole Software Management operation is reported as failed, even if all the atomic actions have been successfully completed.
Similar to the prepare
plugin, you must define the command even if you want nothing in the finalize
command.
The command can be used in several situations. For example,
- remove any unnecessary software module after a sequence of actions.
- commit or roll back the sequence of actions.
- restart any processes using the modules, e.g. restart the analytics engines if the modules have changed.
Install
The install
command installs a software module, possibly of some expected version.
A plugin must be executable in the below format.
$ myplugin install NAME [--module-version VERSION] [--file FILE]
This command takes 1 mandatory argument and has 2 optional flags.
- NAME: the name of the software module to be installed, e.g.
mosquitto
. (Mandatory) - VERSION: the version to be installed. e.g.
1.5.7-1+deb10u1
. The version can be blank, so it's recommended to define the behaviour if a version is not provided. For example, always installs the "latest" version if a version is not provided. (Optional) - FILE: the path to the software to be installed. (Optional)
The installation phase may fail due to the following reasons. An error must be reported if:
- The module name is unknown.
- There is no version for the module that matches the constraint provided by the
--module-version
option. - The file content provided by
--file
option:- is not in the expected format,
- doesn't correspond to the software module name,
- has a version that doesn't match the constraint provided by the
--module-version
option (if any).
- The module cannot be downloaded.
- The module cannot be installed.
At the API level, there is no command to distinguish install or upgrade.
Back to the first docker example, it doesn't address the case with version. Let's expand the example file as below.
Filename: /etc/tedge/sm-plugins/docker
#!/bin/sh
COMMAND="$1"
IMAGE_NAME="$2"
VERSION_FLAG="$3"
IMAGE_TAG="$4"
case "$COMMAND" in
list)
docker image list --format '{{.Repository}}\t{{.Tag}}' || exit 2
;;
install)
if [ $# -eq 2 ]; then
docker pull $IMAGE_NAME || exit 2
elif [ $# -eq 4 ] && [ $VERSION_FLAG = "--module-version" ]; then
docker pull $IMAGE_NAME:$IMAGE_TAG || exit 2
else
echo "Invalid arguments"
exit 1
fi
;;
remove)
if [ $# -eq 2 ]; then
docker rmi $IMAGE_NAME || exit 2
elif [ $# -eq 4 ] && [ $VERSION_FLAG = "--module-version" ]; then
docker rmi $IMAGE_NAME:$IMAGE_TAG || exit 2
else
echo "Invalid arguments"
exit 1
fi
;;
prepare)
;;
finalize)
;;
update-list)
exit 1
;;
esac
exit 0
Pay attention to the exit statuses.
In case of invalid arguments, the plugin returns 1
.
If a command is executed but fails, the plugin returns 2
.
Each exit status is defined here.
If the given NAME is mosquitto
, and the given VERSION is 1.5.7-1+deb10u1
,
the Software Management Agent calls
sudo /etc/tedge/sm-plugins/docker install mosquitto --module-version 1.5.7-1+deb10u1
Then, the plugin executes
docker pull mosquitto:1.5.7-1+deb10u1
Remove
The remove
command uninstalls a software module,
and possibly its dependencies if no other modules are dependent on those.
A plugin must be executable in the below format.
$ myplugin remove NAME [--module-version VERSION]
This command takes 1 mandatory argument and 1 optional argument with a flag.
- NAME: the name of the software module to be removed, e.g.
mosquitto
. (Mandatory) - VERSION: the version to be installed. e.g.
1.5.7-1+deb10u1
. The version can be blank, so it's recommended to define the behaviour if a version is not provided. For example, uninstall a software module regardless of its version if a version is not provided. (Optional)
The uninstallation phase can be failed due to several reasons. An error must be reported if:
- The module name is unknown.
- The module cannot be uninstalled.
Back to the first docker plugin example,
if the NAME is mosquitto
, and the VERSION is 1.5.7-1+deb10u1
,
the Software Management Agent calls
sudo /etc/tedge/sm-plugins/docker remove mosquitto --module-version 1.5.7-1+deb10u1
Then, the plugin executes
docker rmi mosquitto:1.5.7-1+deb10u1
Update-list
The update-list
command accepts a list of software modules and associated operations as install
or remove
.
This basically achieves the same purpose as original commands install and remove,
but gets passed all software modules to be processed in one command.
This can be needed when an order of processing software modules is relevant.
In other words, you can choose a combination of the install
or remove
commands or this update-list
command up to your requirement.
If you don't want to use update-list
, the plugin must return 1
like the first docker plugin example.
case "$COMMAND" in
...
update-list)
exit 1
;;
esac
Let's expand the first docker plugin example to use update-list
.
First, learn what is the input of update-list
.
The Software Management Agent calls a plugin as below. Note that each argument is tab separated:
$ sudo /etc/tedge/sm-plugins/docker update-list <<EOF
install name1 version1
install name2 path2
remove name3 version3
remove name4
EOF
The point is that it doesn't take any command-line argument, but the software action list is sent through stdin.
The behaviour of operations install
and remove
is the same as for original commands install
and remove
.
The above input is equivalent to the use of original commands (install
and remove
):
$ /etc/tedge/sm-plugins/docker install name1 --module-version version1
$ /etc/tedge/sm-plugins/docker install name2 --file path2
$ /etc/tedge/sm-plugins/docker remove "name 3" --module-version version3
$ /etc/tedge/sm-plugins/docker remove name4
To make the docker plugin accept a list of install and remove actions, let's change the file as below. Note that this example works only in bash.
Filename: /etc/tedge/sm-plugins/docker
#!/bin/bash
COMMAND="$1"
case "$COMMAND" in
list)
docker image list --format '{{.Repository}}\t{{.Tag}}' || exit 2
;;
install)
echo docker pull "$2:$3"
;;
remove)
echo docker rmi "$2:$3"
;;
prepare)
;;
finalize)
;;
update-list)
while IFS=$'\t' read -r ACTION MODULE VERSION FILE
do
bash -c "$0 $ACTION $MODULE $VERSION"
done
;;
esac
exit 0
You can find that install
and remove
are replaced by update-list
.
update-list
should define the behaviour to read line by line for the case install
and remove
.
Also, update-list
must be fail-fast.
That example exists immediately if one of the commands fails.
Project references
You can also refer to:
- the specification of the Package Manager Plugin API.
- the APT plugin written in Rust.
- the example Docker plugin written in POSIX standard shell script. This plugin can install/remove docker containers using docker image tags. This plugin is not to be used in production without necessary enhancements. It is to be used only as a reference to write your own plugin.
Device Configuration Management using Cumulocity
Thin-edge provides an operation plugin to manage device configurations using Cumulocity.
- This management is bi-directional:
- A device can be taken as reference, all the managed files being uploaded to the cloud and stored there as a configuration snapshot.
- A configuration snapshot can be pushed from the cloud to any devices of the same type, i.e. supporting the same kind of configuration files.
- With this operation plugin, the device owner defines the list of files (usually configuration files, but not necessarily), that will be managed from the cloud tenant.
- Notably, the plugin configuration itself is managed from the cloud, meaning, the device owner can update from the cloud the list of files to be managed.
- Cumulocity manages the configuration files accordingly to their type, a name that is chosen by the device owner to categorise each configuration. By default, the full path of a configuration file on the device is used as its type.
- When files are downloaded from the cloud to the device, these files are stored in a temporary directory first. They are atomically moved to their target path, only after a fully successful download. The aim is to avoid breaking the system with half downloaded files.
- When a downloaded file is copied to its target, the unix user, group and mod are preserved.
- Once a snapshot has been downloaded from Cumulocity to the device, the plugin publishes a notification message on the local thin-edge MQTT bus. The device software has to subscribe to these messages if any action is required, say to check the content of file, to preprocess it or to restart a daemon.
- In other words, the responsibilities of the plugin are:
- to define the list of files under configuration management
- to notify the cloud when this list is updated,
- to upload these files to the cloud on demand,
- to download the files pushed from the cloud,
- to make sure that the target files are updated atomically after successful download,
- to notify the device software when the configuration is updated.
- By contrast, the plugin is not responsible for:
- checking the uploaded files are well-formed,
- restarting the configured processes.
- A user-specific component, installed on the device,
can implement more sophisticated configuration use-cases by:
- listening for configuration updates on the local thin-edge MQTT bus,
- restarting the appropriate processes when appropriate,
- declaring intermediate files as the managed files, to have the opportunity to check or update their content before moving them to the actual targets.
Installation
Assuming the configuration plugin c8y_configuration_plugin
has been installed in /usr/bin/c8y_configuration_plugin
,
two files must be added under /etc/tedge/operations/c8y/
to declare that this plugin supports two Cumulocity operations:
uploading and downloading configuration files
(which respective SmartRest2 codes are 526
and 524
).
These two files can be created using the c8y_configuration_plugin --init
option:
$ sudo c8y_configuration_plugin --init
$ ls -l /etc/tedge/operations/c8y/c8y_UploadConfigFile
-rw-r--r-- 1 tedge tedge 95 Mar 22 14:24 /etc/tedge/operations/c8y/c8y_UploadConfigFile
$ ls -l /etc/tedge/operations/c8y/c8y_DownloadConfigFile
-rw-r--r-- 1 tedge tedge 97 Mar 22 14:24 /etc/tedge/operations/c8y/c8y_DownloadConfigFile
The c8y_configuration_plugin
has to be run as a daemon on the device, the latter being connected to Cumulocity.
Configuration
The c8y_configuration_plugin
configuration is stored by default under /etc/tedge/c8y/c8y-configuration-plugin.toml
This TOML file defines the list of files to be managed from the cloud tenant. Each configuration file is defined by a record with:
- The full
path
to the file. - An optional configuration
type
. If not provided, thepath
is used astype
. - Optional unix file ownership:
user
,group
and octalmode
.
These are only used when a configuration file pushed from the cloud doesn't exist on the device. When a configuration file is already present on the device, this plugin never changes file ownership, ignoring these parameters.
$ cat /etc/tedge/c8y/c8y-configuration-plugin.toml
files = [
{ path = '/etc/tedge/tedge.toml', type = 'tedge.toml' },
{ path = '/etc/tedge/mosquitto-conf/c8y-bridge.conf' },
{ path = '/etc/tedge/mosquitto-conf/tedge-mosquitto.conf' },
{ path = '/etc/mosquitto/mosquitto.conf', type = 'mosquitto', user = 'mosquitto', group = 'mosquitto', mode = 0o644 }
]
Note that:
- The file
/etc/tedge/c8y/c8y-configuration-plugin.toml
itself doesn't need to be listed. This is implied, so the list can always be configured from the cloud. Thetype
for this self configuration file isc8y-configuration-plugin
. - If the file
/etc/tedge/c8y/c8y-configuration-plugin.toml
is not found, empty, ill-formed or not-readable then onlyc8y-configuration-plugin.toml
is managed from the cloud. - If the file
/etc/tedge/c8y/c8y-configuration-plugin.toml
is ill-formed or cannot be read then an error is logged, but the operation proceed as if the file were empty.
The behavior of the c8y_configuration_plugin
is also controlled
by the configuration of thin-edge:
tedge config get mqtt.bind_address
: the address of the local MQTT bus.tedge config get mqtt.port
: the TCP port of the local MQTT bus.tedge config get tmp.path
: the directory where the files are updated before being copied atomically to their targets.
Usage
$ c8y_configuration_plugin --help
c8y_configuration_plugin 0.6.2
Thin-edge device configuration management for Cumulocity
USAGE:
c8y_configuration_plugin [OPTIONS]
OPTIONS:
--config-dir <CONFIG_DIR> [default: /etc/tedge]
--config-file <CONFIG_FILE> [default: $CONFIG_DIR/c8y/c8y-configuration-plugin.toml]
--debug Turn-on the debug log level
-h, --help Print help information
-i, --init Create supported operation files
-V, --version Print version information
On start, `c8y_configuration_plugin` notifies the cloud tenant of the managed configuration files,
listed in the `CONFIG_FILE`, sending this list with a `119` on `c8y/s/us`.
`c8y_configuration_plugin` subscribes then to `c8y/s/ds` listening for configuration operation
requests (messages `524` and `526`).
notifying the Cumulocity tenant of their progress (messages `501`, `502` and `503`).
The thin-edge `CONFIG_DIR` is used to find where:
* to store temporary files on download: `tedge config get tmp.path`,
* to connect the MQTT bus: `tedge config get mqtt.port`.
Logging
The c8y_configuration_plugin
reports progress and errors on its stderr
.
- All upload and download operation requests are logged, when received and when completed, with one line per file.
- All changes to the list of managed file is logged, one line per change.
- All errors are reported with the operation context (upload or download? which file?).
Notifications
When a configuration file is successfully downloaded from the cloud,
the c8y_configuration_plugin
service notifies this update over MQTT.
- The notification messages are published on the topic
tedge/configuration_change/{type}
, where{type}
is the type of the configuration file that have been updated, for instancetedge/configuration_change/tedge.toml
- Each message provides the path to the freshly updated file as in
{ "path": "/etc/tedge/tedge.toml" }
.
Note that:
- If no specific type has been assigned to a configuration file, then the path to this file is used as its type.
Update notifications for that file are then published on the topic
tedge/configuration_change/{path}
, for instancetedge/configuration_change//etc/tedge/mosquitto-conf/c8y-bridge.conf
. - Since the type of configuration file is used as an MQTT topic name, the characters
#
and+
cannot be used in a type name. If such a character is used in a type name (or in the path of a configuration file without explicit type), then the whole plugin configuration/etc/tedge/c8y/c8y-configuration-plugin.toml
is considered ill-formed.
APIs
The bridged topics
This document lists the MQTT topics that are supported by the thin-edge.io.
Thin Edge JSON MQTT Topics
To send the Thin Edge JSON measurements to a supported IoT cloud, the device should publish the measurements on
tedge/measurements topic. Internally the tedge-mapper will consume the measurements from this topic, translates and
send them to the cloud that the device has been connected to by the tedge connect
command.
Cumulocity MQTT Topics
The topics follow the below format
<protocol>/<direction><type>[/<template>][/<child id>]
Protocol | Direction | Type |
---|---|---|
s = standard | u = upstream | s = static (built-in) |
t = transient | d = downstream | c = custom (device-defined) |
e = error | d = default (defined in connect) | |
t = template | ||
cr = credentials |
SmartREST2.0 topics
All Cumulocity topics have been prefixed by c8y/
.
-
Registration topics c8y/s/dcr c8y/s/ucr
-
Creating template topics c8y/s/dt c8y/s/ut/#
-
Static templates topics c8y/s/us c8y/t/us c8y/q/us c8y/c/us c8y/s/ds
-
Debug topics c8y/s/e
-
Custom template topics c8y/s/uc/# c8y/t/uc/# c8y/q/uc/# c8y/c/uc/# c8y/s/dc/#
C8Y JSON topics
c8y/measurement/measurements/create
c8y/error
You can find more information about Cumulocity topics Here
Azure MQTT Topics
MQTT clients on Thin Edge device must use the below topics to communicate with the Azure cloud.
The Azure topics are prefixed by az/
.
-
az/messages/events/
- Use this topic to send the messages from device to cloud. The messages are forwarded to the Azure topic nameddevices/{device_id}/messages/events/
where device_id is the Thin Edge device id. -
az/messages/devicebound/#
- Use this topic to subscribe for the messages that were sent from cloud to device. Any message published by Azure on one the subtopics ofdevices/{device_id}/messages/devicebound/#
is republished here.
Collectd topics
When the device monitoring feature is enabled,
monitoring metrics are emitted by collectd
on a hierarchy of MQTT topics.
collectd/$HOSTNAME/#
- All the metrics collected on the device (which hostname is$HOSTNAME
).collectd/$HOSTNAME/$PLUGIN/#
- All the metrics collected by a given collectd plugin, named$PLUGIN
.collectd/$HOSTNAME/$PLUGIN/$METRIC
- The topic for a given metric, named$METRIC
. All the measurements are published as a pair of a Unix timestamp in milli-seconds and a numeric value in the format$TIMESTAMP:$VALUE
. For example,1623155717:98.6
.
The collectd-mapper
daemon process ingests these measurements and emits translated messages
the tedge/measurements
topic.
- This process groups the atomic measurements that have been received during the same time-window (currently 200 ms)
- and produces a single thin-edge-json for the whole group of measurements.
Software Management Plugin API
Thin-edge uses plugins to delegate to the appropriate package managers and installers all the software management operations: installation of packages, uninstallations and queries.
- A package manager plugin acts as a facade for a specific package manager.
- A plugin is an executable that follows the plugin API.
- On a device, several plugins can be installed to deal with different kinds of software modules.
- The filename of a plugin is used by thin-edge to determine the appropriate plugin for a software module.
- All the actions on a software module are directed to the plugin bearing the name that matches the module type name.
- The plugins are loaded and invoked by the sm-agent in a systematic order (in practice the alphanumerical order of their names in the file system).
- The software modules to be installed/removed are also passed to the plugins in a consistent order.
- Among all the plugins, one can be marked as the default plugin using
tedge config
cli. - The default plugin is invoked when an incoming software module in the cloud request doesn't contain any explicit type annotation.
- Several plugins can co-exist for a given package manager as long as they are given different names.
Each can implement a specific software management policy.
For instance, for a debian package manager, several plugins can concurrently be installed, say one named
apt
to handle regular packages from the public apt repository and another namedcompany-apt
to install packages from a company's private package repository.
Plugin repository
- To be used by thin-edge, a plugin has to stored in the directory
/etc/tedge/sm-plugins
. - A plugin must be named after the software module type as specified in the cloud request.
That is, a plugin named
apt
handles software modules that are defined with typeapt
in the cloud request. Consequently a plugin to handle software module defined fordocker
must be nameddocker
. - The same plugin can be given different names, using virtual links.
- When there are multiple plugins on a device, one can be marked as the default plugin using the command
tedge config set software.plugin.default <plugin-name>
- If there's one and only one plugin available on a device, that's treated as the default, even without an explicit configuration.
On start-up and sighup, the sm-agent registers the plugins as follow:
- Iterate over the executable file of the directory
/etc/tedge/sm-plugins
. - Check the executable is indeed a plugin, calling the
list
command.
Plugin API
- A plugin must implement all the commands used by the sm-agent of thin-edge, and support all the options for these commands.
- A plugin should not support extra command or option.
- A plugin might have a configuration file.
- It can be a list of remote repositories, or a list of software modules to be excluded.
- These configuration files can be managed from the cloud via the sm-agent (TODO: how).
Input, Output and Errors
- The plugins are called by the sm-agent using a child process for each action.
- Beside command
update-list
there is no input beyond the command arguments, and a plugin that does not implementupdate-list
can close itsstdin
. - The
stdout
andstderr
of the process running a plugin command are captured by the sm-agent.- These streams don't have to be the streams returned by the underlying package manager. It can be a one sentence summary of the error, redirecting the administrator to the package manager logs.
- A plugin must return the appropriate exit status after each command.
- In no cases, the error status of the underlying package manager should be reported.
- The exit status are interpreted by sm-agent as follows:
0
: success.1
: usage. The command arguments cannot be interpreted, and the command has not been launched.2
: failure. The command failed and there is no point to retry.3
: retry. The command failed but might be successful later (for instance, when the network will be back).
- If the command fails to return within 5 minutes, the sm-agent reports a timeout error:
4
: timeout.
The list
command
When called with the list
command, a plugin returns the list of software modules that have been installed with this plugin,
using tab separated values.
$ debian-plugin list
...
collectd-core 5.8.1-1.3
mosquitto 1.5.7-1+deb10u1
...
Contract:
- This command take no arguments.
- If an error status is returned, the executable is removed from the list of plugins.
- The list is returned using CSV with tabulations as separators. Each line has two values separated by a tab: the name of the module then the version of that module. If there is no version for a module, then the trailing tabulation is not required and be skipped.
The prepare
command
The prepare
command is invoked by the sm-agent before a sequence of install and remove commands
$ /etc/tedge/sm-plugins/debian prepare
$ /etc/tedge/sm-plugins/debian install x
$ /etc/tedge/sm-plugins/debian install y
$ /etc/tedge/sm-plugins/debian remove z
$ /etc/tedge/sm-plugins/debian finalize
For many plugins this command will do nothing. However, It gives an opportunity to the plugin to:
- Update the dependencies before an operation, *i.e. a sequence of actions.
Notably, a debian plugin can update the
apt
cache issuing anapt-get update
. - Start a transaction, in case the plugin is able to manage rollbacks.
Contract:
- This command take no arguments.
- No output is expected.
- If the
prepare
command fails, then the planned sequences of actions (.i.e the whole sm operation) is cancelled.
The finalize
command
The finalize
command closes a sequence of install and remove commands started by a prepare
command.
This can be a no-op, but this is also an opportunity to:
- Remove any unnecessary software module after a sequence of actions.
- Commit or rollback the sequence of actions.
- Restart any processes using the modules, e.g. restart the analytics engines if the modules have changed
Contract:
- This command take no arguments.
- No output is expected.
- This command might check (but doesn't have to) that the list of install and remove command has been consistent.
- For instance, a plugin might raise an error after the sequence
prepare;install a; remove a-dependency; finalize
.
- For instance, a plugin might raise an error after the sequence
- If the
finalize
command fails, then the planned sequences of actions (.i.e the whole sm operation) is reported as failed, even if all the atomic actions has been successfully completed.
The install
command
The install
command installs a software module, possibly of some expected version.
$ plugin install NAME [--module-version VERSION] [--file FILE]
Contract:
- The command requires a single mandatory argument: the software module name.
- This module name is meaningful only to the plugin.
- An optional version string can be provided.
- This version string is meaningful only to the plugin and is transmitted unchanged from the cloud to the plugin.
- The version string can include constraints (as at least that version), from the sm-agent viewpoint this is no more than a string.
- If no version is provided the plugin is free to install the more appropriate version.
- An optional file path can be provided.
- When the device administrator provides an url, the sm-agent downloads the software module on the device, then invoke the install command with a path to that file.
- If no file is provided, the plugin has to derive the appropriate location from its repository and to download the software module accordingly.
- The command installs the requested software module and any dependencies that might be required.
- It is up to the plugin to define if this command triggers an installation or an upgrade. It depends on the presence of a previous version on the device and of the ability of the package manager to deal with concurrent versions for a module.
- A plugin might not be able to install dependencies. In that case, the device administrator will have to request explicitly the dependencies to be installed first.
- After a successful sequence
prepare; install foo; finalize
the modulefoo
must be reported by thelist
command. - After a successful sequence
prepare; install foo --module-version v; finalize
the modulefoo
must be reported by thelist
command with the versionv
. If the plugin manage concurrent versions, the modulefoo
might also be reported with versions already installed before the operation. - A plugin is not required to detect inconsistent actions as
prepare; install a; remove a-dependency; finalize
. - This is not an error to run this command twice or when the module is already installed.
- An error must be reported if:
- The module name is unknown.
- There is no version for the module that matches the constraint provided by the
--version
option. - The file content provided by
--file
option:- is not in the expected format,
- doesn't correspond to the software module name,
- has a version that doesn't match the constraint provided by the
--module-version
option (if any).
- The module cannot be downloaded.
- The module cannot be installed.
The remove
command
The remove
command uninstalls a software module, and possibly its dependencies if no other modules are dependent on those.
$ plugin remove NAME [--module-version VERSION]
Contract:
- The command requires a single mandatory argument: the module name.
- This module name is meaningful only to the plugin and is transmitted unchanged from the cloud to the plugin.
- An optional version string can be provided.
- This version string is meaningful only to the plugin and is transmitted unchanged from the cloud to the plugin.
- The command uninstall the requested module and possibly any dependencies that are no more required.
- If a version is provided, only the module of that version is removed. This is in-practice useful only for a package manager that is able to install concurrent versions of a module.
- After a successful sequence
prepare; remove foo; finalize
the modulefoo
must no more be reported by thelist
command. - After a successful sequence
prepare; remove foo --module-version v; finalize
the modulefoo
no more be reported by thelist
command with the versionv
. If the plugin manage concurrent versions, the modulefoo
might still be reported with versions already installed before the operation. - A plugin is not required to detect inconsistent actions as
prepare; remove a; install a-reverse-dependency; finalize
. - This is not an error to run this command twice or when the module is not installed.
- An error must be reported if:
- The module name is unknown.
- The module cannot be uninstalled.
The update-list
command
The update-list
command accepts a list of software modules and associated operations as install
or remove
.
This basically achieves same purpose as original commands install
and remove
, but gets passed all software modules to be processed in one command.
This can be needed when order of processing software modules is relevant - e.g. when dependencies between packages inside the software list do occur.
# building list of software modules and operations,
# and passing to plugin's stdin via pipe:
# NOTE that each argument is tab separated:
$ echo '\
install name1 version1
install name2 path2
remove name3 version3
remove name4'\
| plugin update-list
Contract:
- This command is optional for a plugin. It can be implemented alternatively to original commands
install
andremove
as both are specified above.- If a plugin does not implement this command it must return exit status
1
. In that case sm-agent will call the plugin again package-by-package using original commandsinstall
andremove
. - If a plugin implements this command sm-agent uses it instead of original commands
install
andremove
.
- If a plugin does not implement this command it must return exit status
- This command takes no commandline arguments, but expects a software list sent from sm-agent to plugin's
stdin
. - In the software list each software module is represented by exactly one line, using tab separated values.
- The position of each argument in the argument list has it's defined meaning:
- 1st argument: Is the operation and can be
install
orremove
- 2nd argument: Is the software module's name.
- 3rd argument: Is the software module's version. That argument is optional and can be empty (then empty string "" is used).
- 4th argument: Is the software module's path. That argument is optional and can be empty (then empty string "" is used). For operation
remove
that argument does not exist.
- 1st argument: Is the operation and can be
- Behaviour of operations
install
andremove
is same as for original commandsinstall
andremove
as specified above.- For details about operations' arguments "name", "version" and "path", see specification of original command
install
orremove
. - For details about
exitstatus
see accoring specification of original commandinstall
orremove
.
- For details about operations' arguments "name", "version" and "path", see specification of original command
- An overall error must be reported (via process's exit status) when at least one software module operation has failed.
Example how to invoke that plugin command update-list
. Note that each argument is tab separated:
$ plugin update-list <<EOF
install name1 version1
install name2 path2
remove name3 version3
remove name4
EOF
That is equivalent to use of original commands (install
and remove
):
$ plugin install name1 --module-version version1
$ plugin install name2 --module-path path2
$ plugin remove "name 3" --module-version version3
$ plugin remove name4
Exemplary implementation of a shell script for parsing software list from stdin
:
Note that this example works only in bash.
#!/bin/bash
echo ""
echo "---+++ reading software list +++---"
while IFS=$'\t' read -r ACTION MODULE VERSION FILE
do
echo "$0 $ACTION $MODULE $VERSION"
done
Building thin-edge.io
Requirements
You can use any OS to build from source (below has been tested on Ubuntu, but we also use Debian, macOS, and FreeBSD successfully).
Our recommended setup and required tools are:
- Ubuntu 20.04 or Debian 10.9 (Buster)
- git
- Rust toolchain
Following packages are required:
- build-essentials
- curl
- gcc
A list of our test platforms can be found here.
Get the code
thin-edge.io code is in git repository on github to acquire the code use following command:
- via SSH:
git clone git@github.com:thin-edge/thin-edge.io.git
- or via HTTPS:
git clone https://github.com/thin-edge/thin-edge.io.git
Installing toolchain
Rust toolchain
To install Rust follow Official installation guide.
To get started you need Cargo's bin directory ($HOME/.cargo/bin
) in your PATH
environment variable.
export PATH=$PATH:$HOME/.cargo/bin
And then you can run rustc
to view current version:
$ rustc --version
rustc 1.58.1 (db9d1b20b 2022-01-20)
Note: Above command will add rust to path only for existing session, after you restart the session you will have to add it again, to add rust to the path permanently it will depend on your shell but for Bash, you simply need to add the line from above,
export PATH=$PATH:$HOME/.cargo/bin
to your ~/.bashrc.
For other shells, you'll want to find the appropriate place to set a configuration at start time, eg. zsh uses ~/.zshrc. Check your shell's documentation to find what file it uses.
thin-edge.io operates the MSRV
(Minimum Supported Rust Version) and uses stable toolchain.
Current MSRV is 1.58.1
.
Cross compilation toolchain (optional)
thin-edge.io can be compiled for target architecture on non-target device, this is called cross compilation.
Currently we support Raspberry Pi 3B
for armv7
architecture with Rust's cross compilation toolchain called cargo cross.
To install cargo cross:
cargo install cross
Debian packaging (optional)
We use cargo deb to build our debian packages, the tool takes care of all the work to package thin-edge.io.
To install cargo deb use:
cargo install cargo-deb
Compiling
To build thin-edge.io we are using cargo
.
As we are using cargo workspace
for all our crates. All compiled files are put in ./target/
directory with target's name eg: ./target/debug
or ./target/release
for native builds and for cross compiled targets ./target/<architecture>/debug
or ./target/<architecture>/release
dependent on the target of the build.
Compiling dev
To compile dev profile (with debug symbols) we use following command:
cargo build
Build artifacts can be found in ./target/debug
and will include executables:
$ ls ./target/debug/tedge*
-rwxrwxr-x 2 user user 11111 Jan 1 00:00 tedge
-rwxrwxr-x 2 user user 11111 Jan 1 00:00 tedge_mapper
Binaries can be run eg: ./target/debug/tedge
.
Alternatively, you can use cargo
to build and run executable in a single command:
cargo run --bin tedge
Compiling release
To compile release profile we use following command:
cargo build --release
Build artifacts can be found in ./target/release
and will include executables:
$ ls ./target/release/tedge*
-rwxrwxr-x 2 user user 11111 Jan 1 00:00 tedge
-rwxrwxr-x 2 user user 11111 Jan 1 00:00 tedge_mapper
Binaries can be run eg: ./target/release/tedge
.
Building deb package
Currently thin-edge.io contains 2 binaries, tedge
(cli) and tedge_mapper
which are packaged as separate debian packages. To create following commands are to be issued:
cargo deb -p tedge
cargo deb -p tedge_mapper
All resulting packages are going to be in: ./target/debian/
directory:
$ ls ./target/debian -l
total 2948
-rw-rw-r-- 1 user user 11111 Jan 1 00:00 tedge_0.5.0_amd64.deb
-rw-rw-r-- 1 user user 11111 Jan 1 00:00 tedge_mapper_0.5.0_amd64.deb
Cross compiling
To create binaries which can run on different platform than one you are currently on you can use cargo cross:
cross build --target armv7-unknown-linux-gnueabihf
Build artifacts can be found in ./target/armv7-unknown-linux-gnueabihf/debug
and will include executables:
$ ls ./target/armv7-unknown-linux-gnueabihf/debug/tedge*
-rwxrwxr-x 2 user user 11111 Jan 1 00:00 tedge
-rwxrwxr-x 2 user user 11111 Jan 1 00:00 tedge_mapper
To cross compile release version of the binaries just add --release
to the above command like so:
cross build --target armv7-unknown-linux-gnueabihf --release
Running tests
When contributing to thin-edge.io we ask you to write tests for the code you have written. The tests will be run by build pipeline when you create pull request, but you can easily run all the tests when you are developing with following command:
cargo test
This will run all tests from the repository and sometime may take long time, cargo
allows you to run specific test or set of tests for binary:
cargo test --bin tedge
Reference Guides
The thin-edge.io command-line interface (tedge CLI) is a set of commands used to create and manage thin-edge.io resources.
Following sections show the tedge sub commands.
tedge
commandtedge cert
commandtedge config
commandtedge connect
commandtedge disconnect
commandtedge mqtt
command- Bridged Topics
Software Management (under development)
Thin-edge.io configuration files
The tedge
command
tedge 0.7.2
tedge is the cli tool for thin-edge.io
USAGE:
tedge [OPTIONS] [SUBCOMMAND]
OPTIONS:
--config-dir <CONFIG_DIR> [default: /etc/tedge]
-h, --help Print help information
--init Initialize the tedge
-V, --version Print version information
SUBCOMMANDS:
cert Create and manage device certificate
config Configure Thin Edge
connect Connect to connector provider
disconnect Remove bridge connection for a provider
help Print this message or the help of the given subcommand(s)
mqtt Publish a message on a topic and subscribe a topic
The tedge config
command
tedge-config
Configure Thin Edge
USAGE:
tedge config <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
SUBCOMMANDS:
get Get the value of the provided configuration key
help Print this message or the help of the given subcommand(s)
list Print the configuration keys and their values
set Set or update the provided configuration key with the given value
unset Unset the provided configuration key
Get
tedge-config-get
Get the value of the provided configuration key
USAGE:
tedge config get <KEY>
ARGS:
<KEY> Configuration key. Run `tedge config list --doc` for available keys
OPTIONS:
-h, --help Print help information
Set
tedge-config-set
Set or update the provided configuration key with the given value
USAGE:
tedge config set <KEY> <VALUE>
ARGS:
<KEY> Configuration key. Run `tedge config list --doc` for available keys
<VALUE> Configuration value
OPTIONS:
-h, --help Print help information
List
tedge-config-list
Print the configuration keys and their values
USAGE:
tedge config list [OPTIONS]
OPTIONS:
--all Prints all the configuration keys, even those without a configured value
--doc Prints all keys and descriptions with example values
-h, --help Print help information
Unset
tedge-config-unset
Unset the provided configuration key
USAGE:
tedge config unset <KEY>
ARGS:
<KEY> Configuration key. Run `tedge config list --doc` for available keys
OPTIONS:
-h, --help Print help information
The tedge cert
command
tedge-cert
Create and manage device certificate
USAGE:
tedge cert <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
SUBCOMMANDS:
create Create a self-signed device certificate
help Print this message or the help of the given subcommand(s)
remove Remove the device certificate
show Show the device certificate, if any
upload Upload root certificate
Create
tedge-cert-create
Create a self-signed device certificate
USAGE:
tedge cert create --device-id <ID>
OPTIONS:
--device-id <ID> The device identifier to be used as the common name for the certificate
-h, --help Print help information
Show
tedge-cert-show
Show the device certificate, if any
USAGE:
tedge cert show
OPTIONS:
-h, --help Print help information
Remove
tedge-cert-remove
Remove the device certificate
USAGE:
tedge cert remove
OPTIONS:
-h, --help Print help information
Upload
tedge-cert-upload
Upload root certificate
USAGE:
tedge cert upload <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
SUBCOMMANDS:
c8y Upload root certificate to Cumulocity
help Print this message or the help of the given subcommand(s)
The tedge connect
command
tedge-connect
Connect to connector provider
USAGE:
tedge connect <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
SUBCOMMANDS:
az Create connection to Azure
c8y Create connection to Cumulocity
help Print this message or the help of the given subcommand(s)
Azure
tedge-connect-az
Create connection to Azure
The command will create config and start edge relay from the device to az instance
USAGE:
tedge connect az [OPTIONS]
OPTIONS:
-h, --help
Print help information
--test
Test connection to Azure
Cumulocity
tedge-connect-c8y
Create connection to Cumulocity
The command will create config and start edge relay from the device to c8y instance
USAGE:
tedge connect c8y [OPTIONS]
OPTIONS:
-h, --help
Print help information
--test
Test connection to Cumulocity
The tedge disconnect
command
tedge-disconnect
Remove bridge connection for a provider
USAGE:
tedge disconnect <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
SUBCOMMANDS:
az Remove bridge connection to Azure
c8y Remove bridge connection to Cumulocity
help Print this message or the help of the given subcommand(s)
Azure
tedge-disconnect-az
Remove bridge connection to Azure
USAGE:
tedge disconnect az
OPTIONS:
-h, --help Print help information
Cumulocity
tedge-disconnect-c8y
Remove bridge connection to Cumulocity
USAGE:
tedge disconnect c8y
OPTIONS:
-h, --help Print help information
The tedge mqtt
command
tedge-mqtt
Publish a message on a topic and subscribe a topic
USAGE:
tedge mqtt <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
SUBCOMMANDS:
help Print this message or the help of the given subcommand(s)
pub Publish a MQTT message on a topic
sub Subscribe a MQTT topic
Pub
tedge-mqtt-pub
Publish a MQTT message on a topic
USAGE:
tedge mqtt pub [OPTIONS] <TOPIC> <MESSAGE>
ARGS:
<TOPIC> Topic to publish
<MESSAGE> Message to publish
OPTIONS:
-h, --help Print help information
-q, --qos <QOS> QoS level (0, 1, 2) [default: 0]
-r, --retain Retain flag
Sub
tedge-mqtt-sub
Subscribe a MQTT topic
USAGE:
tedge mqtt sub [OPTIONS] <TOPIC>
ARGS:
<TOPIC> Topic to subscribe to
OPTIONS:
-h, --help Print help information
--no-topic Avoid printing the message topics on the console
-q, --qos <QOS> QoS level (0, 1, 2) [default: 0]
Thin-edge config files
Thin-edge.io requires config files for its operation. The tedge --init
option is used to create
the base directory and other directories inside the base directory with appropriate user and permissions.
The tedge_mapper --init c8y/az
and tedge_agent --init
will create the
directories/files inside the base directory that are required for their operation.
By default, the config files are created in /etc/tedge
directory. To create the config files in
a custom base directory one has to use --config-dir <Path to base directory>
option.
Creating thin-edge
config files
The config files are created using tedge --init
as below.
$ sudo tedge --init
All the directories will be created in the /etc/tedge
directory. The directories layout looks as below.
$ ls -l /etc/tedge
total 16
drwxrwxr-x 2 mosquitto mosquitto 4096 Jun 10 14:49 device-certs
drwxrwxr-x 2 tedge tedge 4096 Jun 10 14:49 mosquitto-conf
drwxrwxr-x 2 tedge tedge 4096 Jun 10 14:49 operations
drwxrwxr-x 2 tedge tedge 4096 Jun 10 14:49 plugins
Use the below command to create the config directories in a custom directory.
$ sudo tedge --config-dir /global/path/to/config/dir --init
Now all the config directories will be created inside the /global/path/to/config/dir
directory.
The directories and files that are required by the tedge_mapper
are created as below.
$ sudo tedge_mapper --init c8y
$ ls -l /etc/tedge/operations/c8y
total 0
-rw-r--r-- 1 tedge tedge 0 Jun 14 14:37 c8y_Restart
-rw-r--r-- 1 tedge tedge 0 Jun 14 14:37 c8y_SoftwareUpdate
To create these directories in a custom directory, use --config-dir
option as below.
$ sudo tedge_mapper --config-dir /global/path/to/config/dir --init c8y
The directories and files that are required by the tedge_agent
are created as below.
$ sudo tedge_agent --init
$ ls -l /etc/tedge/.agent
-rw-r--r-- 1 tedge tedge 0 Jun 15 11:51 /etc/tedge/.agent/current-operation
To create these directories and files in a custom directory, use the --config-dir
option as below as below.
$ sudo tedge_agent --config-dir /global/path/to/config/dir --init
Manage the configuration parameters
The configuration parameters can be set/unset/list in a config file as below
For example, the config parameter can be set as below.
$ sudo tedge config set c8y.url your.cumulocity.io
Now the configuration will be added into /etc/tedge/tedge.toml
Use the below command to set/unset/list configuration parameters in a config file that is present in a custom directory.
$ sudo tedge --config-dir /global/path/to/config/dir config set c8y.url your.cumulocity.io
Now the config will be set in /global/path/to/config/dir/tedge/tedge.toml
Manage the certificate
To create/remove/upload the certificate, one can use the below command.
$ sudo tedge cert create --device-id thinedge
# Find the certificates that are created as below.
$ ls -l /etc/tedge/device-certs/
total 8
-r--r--r-- 1 mosquitto mosquitto 638 Jun 14 14:38 tedge-certificate.pem
-r-------- 1 mosquitto mosquitto 246 Jun 14 14:38 tedge-private-key.pem
Use the below command to create/remove/upload the certificate.
$ sudo tedge --config-dir /global/path/to/config/dir cert create --device-id thinedge
# Find the certificates that are created as below.
$ ls -l /global/path/to/config/dir/tedge/device-certs/
total 8
-r--r--r-- 1 mosquitto mosquitto 638 Jun 14 14:38 tedge-certificate.pem
-r-------- 1 mosquitto mosquitto 246 Jun 14 14:38 tedge-private-key.pem
Connecting to the cloud
Use the tedge connect c8y/az
command to connect to the cloud using the default configuration files
that are present in /etc/tedge
.
To connect to the cloud with config files that are present in a custom location use
the tedge connect --config-dir <Path to custom dir> c8y/az
option.
This is a two step process.
Step 1: Update the mosquitto.conf
Since the bridge configuration files for Cumulocity IoT or Azure IoT Hub will be created in a directory given through --config-dir
,
the path to the bridge configuration files (tedge-mosquitto.conf, c8y/az-bridge.conf) must be found by mosquitto
.
So, the below line has to be added to your mosquitto.conf
file manually.
include_dir /global/path/to/config/dir/tedge/mosquitto-conf
Step 2: tedge connect <cloud[c8y/az]>
using the --config-dir
option
Use the below command to connect to Cumulocity IoT or Azure IoT Hub
cloud using --config-dir
$ sudo tedge --config-dir /global/path/to/config/dir connect c8y/az
Here the path/to/config/dir
is the directory where the configuration files are present.