DEV Community

Chris McKelt
Chris McKelt

Posted on • Originally published at blog.mckelt.com on

3 3

AZURE IOT EDGE – Developing custom modules

Series


Part 1 - dotnet vs python vs node - temperature emission - who is cooler?

Part 2 - Developing modules
Part 3 - Custom Containers using Apache Nifi
Part 4 - Custom Module using TimescaleDB
Part 5 - Custom Module using Grafana

Intro

This is part 2 in a series starting here that runs through an Azure IOT Edge solution located at: https://github.com/chrismckelt/edgy

This part will cover developing and running custom modules written in C#, Python and NodeJS.

It will focus on commands available in the VS Code interface rather than command line arguments as seen at: https://aka.ms/iotedgedev

Azure IoT SDKs

Azure IoT Edge has a number of SDKs for module development in your favourite language. The SDK code will handle setting up environment variables and provide the boiler plate code necessary to send and receive messages using multiple protocols & channels (e.g. MQTT, AMQP)

Setting up VS Code to run the local simulator

Given the solution is cloned locally and Azure is setup with our IOT Hub we can configure a device to act as a local simulator.

  1. Select IOT Hub & choose your IOT Hub

  1. Create IOT Edge Device - I have named my local device ‘LocalSimulator

  1. Setup IOT Edge Simulator – this will create you edge certs

This will generate and install certificates for local development in the following folder & also install the for you note://run VS Code as admin for this

Creating a module for our solution

Right click on the modules folder and select ‘Add IoT Edge Module’.

This will then ask a module name & language (C,C#,Java,Node.js, Python)

This post will focus on the data generator/recorder modules below:

Data Generators

The demo code shows 3 ‘data generator’ modules written in C#, Python & Node JS.

Each module publishes a message every second simulating temperature capture. Properties of the sent message are:

public class Payload
{
public DateTime TimeStamp { get; set; }
public bool IsAirConditionerOn { get; set; }
public double Temperature { get; set; }
public string TagKey { get; set; }
}
view raw Payload.cs hosted with ❤ by GitHub

In C# connecting to the Edge Hub and sending messages can be seen in the following code:

var connectionSettings = new MqttTransportSettings(TransportType.Mqtt_Tcp_Only); // setup connection to hubs MQTT broker
ITransportSettings[] settings = { connectionSettings };
ioTHubModuleClient = await ModuleClient.CreateFromEnvironmentAsync(); // inbuilt SDK magic to connect using environment variables
await ioTHubModuleClient.OpenAsync(); // connect
var chance = new Chance(42); // random data generator
var payload = chance.Object<Payload>();
var currentTemp = 20d;
for (int i = 0; i < 1000; i++)
{
currentTemp = currentTemp + chance.Double(0, 1);
payload.Temperature = currentTemp;
payload.IsAirConditionerOn = chance.Bool(payload.Temperature);
payload.TagKey = "dotnet";
payload.TimeStamp = DateTime.Now; // just display in local time for demo
var msg = JsonConvert.SerializeObject(payload);
var messageBytes = Encoding.UTF8.GetBytes(msg);
using (var pipeMessage = new Message(messageBytes))
{
await ioTHubModuleClient.SendEventAsync("output1", pipeMessage);
Log.Information("sent: " + msg);
}
Thread.Sleep(1000);
i++;
}

Data Recorders

3 modules in matching languages subscribe to their respective modules published messages

ModuleClient ioTHubModuleClient;
var connectionSettings = new MqttTransportSettings(TransportType.Mqtt_Tcp_Only);
ITransportSettings[] settings = { connectionSettings };
ioTHubModuleClient = await ModuleClient.CreateFromEnvironmentAsync();
await ioTHubModuleClient.OpenAsync(); // Open a connection to the Edge runtime
// Register callback to be called when a message is received by the module
await ioTHubModuleClient.SetInputMessageHandlerAsync("input1", PipeMessage, ioTHubModuleClient);
view raw DataRecorder.cs hosted with ❤ by GitHub

Messages received are deserialized from JSON format to a POCO and then saved in a database.

// This method is called whenever the module is sent a message from the EdgeHub. It just pipe the messages without any change.It prints all the incoming messages.
static async Task<MessageResponse> PipeMessage(Message message, object userContext) {
int counterValue=Interlocked.Increment(ref _counter);
var moduleClient=userContext as ModuleClient;
byte[] messageBytes=message.GetBytes();
string messageString=Encoding.UTF8.GetString(messageBytes);
if (!string.IsNullOrEmpty(messageString)) {
try {
Log.Information($"Receiving Message: {messageString.TrimStart('"').TrimEnd('"').Replace('\\', ' ')}");
Payload payload=JsonConvert.DeserializeObject<Payload>(messageString.TrimStart('"').TrimEnd('"').Replace("\\", String.Empty));
await SaveData(payload); // save in database
}
catch (Exception ex) {
Log.Error($"Error processing message: {ex}");
}
}
return await Task.FromResult(MessageResponse.Completed);
}
view raw PipeMessage.cs hosted with ❤ by GitHub

Routes

In order to route messages between modules we use the inbuilt route system in our deployment template file.

Web App – Viewer module

Finally to view the messages from a web page I have modified an existing demo to that uses SignalR view all messages sent to it from the below routes:

When running the solution you can view all published messages on the web page below

Outro

Here was a basic overview of an demo solution to create and build your own custom IoT Edge modules.

Next we will introduce an existing docker container (Apache Nifi) to act as a data orchestrator. This will subscribe to all 'Payload' messages and publish a message to ‘turn off’ the air conditioner when the temperature is too high.

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more