This article assumes a basic understanding of the functionality of Azure IoT Edge. If you don’t have this, start with the official documentation: https://azure.microsoft.com/en-us/campaigns/iot-edge/.
The current Azure IoT Edge samples for .Net are great, but they do not (as of the time of this writing) demonstrate how to hook up and send data to IoTHub. Here we will set out step-by-step instructions for doing this using the existing samples as a starting point. The instructions below show how to send messages to IoTHub using Azure IoT Edge with custom .Net modules. They also show how you can receive cloud to device messages from IoT Hub in your .Net module, so you can implement commands or management operations for your device.
You can find good information about the architecture of Azure IoT Edge here. For our purposes, keep in mind that the Message broker provides interfaces for any module to plug in using common message format and defined callbacks. In the case of .Net, your class inherits from IGatewayModule and IGatewayModuleStart.
The JSON config file provides the glue to tell the system what the pipeline should look like. It defines what modules are in the pipeline, and how messages get passed between modules. You can mix native and .Net modules in the same pipeline. All of the IoT Hub connectivity and functionality is implemented in a native C module called the IoT Hub module. As we will see, the Edge architecture allows you to plug the IoTHub module into the pipeline along with your .Net module. It will take care of setting up protocols and transferring data to IoTHub including tracking multiple devices. It will also deal with command and control messages which it sends into the message broker. These are then picked up by the "Receive" callback function of modules in the pipeline.
The following instructions will setup a no frills IoT Edge implementation that demonstrates how to send and receive data from IoT Hub. When you are finished you will have a bare bones demonstration of the basic technology to build from. If you run into any issues or problems, take a look at the troubleshooting section below.
To send messages to IoT Hub…
Step 1: Follow the instructions here to run a simple project using the C# Nuget packages.
Step 2: Create an IoT Hub and add a sample device. Instructions for creating a hub can be found here. Note that the simplest configuration will do for our purposes. The easiest way to add a device, is to click the “Device Explorer” link in the Azure Portal, and then click the Add button. Copy the resulting device ID and Key away to use later, or you can just retrieve them from the portal when the time comes.
Step 3: From within the DotnetModuleSample solution setup in step 1, open the module_dev_sample.json and add a definition to include the IoTHub module in the pipeline (example below):
Step 4: Add a data source and sink to the JSON file as well
Step 5: In DotNetSensorModule.cs, change the message properties so that “source” is set to “mapping” (required by the IoTHub module) and “DeviceName” and “DeviceKey” are added…
Dictionary<string, string> messageProperties = new Dictionary<string, string>();
messageProperties.Add("deviceName", <Your Device Name);
messageProperties.Add("deviceKey", <Your Device Key>);
Step 6: If you want to continue to see messages output to the command window, change the DotNetPrinterModule.cs to look for messages from the mapping source:
received_message.Properties["source"] == "mapping"
You should now be able to run the solution and see messages coming into IoTHub using Device Explorer or a similar utility.
Receiving messages from IoTHub is also simple…
Step 1: In the JSON configuration file “links” section, add a path from the IoTHub module back to your custom module. For example…
Your Receive() method will already be implemented in the sample within DotNetSensorModule.cs. It is the callback implemented as part of IGatewayModule. Place a breakpoint on the receive function.
Step 2: The messages you receive will have properties and content. The message content is typed as a byte array. If you want to view it as a string you will need to convert it…
str = System.Text.Encoding.Default.GetString(received_message.Content)
Step 3: You can process messages using the DeviceID property to route to the correct device. If you have a module which receives both incoming and outgoing messages, such as the mapper module which maps device MAC addresses to Device IDs, you will need to differentiate between cloud to device and device to cloud messages in your Receive() function. You can look at the identiy_map module in the Azure_IoT_Gateway_SDK as an example.
Getting "dll is null" errors, or error 127 from debug session
- There is most likely a dependency missing – double check the path to the dll in the JSON file
- If all looks good, run in conjunction with the sysinternals utility Process Monitor
- Look in the ProcMon output (filter on the gateway process gw.exe) for NOT FOUND conditions for a dll. If found, this will identify the missing dependency.
Not seeing data coming into IoT Hub
- This could be a variety of reasons, but the most common is an error in DeviceID or Device Key values used.
- This could also be due to a failure to include messageProperties.Add("source", "mapping) in message properties. The IoT Hub requires that the source property be set to “mapping”.
Not receiving messages from IoT Hub
- Be patient, it can take minutes between when you send the message from Device Explorer, and when it hits the receive function of the device.
- You can set the protocol you are using to communicate with IoTHub through the JSON file in the IoTHub settings. Try using AMQP instead of HTTP to see if it may be a protocol configuration issue.
- Check that the necessary ports for the Protocol you are using are open for receive. It may work to make an exception for the app in your firewall using the firewall management utility.