Help understanding IoTHubDeviceClient in distributed modules

Occasional Contributor



I have a hard time wrapping my head around how to work with custom developed modules and connection strings. To make things easy, I've taken one of the Python scripts from the SDK examples on GitHub (the one that sends simulated temperature and humidity values).


The example mentioned uses IoTHubDeviceClient.create_from_connection_string(CONNECTION_STRING) and the send_message(message) to deliver it's values. This works fine and the data keeps coming in. However when I build a module from this and don't want to include a static connection string I can't seem to understand how this is done. Surely there's a corresponding way to get this dynamically populated or handled by the edge device. I just can't find any info on it.


My guess is that you are suppose to use IoTHubModuleClient.create_from_edge_environment() instead and use that but I can't seem to get that to work. Any input to what achieves this? The aim is to be able to push the same module to multiple edge devices connected to different IoT Hubs and to do this I don't want to include a connection string.

8 Replies

@petersaverman the modules in IoT Edge do not need to authenticate with IoT Hub directly and you shouldn't use a device connection string nor the IoT HubDeviceClient  client in a module. As you have seen you need to use the IoTHubModule client.

The IoTEdge runtime is the one that will have to authenticate using the IoT Edge Device credentials created when provisioning in your IoT Hub(s). BTW I recommend using the Device Provisioning Service rather than connection strings when going to production. See some doc about this here.

Once your IoT Edge devices connect and authenticate to the IoT Hub they were configured for, you can deploy the same module to multiple IoT Edge devices through IoT Hub using the Azure Portal, the Azure CLI or your own code using the IoT Hub APIs.

Let me know if that puts you on the right track




Thanks for responding and excuse my late reply. I've actually set up provisioning of my devices and that works fine. I did find a discussion regarding the IoTHubModuleClient not receiving a connection as well as not throwing an error under certain circumstances which I sadly can't remember now but this was my issue as well.

I'm trying to find out just how to use the IoTHubModuleClient to send a message to the Hub right now. Is that where the output comes in (via send_message_to_output) or do I still use the 

or should I still use the send_message method?

Hi @petersaverman 

The modules communication is enabled by the Edge Hub module which is part of the IoT Edge runtime. The idea is that  you configure routes between modules and up to the IoT Hub service at the IoT Edge runtime level and then in your module you can send messages to the output of the module defined in the routing configuration. You can learn more about the IoT Edge runtime concepts in this article and more on the routing setup in this one.

If you want to send messages to IoT Hub directly from a module then you need to setup a route that takes all outputs from the module and sends to "upstream".

For sending all messages from a specific module to IoT Hub, you would setup the route like this:


"$edgeHub": {
    "properties.desired": {
        "routes": {
            "route1": "FROM /messages/modules/<moduleId>/* INTO $upstream"



@OlivierBloch That is a totally different approach. From most example code there is embeded connection string which made me think that the modules sent the data themselves. Thanks for clarifying! Still, I tried another example from the documentation and this still doesn't give me any messages when monitoring the endpoints. I'm starting to suspect that something else might be wrong. Is there a good approach to know where the fault is? Logs don't give anything away either. I expected the example above to "just work".

To clarify: the only output given from above mentioned example is:

IoT Hub Client for Python
The sample is now waiting for messages.
Press Q to quit
Press Q to quit
Press Q to quit
Press Q to quit
... and so on

Nothing is triggered. Am I supposed to do something to trigger this?


The example I referenced does the following: It deploys 2 modules on your IoT Edge device, the first one is the SimulatedTempModule, which is a standard temp sensor data simulator that generates random temp values, and the second is your custom module that listens to the SimulatedTempModule module and checks for a temperature threshold (configured using the module Twin). When the threshold is passed, the custom module will create and send an alert message out. The routes should be configured to sen all telemetry outputs from the temp sensor simulator to the custom module and to send all messages from your custom module (alerts for temperature above the threshold) to IoT Hub.

If things are not working as expected, then you can troubleshoot using recommended tools and techniques from this article:

I recommend you start by checking your modules are all running, then looking at the output of the temp sensor simulator. If all is ok there, look at  your custom module to see if it sends an alert on its output when temp goes above configured threshold. And if everything is ok there then you can use the IoT Explorer tool to monitor what's arriving in your IoT Hub.

@OlivierBloch That was a really hard thing for me to wrap my head around but I've finally managed to get it working. A million thanks!


I still have a question though. When I monitor the endpoint in Visual Studio Code or the terminal, I get no event data displayed. But still, messages are being sent, because I see it coming in and getting stored in my data lake. Any idea what's up with that?

Hi @petersaverman 

I am glad you are making progress.

When you say you monitor events in VS Code or the terminal, can you describe what you are doing?

If data shows up in your storage, then you should definitively see it when monitoring IoT Hub's endpoint. Now if you have setup routing on your IoT Hub to send all telemetry to a specific endpoint different than the default endpoint, than you'd need to monitor that other endpoint or ensure your route sends the messages to both your custom endpoint and the default one.