Manipulate IoT Edge Module twin using an Azure Function

We use IoT Central a lot for demonstration purposes. It provides an IoT Dashboard for your IoT devices on a SaaS level. It brings speed into the projects and we can have good discussions about usability with customers.

Recently, I had to add some buttons in IoT Central to manipulate an IoT Edge device. At this moment, IoT Central is not supporting IoT Edge devices but it can be done with a simple trick. So displaying information is not that hard. But sending module twin changes back to the IoT edge is not simply done.

In this blog, I show how to program IoT Edge module twin updates using c#. I use Azure Functions to make this code reachable from other sources like IoT Central.

Desired properties

Both an Azure IoT device and an Azure IoT Edge device support modules. Modules are Docker containers in case of IoT Edge. Each IoT Edge container supports a module Twin with desired and reported properties.

The module retrieves desired properties from the cloud and reports back what it has accomplished based on the desired properties in the reported properties.

Azure Function

So we want to manipulate the desired properties. Reading reported properties is out of scope but easy to accomplish.

This is how an Azure Function looks like, using an HTTP trigger:

#r "Newtonsoft.Json"

using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;

using Microsoft.Azure.Devices;
using Microsoft.Azure.Devices.Shared;

public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
  string threshold = req.Query["t"];
  var setpoint = Convert.ToInt32(threshold);
  log.LogInformation($"Trigger function processed a request {threshold}");

  var connectionString = "[IoT Hub connection string]";
  var deviceID = "demodevice";
  var moduleID = "modbusCommand";

  using (var registryManager = RegistryManager.CreateFromConnectionString(connectionString))
    var twin = await registryManager.GetTwinAsync(deviceID, moduleID);
    twin.Properties.Desired["setpoint"] = setpoint;
    await registryManager.UpdateTwinAsync(deviceID, moduleID, twin, twin.ETag);

  return (ActionResult)new OkObjectResult($"Processed {threshold}");

Note: we need an IoTHub connection string. For simplicity, it’s written down in the source code here. It is recommended to use an Azure Vault to protect your secrets in production.

As you can see, we use a RegistryManager to retrieve the module twin. We manipulate the desired property named ‘setpoint’ and send back the twin to the module.

This UpdateTwinAsync method has several overloads. Most of them are related to the device twin but we need this extra moduleid to manipulate a module twin.

Note: Here I sent the complete twin back to the IoTHub. The documentation refers to a ‘twinPatch’ so a partial update should be sufficient too. An example of a module twin patch can be found here.

This Azure Function needs a Nuget Package to compile. Add an extra file named ‘function.proj’:

<Project Sdk="Microsoft.NET.Sdk">
    <PackageReference Include="Microsoft.Azure.Devices" Version="1.17.3" />

This looks like:


Try to recompile. It should succeed…

Now you can reach out to the function with a post on the related URL. My call looks like:

https://[project][api key]==&t=40

At the end of the URL, I added ‘&t=42’. This is how the threshold is passed on using a Query.

In Postman it looks like:


See how the twin change is picked up:


The desired property value is set. And the module seems to have it picked up already. The reported property (set by the module) resembles the same value.

IoT Central button

Now we switch over to IoT Central. In IoT Central, we can alter dashboards at several places. We focus here on the device template.

If I open the device template dashboard, I am able to add several widgets:


As you can see, there seems to be no button. But there is an Image widget which accepts an URL. this URL is used to navigate, jump between dashboards and external resources.

We use it to set the setpoint:


Add a picture with some meaningful text or icon to it. I added this really boring image with only the text ’50’ on it. And I set the query threshold value to 50 too.

Save it and test it.

Note: There is a side effect of this approach. The jump to this URL will open a second browser page which shows the outcome of the jump. Normally this will result in a new website which is great. But we are not really interested in:


A workaround is to right-click on it: ‘Open in new tab’. This will result in a new tab page but the focus will stay on your dashboard.


In this blog, we have seen how we can change the desired properties of an IoT Edge device using C# code. We used an Azure HTTP Trigger function to accomplish this.

And we have seen how we can integrate IoT Edge into IoT Central. It’s not something I recommend in production. But for demos and as a starting point for discussions with customers it’s viable.

Let’s hope Microsoft will support IoT Edge soon in IoT Central, that combination will become very powerful.