2
votes

I have an Azure IOThub that contains one edge device. Within this edge device I have several modules running and I can change the twin property of any individual module by connecting to it with it's connection string.

Now I would like the module to do something when it's twin property is changed but the module doesn't have access to it's connection string and it shouldn't because it shouldn't need to connect to itself.

How can a module detect it's twin property change without having a connection string?

I have followed this tutorial but this uses a connection string to detect changes: https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-csharp-csharp-module-twin-getstarted#create-a-module-identity

Here's the code for this module:

using System;
using Microsoft.Azure.Devices.Client;
using Microsoft.Azure.Devices.Shared;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace DataSyncService
{

    class Program
    {

        private const string ModuleConnectionString = "CONNECTION STRING";
        private static ModuleClient Client = null;
        static void ConnectionStatusChangeHandler(ConnectionStatus status,
                                                  ConnectionStatusChangeReason reason)
        {
            Console.WriteLine("Connection Status Changed to {0}; the reason is {1}",
                status, reason);
        }

        static void Main(string[] args)
        {
            Microsoft.Azure.Devices.Client.TransportType transport =
                Microsoft.Azure.Devices.Client.TransportType.Amqp;

            try
            {
                Client =
                    ModuleClient.CreateFromConnectionString(ModuleConnectionString, transport);
                Client.SetConnectionStatusChangesHandler(ConnectionStatusChangeHandler);
                // I want to set this callback but this requires a client and the client requires
                // a connection string.    
                Client.SetDesiredPropertyUpdateCallbackAsync(OnDesiredPropertyChanged, null).Wait();

                Console.WriteLine("Retrieving twin");
                var twinTask = Client.GetTwinAsync();
                twinTask.Wait();
                var twin = twinTask.Result;
                Console.WriteLine(JsonConvert.SerializeObject(twin.Properties));

                Console.WriteLine("Sending app start time as reported property");
                TwinCollection reportedProperties = new TwinCollection();
                reportedProperties["DateTimeLastAppLaunch"] = DateTime.Now;

                Client.UpdateReportedPropertiesAsync(reportedProperties);
            }
            catch (AggregateException ex)
            {
                Console.WriteLine("Error in sample: {0}", ex);
            }

            Console.WriteLine("Waiting for Events.  Press enter to exit...");
            Console.ReadLine();
            Client.CloseAsync().Wait();
        }

        private static async Task OnDesiredPropertyChanged(TwinCollection desiredProperties,
                                                           object userContext)
        {
            Console.WriteLine("desired property change:");
            Console.WriteLine(JsonConvert.SerializeObject(desiredProperties));
            Console.WriteLine("Sending current time as reported property");
            TwinCollection reportedProperties = new TwinCollection
                                                    {
                                                        ["DateTimeLastDesiredPropertyChangeReceived"] = DateTime.Now
                                                    };

            await Client.UpdateReportedPropertiesAsync(reportedProperties).ConfigureAwait(false);
        }
    }
}
1

1 Answers

1
votes

When you create a new module in Visual Studio Code, it generates a template module for you that will show you how it's done. I'll include the important bit below:

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.");

            // Register callback to be called when a message is received by the module
            await ioTHubModuleClient.SetInputMessageHandlerAsync("input1", PipeMessage, ioTHubModuleClient);
        }

The way this works is because the Azure IoT Edge runtime will create the module as a Docker container with the connection settings as environment variables. The module client uses those variables to connect to IoT Hub when you call

ModuleClient ioTHubModuleClient = await ModuleClient.CreateFromEnvironmentAsync(settings);

There is a good sample on this Microsoft tutorial that also covers listening for Twin updates.