Azure IoT Hub Cloud Connection: Difference between revisions

From Teltonika Networks Wiki
No edit summary
No edit summary
 
(28 intermediate revisions by 2 users not shown)
Line 1: Line 1:
<b>Azure IoT Hub</b> is an open and flexible cloud platform that supports open-source SDKs and multiple protocols.


__TOC__
__TOC__
==Introduction==
==Introduction==
This article contains instructions on how to configure a Teltonika Networks device in order to connect to the Azure IoT Hub. <b>Azure IoT Hub</b> is a managed service hosted in the cloud that acts as a central message hub for communication between an IoT application and its attached devices.


This article contains instructions on how to configure a RUT router in order to connect to the Azure IoT Hub.<br>
The information in this page is updated in accordance with the RutOS 7.8 firmware version.


{{Template:Networking_rutx_manual_fw_disclosure
For information on Azure services utilizing legacy firmware, please click [https://wiki.teltonika-networks.com/view/Azure_IoT_Hub_cloud_connection_(Legacy_WebUI) here].
| fw_version = RUTX_R_00.02.01.1
}}


For a wiki on Azure services based on RutOS versions prior to the 7.8 update, please click [https://wiki.teltonika-networks.com/view/Azure_IoT_Hub_cloud_connection_RUTOS here].


==Prerequisites==
==Prerequisites==
Line 16: Line 14:
You will need:
You will need:


*A router from the RUTX09 or RUTX11
*A Teltonika Networks device;
*An Azure IoT Hub account
*An Azure IoT Hub account.


==Azure account creation==
==Azure account creation==
Line 26: Line 24:


<ul>
<ul>
     <li>First you will want to create a Resource group for easier management of resources that you will add later. In Microsoft Azure home page.</li>
     <li>First you will want to create a Resource group for easier management of resources that will be added later. In Microsoft Azure home page.</li>
     <ul>Select '''Resource groups''' <br>If it is not in very first page, click '''More services''' and locate it there. </ul>  
     <ul>Select '''Resource groups''' <br>If it is not in very first page, click '''More services''' and locate it there. </ul>  
     <div>[[File:Azure01.png|border|class=tlt-border|800px]]</div>
     <div>[[File:Azure01.png|border|class=tlt-border|800px]]</div>
Line 32: Line 30:
[[File:Azure02.png|border|class=tlt-border]]
[[File:Azure02.png|border|class=tlt-border]]


<li>And then finish creating yours Resource group </li>
<li>And finish creating the Resource group </li>


Select your subscription, we are using '''Free Trial''' for this test.  
Select your subscription, for this example '''Free Trial''' will be used.  
#Name your group
#Name your group
#Finally, choose server location for meta data. We will choose '''''(South America) Brazil South''''' and will use it during test where available.
#Choose server location for meta data. We will choose '''''(South America) Brazil South''''' and will use it during this example.
[[File:Azure03_RUTX.png|border|class=tlt-border]]
[[File:Azure03_RUTX.png|border|class=tlt-border]]


<li>At this moment we will skip adding Tags since we will be able to do that later if needed, so simply press '''Review + create''' at the bottom of screen and then click Create to finish setup.</li>
<li>At this moment Tags will be skipped, press '''Review + create''' at the bottom of screen and click Create to finish setup.</li>
[[File:Azure04.png|border|class=tlt-border]]
[[File:Azure04.png|border|class=tlt-border]]
<br>
<br>
[[File:Azure05_RUTX.png|border|class=tlt-border]]
[[File:Azure05_RUTX.png|border|class=tlt-border]]


<li>You will be redirected to Homepage, then click on '''Resource groups'''. You should see yours newly created group, select it, and press '''Add'''.</li>
<li>After being redirected to Homepage click on '''Resource groups'''. You should see the newly created group, select it and press '''Add'''.</li>


[[File:Azure06_RUTX.png|border|class=tlt-border|800px]]
[[File:Azure06_RUTX.png|border|class=tlt-border|800px]]
Line 56: Line 54:
     <div>1. Region – '''(South America) Brazil South''' as before</div>  
     <div>1. Region – '''(South America) Brazil South''' as before</div>  
     <div>2. Create a name for IoT Hub</div>
     <div>2. Create a name for IoT Hub</div>
     <div>3. Then go to '''Size and scale tab''' </div>
     <div>3. Go to '''Size and scale tab''' </div>
</li>
</li>
[[File:Azure08_RUTX.png|border|class=tlt-border|800px]]
[[File:Azure08_RUTX.png|border|class=tlt-border|800px]]
Line 62: Line 60:
   <div>At the bottom of the screen '''Review + create'''</div>
   <div>At the bottom of the screen '''Review + create'''</div>
[[File:Azure09.png|border|class=tlt-border|800px]]
[[File:Azure09.png|border|class=tlt-border|800px]]
     <div>And finally, Click on >> '''Create''' </div>
     <div>Click on >> '''Create''' </div>
[[File:Azure10_RUTX.png|border|class=tlt-border|400px]]
[[File:Azure10_RUTX.png|border|class=tlt-border|400px]]
   <div>'''Note:''' Wait until resource deploys and press Go to '''Resources''' </div>
   <div>'''Note:''' Wait until resource deploys and press Go to '''Resources''' </div>
Line 79: Line 77:
[[File:Azure13_RUTX.png|border|class=tlt-border|400px]]
[[File:Azure13_RUTX.png|border|class=tlt-border|400px]]


     <li>After you finish creation, you will be redirected back to IoT devices select yours newly created '''Device ID'''</li>
     <li>After creating a new device you will be redirected back to IoT devices. Select the newly created '''Device ID'''</li>
[[File:Azure14_RUTX.png|border|class=tlt-border|800px]]
[[File:Azure14_RUTX.png|border|class=tlt-border|800px]]


     <li>In your device window you will find information needed to connect RUT devices to Azure IoT Hub.</li>
     <li>In the device window you will find information needed to connect Teltonika devices to Azure IoT Hub.</li>
       <div>For now, we will only need '''connection string'''. Copy Primary Connection string by pressing copy icon next to it. </div>
       <div>For now only '''connection string''' will be used. Copy Primary Connection string. </div>
[[File:Azure16_RUTX.png|border|class=tlt-border|800px]]
[[File:Azure16_RUTX.png|border|class=tlt-border|800px]]


Line 89: Line 87:


==Configuring Azure IoT Hub on RutOS==
==Configuring Azure IoT Hub on RutOS==
To configure an Azure IoT Hub instance on a RUT device, it is essential to first install the Azure IoT Hub package via the package manager.
To configure an Azure IoT Hub instance on the Teltonika device it is essential to install the Azure IoT Hub package via the package manager.
<ul>
<ul>
<li>To install required package, please on the router WebUI, navigate '''System > Package Manager''' and install Azure IoT Hub package </li>
<li>To install required package navigate to '''System > Package Manager''' and install Azure IoT Hub package </li>
[[File:Azure RutOSconf 1.png|border|class=tlt-border]]
[[File:Azure RutOSconf 1.png|border|class=tlt-border]]
</ul>
</ul>
Now navigate to ''' Services > Cloud solutions > Azure IoT Hub''' and add a new instance. In the pop-up window, you will notice two different connection types available:
Navigate to '''Services > Cloud solutions > Azure IoT Hub''' and add a new instance. In the pop-up window there will be two different connection types available:
<ul> <li> Shared Access signature (SAS) key </li>
<ul> <li> '''Shared Access signature (SAS) key''' </li>
<li> Device Provisioning Service (DPS) </li> </ul>
<li> '''Device Provisioning Service (DPS)''' </li> </ul>
In this article, we will demonstrate the configuration steps for both connection types.
In this article both connection types will be demonstrated.
===SAS key connection type configuration===
===SAS key connection type configuration===
Configuring Azure IoT Hub using the SAS key connection type is quite simple and straightforward. Please follow these three steps:
Configuring Azure IoT Hub using the SAS key connection type is straightforward:
<div>1. Make sure to enable the instance by pressing '''Enable''' button </div>
<div>1. Make sure to enable the instance by pressing '''"Enable"''' button </div>
<div>2. Paste previously copied '''Connection String'''</div>
<div>2. Paste previously copied '''"Primary Connection String"'''</div>
<div>3. Press '''Save & Apply''' button </div>
<div>3. Press '''"Save & Apply"''' button </div>
[[File:Azure RutOSconf 2.2.png|border|class=tlt-border]]
[[File:Azure RutOSconf 2.2.png|border|class=tlt-border]]
</ul>
</ul>
After the instance is correctly configured, you will be able to see the connection status on the Azure IoT Hub page of the WebUI. A green dot indicates that the connection is successful.
After the instance is correctly configured the connection status icon will be visible. A green dot indicates that the connection is successful.
[[File:Azure RutOSconf 3.png|border|class=tlt-border]]
[[File:Azure RutOSconf 3.png|border|class=tlt-border]]
Additionally, you can check the connection status through the router command line by executing the following command:
ubus call azure.1 get_connection_status
Upon executing this command, you will see its output. If the connection is successful, you will see the following output:
[[File:Azure RutOSconf 4.png|border|class=tlt-border]]


If you are able to see that the connection status is succesfully and authorized it means that connection is established using SAS key connection type. Now, lets move foward with configuration of Device Provisioning Service (DPS) connection type.
===Device Provisioning Service (DPS) configuration===
 
The IoT Hub Device Provisioning Service (DPS) is a helper service for IoT Hub that enables zero-touch, just-in-time provisioning to the right IoT hub without requiring human intervention, allowing customers to provision millions of devices in a secure and scalable manner.


===Device Provisioning Service (DPS) configuration===
One of the primary features of DPS is its capability to dynamically manage multiple device identities. This service manages the device identity creation using enrollments which can be configured using the following attestation types:
One of the primary features of DPS is its capability to dynamically manage multiple device identities. This service manages the device identity creation process using mechanisms called attestations. There are two such mechanisms:
<ul>
<ul>
<li> 1. X.509 </li>
<li> 1. X.509 intermediate certificates </li>
<li> 2. Symmetric keys </li>
<li> 2. Symmetric keys </li>
</ul>
</ul>
====DPS X.509 mechanism====
The first mechanism utilizes X.509 certificates. Each DPS service includes one or more services known as enrollment groups, which handle this task. Each enrollment group is configured to function with a specific IoT Hub, considering there may be multiple IoT Hubs. At the DPS, the root CA certificate needs to be registered. Additionally, each enrollment group should have one or more intermediate CAs that are signed by the root CA. Each RUT device must have a unique certificate signed by an intermediate CA. This certificate contains additional information, such as the subject ID field, which will serve as the device identity name on the IoT Hub. Now, let's delve into an actual example of configuring such a service.


To learn more about DPS service read about it [https://learn.microsoft.com/en-us/azure/iot-dps/ here]
====DPS X.509 attestation====
<ul>
<ul>
<div> 1. The initial step is to generate certificates. You can refer to the Microsoft guide to generate the required certificates successfully. The Microsoft guide can be found here: https://learn.microsoft.com/en-us/azure/iot-dps/tutorial-custom-hsm-enrollment-group-x509?pivots=programming-language-ansi-c#create-a-root-ca-certificate  
<div> 1. The initial step generating certificates. Refer to the Microsoft guide, section [https://learn.microsoft.com/en-us/azure/iot-dps/tutorial-custom-hsm-enrollment-group-x509?pivots=programming-language-ansi-c#create-an-x509-certificate-chain "''Create an X.509 certificate chain''"] for in depth information that explains each step of the process in detail.
 
The required certificates and keys:
The required certificates and keys:
<li> Root CA certificate </li>
<li> '''Root CA certificate''' </li>
<li> Intermediate CA certificate </li>
<li> '''Intermediate CA certificate''' </li>
<li> Devices certificates </li>
<li> '''Devices certificates''' </li>


Please ensure to carefully follow the Microsoft guide to create certificates, making sure not to miss any steps as they are all crucial.
2. After successfully generating the certificates return to the Azure portal page and navigate to your Azure IoT Hub Device Provisioning Service (DPS) page. From there proceed create an enrollment group. Refer to the Microsoft guide, section [https://learn.microsoft.com/en-us/azure/iot-dps/tutorial-custom-hsm-enrollment-group-x509?pivots=programming-language-ansi-c#create-an-enrollment-group "''Create an enrollment group''"] for in depth information.
</div>


Following the Microsoft guide, after creating the Root CA certificate, you will notice that it is named "Azure IoT Hub CA Cert Test Only".
3. Return to the device WebUI and navigate to '''Services -> Cloud Solutions -> Azure IoT Hub''' page to create a new configuration instance:
[[File:Azure RutOSconf 5.png|border|class=tlt-border]]
After creating the root CA certificate, an intermediate CA certificate must be generated. Upon inspecting this certificate, you should notice that it is issued by the "Azure IoT Hub CA Cert Test Only", as seen previously.
[[File:Azure RutOSconf 6.png|border|class=tlt-border]]
After successfully creating the intermediate CA certificate, proceed with creating the device certificate and signing it using the intermediate authority. It's crucial to note that the subject field will be the name of the newly registered identity on the IoT Hub page. If you are following the provided Microsoft guide, you can observe "device-01" name, remember it as it will be used in later configurations steps.
[[File:Azure RutOSconf 7.png|border|class=tlt-border]]


Finally, we append the root CA, intermediate CA, and device certificates into one certificate chain. If you are following the guide, the "device-01-full-chain.cert.pem" file will be created. Later, we will upload this file to the RUT device WebUI page.
3.1 Set connection type as a '''Device Provisioning Service (DPS)''';
</div>
<div>
2. After successfully generating the certificates, return to the Azure portal page and navigate to your Azure IoT Hub Device Provisioning Service (DPS) page. From there, proceed to the certificate page and upload the root CA file.
[[File:Azure RutOSconf 8.png|border|class=tlt-border]]
</div>


3. Next, navigate to the "Manage Enrollments" page to register the intermediate CA and target our IoT Hub service instance.
3.2 Enter '''"ID Scope"''' of your DPS service page on Azure. This value can be retrieved from the DPS instance found on Azure Portal page or by following the earlier guide;


[[File:Azure RutOSconf 9.1.png|border|class=tlt-border]]
3.3 Specify the '''"Registration ID"'''. This is the subject common name (CN) of the device leaf certificate that was created using the earlier guide.
[[File:Azure RutOSconf 10.png|border|class=tlt-border]]


4. The final step is to return to the RUT device WebUI and navigate to '''Services -> Cloud Solutions -> Azure IoT Hub''' page to create a new configuration instance. In the configuration pop-up window, please follow these steps:
3.4 Upload the certificate chain file and the private key file.  
4.1 Set connection type as a '''Device Provisioning Service (DPS)''';
4.2 Enter '''ID Scope''' of your DPS service page on Azure;
4.3 Specify the '''Registration ID'''. Remember the "device-01" one? If you followed the Microsoft guide step by step, you need to enter "device-01" in the "Registration ID" field.
4.4 Lastly, upload the certificate chain file and the private key file.  


With all the required values in place, the configuration pop-up window should resemble the screenshot below:
With all the required values in place the configuration pop-up window should resemble the screenshot below:


[[File:Azure RutOSconf 11.png|border|class=tlt-border]]
[[File:Azure RutOSconf 11.png|border|class=tlt-border]]


After a couple of seconds, you will be able to observe the status of your configured instance in the Azure IoT Hub page on the router WebUI.
After a couple of moments the status of the configured instance status icon should turn green indicating the device has successfully established connection to Azure server.


[[File:Azure RutOSconf 12.png|border|class=tlt-border]]
[[File:Azure RutOSconf 12.png|border|class=tlt-border]]
The device successfully connects to the Azure IoT Hub.


====DPS Symmetric key mechanism====
====DPS Symmetric key mechanism====
Symmetric key mechanism is a more basic one. To configure it, firstly head back to Azure portal your DPS service page and create new enrollment group with Symmetric key attestation mechanism.
The Symmetric key mechanism configuration is more straightforward. To configure it go back to the Azure portal page, navigate to your DPS service page and create a new enrollment group with the Symmetric key attestation mechanism.


[[File:Azure RutOSconf 13.png|border|class=tlt-border]]
[[File:Azure RutOSconf 13.png|border|class=tlt-border]]


Inspecting the newly created enrollment group will reveal some keys. The primary key will be used to derive each individual device indentities. This can be done with simple script, which is available on the following Microsoft guide: https://learn.microsoft.com/en-us/azure/iot-dps/how-to-legacy-device-symm-key?tabs=linux&amp%3Bpivots=programming-language-ansi-c&pivots=programming-language-ansi-c#derive-a-device-key
Inspecting the newly created enrollment group will reveal some keys. The primary key will be used to derive each individual device identity. This can be done using a script which is available on Microsoft DPS documentation [https://learn.microsoft.com/en-us/azure/iot-dps/how-to-legacy-device-symm-key?tabs=linux&amp%3Bpivots=programming-language-ansi-c&pivots=programming-language-ansi-c#derive-a-device-key here].
 
The script contains a couple of variables: '''"KEY"''' and '''"REG_ID"'''. The KEY field shall contain the primary key which is obtained from the newly created enrollment group. The '''"REG_ID"''' field specifies the device identity name that will be created. Upon executing the script a shared access key will be created.


In the script, you will see couple important variables - KEY and REG_ID. In the key field, we must specify primary key, which we take from new created enrollment group.
[[File:Azure symm example 1.png|border|class=tlt-border]]


[[File:Azure RutOSconf 14.1.png|border|class=tlt-border]]
Go back to the device WebUI '''Services -> Cloud Solutions -> Azure IoT Hub''' configuration page and add a new instance. In the configuration window select DPS connection type and Symmetric Key connection type.


<ul>
<li> In the '''"ID scope"''' field specify your Azure DPS service ID. This value can be retrieved from the DPS instance found on Azure Portal page or by following the earlier guides from Microsoft.</li>
<li> In the '''"Registration ID"''' field enter the '''"REG_ID"''' value that was specified in the earlier script.</li>
<li> In the '''"Symmetric key"''' field enter the output value of the script that was used earlier].</li>
</ul>
</ul>


==Checking if Data reaches Azure IoT Hub==
If you are following this guide your configuration window should look similar to the screenshot below.
<ul>
 
<li>From router side, connect to it with CLI or SSH client and write in command '''azure_iothub''' and press Enter </li>
[[File:Azure symm example 2 modified.png|border|class=tlt-border]]
<div>- You should get answer that looks something like that, depending on what information you chose to send. </div>
 
[[File:Azure19_RUTX.png|border|class=tlt-border]]
After a few moments the device should establish connection to the Azure server.
<li>From Azure IoT Hub side you can check if it receives data. Go to IoT Hub that you created previously. Select '''Overview''', there you can see:  
 
</li>
After returning to the IoT Hub services in the Azure portal page it can be observed that the DPS service has created a new device identity was named the same as what we specified in the '''"REG_ID"''' field in the script.
<div>1. How many devices are connected to hub, and how many messages it sent during chosen period of time.</div>
 
<div>2. Device to cloud messages, that your router is sending.</div><br>
[[File:Azure symm example 3.png|border|class=tlt-border]]
<div>It should look something like that if IoT Hub is receiving data. </div>
 
[[File:Azure20_RUTX.png|border|class=tlt-border|800px]]
</ul>
<li>To capture logs you will need '''Device Explorer''' for IoT Hub Devices.</li>
 
<div>For Windows you can get here: https://github.com/Azure/azure-iot-sdk-csharp/releases/tag/2019-1-4 </div><br>
==Direct methods configuration==
<div>Scroll down to Assets, download and install '''SetupDeviceExplorer.msi''' </div>
 
[[File:Azure21.png|border|class=tlt-border]]
IoT Hub direct methods enable you to remotely invoke calls on devices from the cloud. Direct methods follow a request-response pattern and are meant for communications that require immediate confirmation of their result.
<li>Now you will need connection string of yours Azure IoT Hub, Not device. Navigate to IoT hub in your browser, then:</li>
 
<div>1. Click '''Shared access policies'''</div>
By default, all configuration instances will have this option disabled. To enable it, navigate on the router WebUI to '''Services -> Cloud Solutions -> Azure IoT Hub''' and press the edit button on the specific instance. Afterwards the "'''Enable Direct Methods'''" option needs to be enabled.
<div>2. Next choose '''iothubowner'''</div>
 
<div>3. And copy '''Connection string – primary key'''</div>
[[File:Azure RutOSconf 19.png|border|class=tlt-border]]
[[File:Azure22-1_RUTX.png|border|class=tlt-border|800px]]
 
For testing and demonstration purposes we will use the Azure IoT Explorer application. The Azure IoT Explorer is a graphical tool for interacting with devices connected to your IoT hub. To learn more about this tool you can follow the Microsoft documentation [https://learn.microsoft.com/en-us/azure/iot/howto-use-iot-explorer here].
 
===Using internal device API with Direct Methods===
 
After enabling the direct method feature go to Azure IoT Explorer, select the appropriate device identity and navigate to the direct methods tab. All our devices support the '''"api_call"''' direct method which exposes the API interface to be used from the Azure side. In this example we will make a simple GET request to retrieve the I/O status of the device. Full documentation of Teltonika devices API can be found [https://developers.teltonika-networks.com/ here] .
 
The Azure IoT Explorer direct method tab will have a Payload field. In this field the '''"api_call"''' method expects JSON formatted data.
 
[[File:Azure RutOSconf 20.png|border|class=tlt-border]]
 
The API call expects at least two parameters. The first one is called '''"method"''' which needs to have an integer value between zero and three, corresponding to the API method type - either GET, POST, PUT or DELETE. The second parameter is '''"endpoint"''' which expects a string value of the API endpoint. In this case, we will call the '''"/io/status"''' endpoint.
 
[[File:Azure RutOSconf 22.1.png|border|class=tlt-border]]
 
After pressing the "'''Invoke Method'''" button the response from the device will be visible which is a standard API response specified in our [https://developers.teltonika-networks.com/fundamentals/#request-and-response-structures documentation].
 
[[File:Azure RutOSconf 21.png|border|class=tlt-border]]
 
To determine the appropriate payload and method to use we provide an additional file currently called '''"teltonikaGenericDevice.json"'''. This file is written in '''Digital Twin Definition Language (DTDL)'''. To learn more about DTDLs and Digital Twins read about it in Microsoft documentation [https://learn.microsoft.com/en-us/azure/digital-twins/concepts-models here].
 
In this file you can see that it supports the api_call method, which accepts three values. The request body is optional, as some methods, such as the GET method, may not require it. JSON files can be downloaded  [[Media:Teltonika-dtmi-docs.zip|here]].
 
The IoT Explorer can be configured to parse DTDL files and display them to the user for easier work.
 
===IoT plug and Play configuration===
 
Navigate to the "'''IoT Plug and Play components'''" tab on the IoT Explorer. Initially there may be an error stating that it did not retrieve an interface model. To resolve this click on the "'''Configure'''" button. In this guide a local folder will be added by pressing the "'''Add'''" button.
 
[[File:Azure RutOSconf 23.png|border|class=tlt-border]]
 
The specified directory must have the DTDL '''".json"''' files. After adding the local folder press the '''"Save"''' button.
 
Return to the device identity Plug and Play tab. Now you will be able to see two components with model IDs named "'''genericDevice'''" and "'''deviceInformation'''". The generic device will display the DTDL interface description.
 
[[File:Azure RutOSconf 24.png|border|class=tlt-border]]
 
In the upper toolbar select the "'''Commands'''" tab. There you will see that IoT Explorer has parsed the API call method and created three new fields. Now we can try to call the same I/O status method that we called previously.
 
[[File:Azure RutOSconf 25.png|border|class=tlt-border]]
 
We can see that some information was correctly retrieved from the router. This workflow makes it easier to work with API calls from the Azure side.
 
==Sending data with "Data to Server" feature==
 
The Data to Server service allows you to set up collections that collect data from various sources and periodically sends it to various servers. We can configure this feature to send data from the device to Azure IoT Hub.
 
===Data to Server configuration===


<li>After that go back to Device Explorer: </li>
To configure the '''Data to Server''' service on Teltonika devices navigate to '''Services -> Data to Server''' on the WebUI. This guide will cover only the collection output part. To learn more about Data to Server features you can find the dedicated guide on our Wiki. From this point it is assumed the collection is properly set up with correct inputs.
<div>1. In Configuration tab paste in Connection string that you just copied</div>
<div>2. Copy HostName part from connection string and paste it in '''Protocol Gateway HostName'''</div>
<div>3. Click '''Update''' </div>
[[File:Azure23_RUTX.png|border|class=tlt-border|600px]]


<li>Open Management tab </li>
<li> In the server configuration configuration window, choose "'''Type'''" as a "'''Azure IoT Hub'''" option; </li>
<div>1. Click Update </div>
<div>2. You should see your device in the list below and '''Connection state''' </div>
[[File:Azure24_RUTX.png|border|class=tlt-border|800px]]


<li>Go to Data tab</li>
In the "Configuration type" field you can choose whether to use an existing Azure IoT Hub configuration or configure a new and unique Azure IoT Hub configuration. In this example we will stick with the previously created Azure IoT Hub instance configuration.
<div>1. Click monitor, and wait for '''Event Hub Data''' to update (Depends on yours chosen interval)</div>
<div>2. Messages like this should start appearing. </div>
[[File:Azure25_RUTX.png|border|class=tlt-border|600px]]


==Setting router to Forward MQTT messages/commands to Azure IoT Hub==
If you choose to create a new unique Azure IoT Hub configuration on the Data to Server instance you will need to input all the options that were discussed earlier in this guide.
<div>First you will need MQTT broker to subscribe to, for testing purposes we will set MQTT Broker in same router, and will use PC from LAN to sent MQTT messages.</div>


<li>Go to Services > MQTT > Broker </li>
<li> Select your preferred Azure IoT Hub instance; </li>
<div>1. Click '''Enable'''</div>
<li> Press "'''Save & Apply'''" button. </li>
<div>2. Use same port in MQTT Broker and Azure IoT Hub settings.</div>
<div>3. Press '''Save'''</div>
[[File:Azure26-1_RUTX.png]]


<li>Go to '''Services > Cloud solutions > Azure IoT Hub'''</li>
If you are following this guide your configuration should resemble something similar to the screenshot below.
<div>1. Enable monitoring </div>
<div>2. Use same Connection string as before (GSM values configuration) </div>
<div>3. Messages Type choose '''MQTT messages''' </div>
<div>4. Enter MQTT Host address, we are using 127.0.0.1 since our broker is set up on same router.</div>
<div>5. Port '''Same as MQTT Broker'''</div>
<div>6. And Topic under which router will subscribe to MQTT Broker</div>
<div>7. Press '''Save''', we will not need username or password.</div>
[[File:Azure27-2_RUTX.png]]


[[File:Azure RutOSconf 28.png|border|class=tlt-border]]
</ul>
</ul>
==Checking if MQTT messages are being forwarded to Azure IoT Hub==


===Linux===
====Checking if data reaches IoT Hub on Azure====
<ul>
 
<div>Connect to router with SSH, in logread you should see Router establishing connection to Azure IoT Hub: </div>
To determine whether data successfully reaches Azure IoT Hub select your device and navigate to the "Telemetry" tab on the Azure IoT Explorer. Ensure that '''"Use built-in event hub"''' option is enabled and press the '''"Start"''' button. After some time you should see that data was sent from the device to the Azure IoT Hub.
[[File:Azure27-1.png|border|class=tlt-border]]
 
<li>Open terminal and publish to MQTT Broker message with previously chosen topic.<br>
[[File:Azure RutOSconf 29.png|border|class=tlt-border]]
For our example we are using example: '''mosquito_pub -h 192.168.1.1 -p 8883 -m ‘testing Azure MQTT messages’ -t test''' </li>
 
<br><div>If everything was configured correctly in Device Explorer Data tab you should receive message like: </div>
==Example use cases==
[[File:Azure28_RUTX.png|border|class=tlt-border|1000px]]
 
<div>This means our router Forwards MQTT messages to Azure IoT Hub. </div>
This section shows some practical examples that combines most of the features that are discussed earlier.
</ul>
 
===Dynamically monitoring Modbus data===
 
This example shows how to monitor and dynamically control Modbus data purely from the Azure cloud. We will set up a simple Modbus TCP server and client with Data to Server which will forward all the incoming Modbus data to Azure IoT Hub. In the end using direct methods we will showcase how Modbus TCP client can collect and report different data from the cloud.
[[File:698929 TOPO 1.png|border|class=tlt-border]]
For this we will be using the following services:
 
*Azure IoT Hub;
*Data to Server;
*Modbus TCP Server;
*Modbus TCP Client;
*An Azure IoT Hub account.
 
In this example the Azure IoT Hub WebUI service configuration will not be covered since all the necessary information can be found in the earlier sections.
 
====Modbus TCP Server====
 
Enable the service in '''Services -> Modbus -> Modbus TCP Server''' with '''"Enable"''' option. For more information about this service you can find it on our Modbus Wiki [https://wiki.teltonika-networks.com/view/RUTX11_Modbus#Modbus_TCP_Server TCP server section]
 
====Modbus TCP Client====
 
Go to '''Services -> Modbus -> Modbus TCP Client''' page and create a new instance. This part will assume most of the configuration for this page is already made. For more information about this service you can find it on our Modbus Wiki [https://wiki.teltonika-networks.com/view/RUTX11_Modbus#Modbus_TCP_Client TCP client section].
 
For this use case a single Modbus request configuration will be created to request the current device timestamp:
 
*Data type: '''32bit UINT, Byte order 1,2,3,4'''
*Function: '''Read holding registers (3)'''
*First register number: '''2'''
*Register counter/Values: '''2'''
 
For device specific Modbus register information refer to the appropriate Wiki documentation.
 
====Data to Server====
 
1. Go to '''Services -> Data to Server''' page and create a new collection instance.
 
1.1. Select the input '''Type''' to '''"Modbus"''';
 
1.2. Change the '''Format type''' to '''"Custom"''';
 
1.3. In the '''Format string''' we will enter the following data:
'''{"Date (Linux timestamp)": %timestamp%, "MODBUS server ID": "%server_id%", "MODBUS server name" : "%server_name%", "Request name": "%name%", "Start register": "%addr%", "Register data (JSON object)": %data%, "Raw data": "%raw_data%"}'''
This will form requests about Modbus data including the register values;
 
1.4. In the '''"Collection configuration"''' page select the '''"Format type"''' to '''"Custom"''';
 
1.5. Change the '''"Format string"''' to '''{ "input1": %input1% }'''. Make sure to change the '''%input1%''' value to your specific input name. Note that this value is not enclosed in braces. This is intentional since the braces are present in the Modbus input '''Format string''' field;
 
1.6. In the '''"Server configuration"''' select the '''"Type"''' to '''"Azure IoT Hub"''' and configure the Azure configuration instance in accordance to your needs.
 
====Monitoring and controlling incoming data====
 
Inspecting the incoming data to the Azure IoT Hub using Azure IoT Explorer reveals that Modbus data is being received successfully.
 
[[File:Azure modbus example 1 modified 1.png|border|class=tlt-border]]
 
In order to change the type of Modbus data sent to the Azure IoT Hub without going to the device WebUI the '''Direct Methods''' feature can be utilized. Using Azure IoT Explorer go to the device identity that was configured on the Teltonika device and select '''"Direct method"''' tab.
 
Using the '''"api_call"''' direct method create API requests that update the Modbus TCP Client request configurations (API reference for Modbus services can be found [https://developers.teltonika-networks.com/reference/7.6.10/v1/modbus/ here]. In this example the request configuration will be changed to collect '''"Mobile signal strength"'''. To do this using only API we will need to resolve the Modbus TCP client instance ID then the request ID of the instance which currently collects the temperature data. Using both of the IDs we will form the last API PUT request to update the register values:
 
2.1. Invoke '''"/modbus/client/tcp/config"''' GET request and inspect the output on IoT Explorer. The '''"data"''' array will contain JSON objects of every configured client instance. The '''"id"''' value will be used when forming the next API request;
 
[[File:Azure modbus example 2.png|border|class=tlt-border]]
 
2.2. Invoke '''"/modbus/client/tcp/{id}/requests/config"''' GET request and replace the '''"{id}"''' with the '''"id"''' value from the previous step. Inspecting the output will reveal the '''"data"''' array which contain JSON objects of every configured request. The '''"id"''' value of the request that collects temperature data will be used when forming the next API request;
 
[[File:Azure modbus example 3.png|border|class=tlt-border]]
 
2.3. Invoke '''"/modbus/client/tcp/{id}/requests/config/{request_id}"''' PUT request and replace the '''"{id}"''' with the '''"id"''' value from the 2.1. step and replace the '''"{request_id}"''' with the '''"id"''' value from the 2.2. step. In the '''"request_body"''' field add values to change the first register and data type values: '''{"data":{"first_reg":"4","data_type":"32bit_int1234"}}''' which corresponds to mobile signal strength register (other parameters such as number of registers stay the same since the timestamp register count is the same too).
 
[[File:Azure modbus example 4.png|border|class=tlt-border]]
 
2.4. Observe the incoming telemetry data. At this point the register data shall contain the mobile signal strength values.
 
[[File:Azure modbus example 5.png|border|class=tlt-border]]


===Windows===
This concludes the Azure IoT Hub guide. Using direct methods with device API is a powerful tool that unlocks new capabilities of device monitoring and control from the cloud. Nearly all features available via device WebUI are also available using API.
<ul>
<li>Install a MQTT client software to do the test, for this example we used MQTT.fx</li>
<div>1. Setup your Router IP Address</div>
<div>2. Use the '''same broker port'''</div>
<div>3. Paste your '''Connection string – primary key''' and click '''Apply'''</div>
[[File:Azure29-1_RUTX.png|border|class=tlt-border|800px]]


<div>1. Connect to the server broker</div>
'''
<div>2. Use the created topic. For this example '''test'''</div>
==External links==
<div>3. Send a message</div>
[[File:Azure30_RUTX.png|border|class=tlt-border|1000px]]


<li>If you did everything right this message will be shown in the device explorer</li>
# https://azure.microsoft.com/en-us/
</ul>
# https://developers.teltonika-networks.com/
# https://learn.microsoft.com/en-us/azure/iot/howto-use-iot-explorer
# https://learn.microsoft.com/en-us/azure/iot-dps/
# https://learn.microsoft.com/en-us/azure/iot-dps/how-to-legacy-device-symm-key?tabs=linux&amp%3Bpivots=programming-language-ansi-c&pivots=programming-language-ansi-c#derive-a-device-key
# https://learn.microsoft.com/en-us/azure/iot-dps/tutorial-custom-hsm-enrollment-group-x509?pivots=programming-language-ansi-c#create-an-x509-certificate-chain
# https://learn.microsoft.com/en-us/azure/iot-dps/tutorial-custom-hsm-enrollment-group-x509?pivots=programming-language-ansi-c#create-an-enrollment-group
# https://developers.teltonika-networks.com/reference/7.6.10/v1/modbus/
# https://wiki.teltonika-networks.com/view/RUTX11_Modbus#Modbus_TCP_Client
# https://wiki.teltonika-networks.com/view/RUTX11_Modbus#Modbus_TCP_Server
# https://learn.microsoft.com/en-us/azure/digital-twins/concepts-models
# https://developers.teltonika-networks.com/fundamentals/#request-and-response-structures

Latest revision as of 14:05, 22 July 2024

Introduction

This article contains instructions on how to configure a Teltonika Networks device in order to connect to the Azure IoT Hub. Azure IoT Hub is a managed service hosted in the cloud that acts as a central message hub for communication between an IoT application and its attached devices.

The information in this page is updated in accordance with the RutOS 7.8 firmware version.

For information on Azure services utilizing legacy firmware, please click here.

For a wiki on Azure services based on RutOS versions prior to the 7.8 update, please click here.

Prerequisites

You will need:

  • A Teltonika Networks device;
  • An Azure IoT Hub account.

Azure account creation

Visit https://azure.microsoft.com/en-us/ and create an account that will suit your needs, for testing purposes we will be using free Azure account.

Managing Azure services

  • First you will want to create a Resource group for easier management of resources that will be added later. In Microsoft Azure home page.
    • Select Resource groups
      If it is not in very first page, click More services and locate it there.
  • In new window, select Add
  • And finish creating the Resource group
  • Select your subscription, for this example Free Trial will be used.
    1. Name your group
    2. Choose server location for meta data. We will choose (South America) Brazil South and will use it during this example.
  • At this moment Tags will be skipped, press Review + create at the bottom of screen and click Create to finish setup.

  • After being redirected to Homepage click on Resource groups. You should see the newly created group, select it and press Add.
  • Select Internet of Things or simply search IoT Hub and press Create.
  • We leave default subscription and resource group and choose:
    1. Region – (South America) Brazil South as before
    2. Create a name for IoT Hub
    3. Go to Size and scale tab
  • For testing purposes, we are using F1: Free tier
  • At the bottom of the screen Review + create

    Click on >> Create

    Note: Wait until resource deploys and press Go to Resources


  • Inside IoT Hub list:
    Scroll down to Explorers and select IoT devices

  • Press New
  • In new device creation
    1. Enter Device ID
    2. Leave everything else on default and press Save
  • After creating a new device you will be redirected back to IoT devices. Select the newly created Device ID
  • In the device window you will find information needed to connect Teltonika devices to Azure IoT Hub.
  • For now only connection string will be used. Copy Primary Connection string.

Configuring Azure IoT Hub on RutOS

To configure an Azure IoT Hub instance on the Teltonika device it is essential to install the Azure IoT Hub package via the package manager.

  • To install required package navigate to System > Package Manager and install Azure IoT Hub package

Navigate to Services > Cloud solutions > Azure IoT Hub and add a new instance. In the pop-up window there will be two different connection types available:

  • Shared Access signature (SAS) key
  • Device Provisioning Service (DPS)

In this article both connection types will be demonstrated.

SAS key connection type configuration

Configuring Azure IoT Hub using the SAS key connection type is straightforward:

1. Make sure to enable the instance by pressing "Enable" button
2. Paste previously copied "Primary Connection String"
3. Press "Save & Apply" button

After the instance is correctly configured the connection status icon will be visible. A green dot indicates that the connection is successful.

Device Provisioning Service (DPS) configuration

The IoT Hub Device Provisioning Service (DPS) is a helper service for IoT Hub that enables zero-touch, just-in-time provisioning to the right IoT hub without requiring human intervention, allowing customers to provision millions of devices in a secure and scalable manner.

One of the primary features of DPS is its capability to dynamically manage multiple device identities. This service manages the device identity creation using enrollments which can be configured using the following attestation types:

  • 1. X.509 intermediate certificates
  • 2. Symmetric keys

To learn more about DPS service read about it here

DPS X.509 attestation

    1. The initial step generating certificates. Refer to the Microsoft guide, section "Create an X.509 certificate chain" for in depth information that explains each step of the process in detail.

    The required certificates and keys:

  • Root CA certificate
  • Intermediate CA certificate
  • Devices certificates
  • 2. After successfully generating the certificates return to the Azure portal page and navigate to your Azure IoT Hub Device Provisioning Service (DPS) page. From there proceed create an enrollment group. Refer to the Microsoft guide, section "Create an enrollment group" for in depth information.

    3. Return to the device WebUI and navigate to Services -> Cloud Solutions -> Azure IoT Hub page to create a new configuration instance:

    3.1 Set connection type as a Device Provisioning Service (DPS);

    3.2 Enter "ID Scope" of your DPS service page on Azure. This value can be retrieved from the DPS instance found on Azure Portal page or by following the earlier guide;

    3.3 Specify the "Registration ID". This is the subject common name (CN) of the device leaf certificate that was created using the earlier guide.

    3.4 Upload the certificate chain file and the private key file.

    With all the required values in place the configuration pop-up window should resemble the screenshot below:

    After a couple of moments the status of the configured instance status icon should turn green indicating the device has successfully established connection to Azure server.

    DPS Symmetric key mechanism

    The Symmetric key mechanism configuration is more straightforward. To configure it go back to the Azure portal page, navigate to your DPS service page and create a new enrollment group with the Symmetric key attestation mechanism.

    Inspecting the newly created enrollment group will reveal some keys. The primary key will be used to derive each individual device identity. This can be done using a script which is available on Microsoft DPS documentation here.

    The script contains a couple of variables: "KEY" and "REG_ID". The KEY field shall contain the primary key which is obtained from the newly created enrollment group. The "REG_ID" field specifies the device identity name that will be created. Upon executing the script a shared access key will be created.

    Go back to the device WebUI Services -> Cloud Solutions -> Azure IoT Hub configuration page and add a new instance. In the configuration window select DPS connection type and Symmetric Key connection type.

    • In the "ID scope" field specify your Azure DPS service ID. This value can be retrieved from the DPS instance found on Azure Portal page or by following the earlier guides from Microsoft.
    • In the "Registration ID" field enter the "REG_ID" value that was specified in the earlier script.
    • In the "Symmetric key" field enter the output value of the script that was used earlier].

    If you are following this guide your configuration window should look similar to the screenshot below.

    After a few moments the device should establish connection to the Azure server.

    After returning to the IoT Hub services in the Azure portal page it can be observed that the DPS service has created a new device identity was named the same as what we specified in the "REG_ID" field in the script.

Direct methods configuration

IoT Hub direct methods enable you to remotely invoke calls on devices from the cloud. Direct methods follow a request-response pattern and are meant for communications that require immediate confirmation of their result.

By default, all configuration instances will have this option disabled. To enable it, navigate on the router WebUI to Services -> Cloud Solutions -> Azure IoT Hub and press the edit button on the specific instance. Afterwards the "Enable Direct Methods" option needs to be enabled.

For testing and demonstration purposes we will use the Azure IoT Explorer application. The Azure IoT Explorer is a graphical tool for interacting with devices connected to your IoT hub. To learn more about this tool you can follow the Microsoft documentation here.

Using internal device API with Direct Methods

After enabling the direct method feature go to Azure IoT Explorer, select the appropriate device identity and navigate to the direct methods tab. All our devices support the "api_call" direct method which exposes the API interface to be used from the Azure side. In this example we will make a simple GET request to retrieve the I/O status of the device. Full documentation of Teltonika devices API can be found here .

The Azure IoT Explorer direct method tab will have a Payload field. In this field the "api_call" method expects JSON formatted data.

The API call expects at least two parameters. The first one is called "method" which needs to have an integer value between zero and three, corresponding to the API method type - either GET, POST, PUT or DELETE. The second parameter is "endpoint" which expects a string value of the API endpoint. In this case, we will call the "/io/status" endpoint.

After pressing the "Invoke Method" button the response from the device will be visible which is a standard API response specified in our documentation.

To determine the appropriate payload and method to use we provide an additional file currently called "teltonikaGenericDevice.json". This file is written in Digital Twin Definition Language (DTDL). To learn more about DTDLs and Digital Twins read about it in Microsoft documentation here.

In this file you can see that it supports the api_call method, which accepts three values. The request body is optional, as some methods, such as the GET method, may not require it. JSON files can be downloaded here.

The IoT Explorer can be configured to parse DTDL files and display them to the user for easier work.

IoT plug and Play configuration

Navigate to the "IoT Plug and Play components" tab on the IoT Explorer. Initially there may be an error stating that it did not retrieve an interface model. To resolve this click on the "Configure" button. In this guide a local folder will be added by pressing the "Add" button.

The specified directory must have the DTDL ".json" files. After adding the local folder press the "Save" button.

Return to the device identity Plug and Play tab. Now you will be able to see two components with model IDs named "genericDevice" and "deviceInformation". The generic device will display the DTDL interface description.

In the upper toolbar select the "Commands" tab. There you will see that IoT Explorer has parsed the API call method and created three new fields. Now we can try to call the same I/O status method that we called previously.

We can see that some information was correctly retrieved from the router. This workflow makes it easier to work with API calls from the Azure side.

Sending data with "Data to Server" feature

The Data to Server service allows you to set up collections that collect data from various sources and periodically sends it to various servers. We can configure this feature to send data from the device to Azure IoT Hub.

Data to Server configuration

To configure the Data to Server service on Teltonika devices navigate to Services -> Data to Server on the WebUI. This guide will cover only the collection output part. To learn more about Data to Server features you can find the dedicated guide on our Wiki. From this point it is assumed the collection is properly set up with correct inputs.

  • In the server configuration configuration window, choose "Type" as a "Azure IoT Hub" option;
  • In the "Configuration type" field you can choose whether to use an existing Azure IoT Hub configuration or configure a new and unique Azure IoT Hub configuration. In this example we will stick with the previously created Azure IoT Hub instance configuration. If you choose to create a new unique Azure IoT Hub configuration on the Data to Server instance you will need to input all the options that were discussed earlier in this guide.

  • Select your preferred Azure IoT Hub instance;
  • Press "Save & Apply" button.
  • If you are following this guide your configuration should resemble something similar to the screenshot below.

    Checking if data reaches IoT Hub on Azure

    To determine whether data successfully reaches Azure IoT Hub select your device and navigate to the "Telemetry" tab on the Azure IoT Explorer. Ensure that "Use built-in event hub" option is enabled and press the "Start" button. After some time you should see that data was sent from the device to the Azure IoT Hub.

    Example use cases

    This section shows some practical examples that combines most of the features that are discussed earlier.

    Dynamically monitoring Modbus data

    This example shows how to monitor and dynamically control Modbus data purely from the Azure cloud. We will set up a simple Modbus TCP server and client with Data to Server which will forward all the incoming Modbus data to Azure IoT Hub. In the end using direct methods we will showcase how Modbus TCP client can collect and report different data from the cloud. For this we will be using the following services:

    • Azure IoT Hub;
    • Data to Server;
    • Modbus TCP Server;
    • Modbus TCP Client;
    • An Azure IoT Hub account.

    In this example the Azure IoT Hub WebUI service configuration will not be covered since all the necessary information can be found in the earlier sections.

    Modbus TCP Server

    Enable the service in Services -> Modbus -> Modbus TCP Server with "Enable" option. For more information about this service you can find it on our Modbus Wiki TCP server section

    Modbus TCP Client

    Go to Services -> Modbus -> Modbus TCP Client page and create a new instance. This part will assume most of the configuration for this page is already made. For more information about this service you can find it on our Modbus Wiki TCP client section.

    For this use case a single Modbus request configuration will be created to request the current device timestamp:

    • Data type: 32bit UINT, Byte order 1,2,3,4
    • Function: Read holding registers (3)
    • First register number: 2
    • Register counter/Values: 2

    For device specific Modbus register information refer to the appropriate Wiki documentation.

    Data to Server

    1. Go to Services -> Data to Server page and create a new collection instance.

    1.1. Select the input Type to "Modbus";

    1.2. Change the Format type to "Custom";

    1.3. In the Format string we will enter the following data:

    {"Date (Linux timestamp)": %timestamp%, "MODBUS server ID": "%server_id%", "MODBUS server name" : "%server_name%", "Request name": "%name%", "Start register": "%addr%", "Register data (JSON object)": %data%, "Raw data": "%raw_data%"}
    

    This will form requests about Modbus data including the register values;

    1.4. In the "Collection configuration" page select the "Format type" to "Custom";

    1.5. Change the "Format string" to { "input1": %input1% }. Make sure to change the %input1% value to your specific input name. Note that this value is not enclosed in braces. This is intentional since the braces are present in the Modbus input Format string field;

    1.6. In the "Server configuration" select the "Type" to "Azure IoT Hub" and configure the Azure configuration instance in accordance to your needs.

    Monitoring and controlling incoming data

    Inspecting the incoming data to the Azure IoT Hub using Azure IoT Explorer reveals that Modbus data is being received successfully.

    In order to change the type of Modbus data sent to the Azure IoT Hub without going to the device WebUI the Direct Methods feature can be utilized. Using Azure IoT Explorer go to the device identity that was configured on the Teltonika device and select "Direct method" tab.

    Using the "api_call" direct method create API requests that update the Modbus TCP Client request configurations (API reference for Modbus services can be found here. In this example the request configuration will be changed to collect "Mobile signal strength". To do this using only API we will need to resolve the Modbus TCP client instance ID then the request ID of the instance which currently collects the temperature data. Using both of the IDs we will form the last API PUT request to update the register values:

    2.1. Invoke "/modbus/client/tcp/config" GET request and inspect the output on IoT Explorer. The "data" array will contain JSON objects of every configured client instance. The "id" value will be used when forming the next API request;

    2.2. Invoke "/modbus/client/tcp/{id}/requests/config" GET request and replace the "{id}" with the "id" value from the previous step. Inspecting the output will reveal the "data" array which contain JSON objects of every configured request. The "id" value of the request that collects temperature data will be used when forming the next API request;

    2.3. Invoke "/modbus/client/tcp/{id}/requests/config/{request_id}" PUT request and replace the "{id}" with the "id" value from the 2.1. step and replace the "{request_id}" with the "id" value from the 2.2. step. In the "request_body" field add values to change the first register and data type values: {"data":{"first_reg":"4","data_type":"32bit_int1234"}} which corresponds to mobile signal strength register (other parameters such as number of registers stay the same since the timestamp register count is the same too).

    2.4. Observe the incoming telemetry data. At this point the register data shall contain the mobile signal strength values.

    This concludes the Azure IoT Hub guide. Using direct methods with device API is a powerful tool that unlocks new capabilities of device monitoring and control from the cloud. Nearly all features available via device WebUI are also available using API.

    External links

    1. https://azure.microsoft.com/en-us/
    2. https://developers.teltonika-networks.com/
    3. https://learn.microsoft.com/en-us/azure/iot/howto-use-iot-explorer
    4. https://learn.microsoft.com/en-us/azure/iot-dps/
    5. https://learn.microsoft.com/en-us/azure/iot-dps/how-to-legacy-device-symm-key?tabs=linux&amp%3Bpivots=programming-language-ansi-c&pivots=programming-language-ansi-c#derive-a-device-key
    6. https://learn.microsoft.com/en-us/azure/iot-dps/tutorial-custom-hsm-enrollment-group-x509?pivots=programming-language-ansi-c#create-an-x509-certificate-chain
    7. https://learn.microsoft.com/en-us/azure/iot-dps/tutorial-custom-hsm-enrollment-group-x509?pivots=programming-language-ansi-c#create-an-enrollment-group
    8. https://developers.teltonika-networks.com/reference/7.6.10/v1/modbus/
    9. https://wiki.teltonika-networks.com/view/RUTX11_Modbus#Modbus_TCP_Client
    10. https://wiki.teltonika-networks.com/view/RUTX11_Modbus#Modbus_TCP_Server
    11. https://learn.microsoft.com/en-us/azure/digital-twins/concepts-models
    12. https://developers.teltonika-networks.com/fundamentals/#request-and-response-structures