Controlling an LED from the cloud using a C# Azure IoT Edge module on the Raspberry Pi

Please follow and share!
Twitter
Facebook
LinkedIn
RSS

This post expects that you have created an Azure IoT Edge device and have it registered with an existing IoT Hub (free or standard tier). If you need some help with this, see this blog post.

This article is part of The Fourth Annual C# Advent Calendar initiative by Matthew D. Groves. You’ll find other helpful articles and tutorials published daily by community members and experts there, so make sure to check it out every day.

Azure IoT Edge modules are deployed to devices as Docker containers. In this article we will create an Azure IoT Edge module to control an LED that is connected to the Raspberry Pi.

Wiring

Wiring diagram

In this diagram, we will connect the Raspberry PI GPIO7 pin to a 100 ohm resistor. Connect the other end of the resistor to the the cathode (+ve, long leg) of the LED. The anode of the LED (-ve, short leg) will be connected to the Raspberry PI ground (GND).

Create a Container Registry

Login to the Azure Portal and navigate to the resource group that contains your IoT Hub. From the top toolbar, select the + Add button.

In the Marketplace search box, search for Container Registry, and select it from the search results. Select Create on the resource overview screen.

In the Create container registry form, give the registry a globally unique name and ensure it is located in the appropriate region. You can select the Basic SKU. Select the Review + create button, then after validation passes, select Create.

Create container registry form

Navigate to the container registry resource once it’s deployed. From the left menu, select Access keys, then enable the Admin user switch. Make note of the Login server, Username and password values.

Container registry Access Keys

Creating the Azure IoT Edge Module

You have the choice to create the Azure IoT Edge module using Visual Studio or Visual Studio Code. In this case, I will be using Visual Studio Code. The pre-requisites needed are the following:

Create a folder where you would like the project to be created. Then open Visual Studio Code.

We will use the command palette to scaffold the project. Use CTRL+SHIFT+P to open the palette. First, login to Azure using the Azure: Sign in command. Next, execute the following command: Azure IoT Edge: New IoT Edge solution. In executing this command, you will be prompted for the following:

  • Folder where you’d like the solution created
  • The solution name
  • The module template (select C#)
  • The module name (LightControl)
  • The Docker image repository with the module name (registryloginserver.azurecr.io/lightcontrol)

Once the solution has been scaffolded, open the .env file, and add the CONTAINER_REGISTRY_USERNAME and CONTAINER_REGISTRY_PASSWORD values with those that you recorded from the Access keys section of the container registry.

Open a Terminal window (Powershell), and change directory into the modules/LightControl folder. Execute the following command to add GPIO support to our module:

dotnet add System.Device.GPIO

Open the modules\LightControl\Program.cs file and replace it with the following code listing (commented inline):

namespace LightControl
{
    using System;   
    using System.Runtime.Loader;    
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Azure.Devices.Client;
    using Microsoft.Azure.Devices.Client.Transport.Mqtt;
    using System.Device.Gpio;

    class Program
    {
        static int ledpin = 7; //GPIO 7
        static GpioController controller;

        static void Main(string[] args)
        {
            Init().Wait();

            // Wait until the app unloads or is cancelled
            var cts = new CancellationTokenSource();
            AssemblyLoadContext.Default.Unloading += (ctx) => cts.Cancel();
            Console.CancelKeyPress += (sender, cpe) => cts.Cancel();
            WhenCancelled(cts.Token).Wait();
        }

        /// <summary>
        /// Handles cleanup operations when app is cancelled or unloads
        /// </summary>
        public static Task WhenCancelled(CancellationToken cancellationToken)
        {
            var tcs = new TaskCompletionSource<bool>();
            cancellationToken.Register(s => ((TaskCompletionSource<bool>)s).SetResult(true), tcs);
            return tcs.Task;
        }

        /// <summary>
        /// Initializes the ModuleClient and sets up the callback to receive
        /// direct method calls from the IoT Hub
        /// </summary>
        static async Task Init()
        {
            MqttTransportSettings mqttSetting = new MqttTransportSettings(TransportType.Mqtt_Tcp_Only);
            ITransportSettings[] settings = { mqttSetting };

            // Open a connection to the Edge runtime
            ModuleClient ioTHubModuleClient = await ModuleClient.CreateFromEnvironmentAsync(settings);
            await ioTHubModuleClient.OpenAsync();
            Console.WriteLine("IoT Hub module client initialized.");
         
            //setup direct method handler 
            await ioTHubModuleClient.SetMethodDefaultHandlerAsync(DirectMethodCalled, ioTHubModuleClient);
            controller = new GpioController();
            controller.OpenPin(ledpin, PinMode.Output);
            Console.WriteLine("Initialized GPIO and listening for direct method call");

        }
        private static Task<MethodResponse> DirectMethodCalled(MethodRequest methodRequest, object userContext)
        {
            var data = Encoding.UTF8.GetString(methodRequest.Data);
            Console.WriteLine(data);
                      
           string result = "{\"result\":\"Executed direct method: " + methodRequest.Name + "\"}";

           switch(methodRequest.Name) {
               case "ON":
                    // Turn on the LED                    
                    controller.Write(ledpin, PinValue.High);
                    Console.WriteLine("LED SHOULD BE ON NOW");
                    break;
               case "OFF":
                    // Turn off the LED
                    controller.Write(ledpin, PinValue.Low);
                    Console.WriteLine("LED SHOULD BE OFF NOW");
                    break;
               default:
                    Console.WriteLine("Unknown method");
                    break;                   
           }
           //Acknowledge the receipt of the direct method call
           return Task.FromResult(new MethodResponse(Encoding.UTF8.GetBytes(result), 200));
           
        }

    }
}

Next, open the modules\LightControl\Dockerfile.arm32v7 file. Replace ONLY the first line of the file with the following (this will allow us to build the Linux based container on Windows):

FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-env

Build and push the LightControl module

Open the Command Palette once again, and execute the Azure IoT Edge: Build and Push IoT Edge Module Image. This command will publish our build to our Azure Container Registry. You can expect the following prompts:

  • Select module config file (select the modules\LightControl\module.json file)
  • Select Platform (select arm32v7)

Once the build has completed. Locate in the output the line that starts with Successfully tagged. Record the tag value. It should look something similar to: yourcontainerregistry.azurecr.io/lightcontrol:0.0.1-arm32v7

Build output

Add the module to be deployed to the Edge device

In the Azure Portal, navigate to your IoT Hub. From the left menu, select IoT Edge located in the Automatic Device Management section. From there, select your edge device from the list. Select Set modules from the top toolbar menu.

On the Set modules on device page, fill out the Container Registry Credentials section at the top of the form with the values you recorded when creating the registry.

The Container Registry Credentials section

In the IoT Edge Modules section, expand the + Add drop down and select IoT Edge Module.

Enter LightControl as the Module Name, and with the Module Settings tab selected, paste the tag value that you recorded earlier (similar to yourcontainerregistry.azurecr.io/lightcontrol:0.0.1-arm32v7).

Select the Container Create Options tab, and paste the following JSON. This will allow the Docker container we deploy access to the GPIO pins.

{
    "HostConfig": {
        "Privileged": true
    }
}

Select the Add button, to add this module to the list.

Module settings tab
Container Create Options

You should now be back on the Set modules on device screen. Select Review + create, then Create once validation has passed. This will return you to the Edge Device screen. Give the deployment a minute or two to reach your device, then select the Refresh button from the top toolbar. You should see LightControl listed as a module and reported by the device. Stay on this screen – we’ll be needing it momentarily.

Control the LED with a Direct Method call

Open a command prompt, and SSH into your Edge device. Once logged in execute the following command:

sudo iotedge logs -f LightControl

This command will show the console output of our module. Keep this window visible while you return to the Azure Portal Edge Device Screen. From the Modules list, select the LightControl module. This will open the Details screen for our LightControl Edge module. From the top toolbar, select the Direct method item.

On the Direct method form, for Method Name, you can enter the value ON or OFF. In the Payload field, you can optionally send additional information to the module direct method handler. Invoke the method by selecting the Invoke Method button from the top toolbar.

In my example, I called the method ON and passed in the payload JSON of: { “Initiator”: “CSAdvent” }

Invoke direct method

Once invoked, you should see your LED turn on! Not only that, but looking in your SSH window, you will see the console output that the light should be on.

Console output showing the light is on.

Feel free to invoke the OFF method and watch the LED and the console output.

Wrapping up!

I hope that this article helps demonstrate how to control GPIO pins from an Azure IoT Edge module. Enjoy the rest of the C# Advent series!

Please follow and share!
Twitter
Facebook
LinkedIn
RSS

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.