Search code examples
pythonazure-iot-edge

Azure edge modules cannot receive direct method requests


I have created a very small edge module which sends telemetry to an IoT Hub and which receives direct messages. When I start my IoT Edge script with

IoTHubModuleClient.create_from_connection_string(connection_string)

locally everything is fine. It can send telemetry and receive direct method requests.

When I deploy my script as an edge module in a container it also sends telemetry, but however it cannot receive any direct method requests:

IoTHubModuleClient.create_from_edge_environment()

My stripped code would look like this:

import time
import os
import sys
import asyncio
import threading
from azure.iot.device.aio import IoTHubModuleClient
from azure.iot.device import MethodResponse

async def main():

    try:
        if not sys.version >= "3.5.3":
            raise Exception( "The sample requires python 3.5.3+. Current version of Python: %s" % sys.version )
        print ( "IoT Hub Client for Python" )

        # For production
        module_client = IoTHubModuleClient.create_from_edge_environment()

        # For tests
        #connection_string = "Here was my connection string :)"
        #module_client = IoTHubModuleClient.create_from_connection_string(connection_string)
        
        async def direct_method_received(method_request):

            try:
                await module_client.send_message("Received Method Request: " + str(method_request.name))                
                print("Received direct message: {} {}\n".format(str(method_request.name), str(method_request.payload)))
       
                method_response = MethodResponse.create_from_method_request(method_request, 200, None)
                await module_client.send_method_response(method_response)
                
            except Exception as e:            
                method_response = MethodResponse.create_from_method_request(method_request, 400, payload=logging)
                await module_client.send_method_response(method_response)


        module_client.on_method_request_received = direct_method_received
        
        await module_client.connect()
        await module_client.send_message("Receive Module is running.")

        while True:
            try:
                await asyncio.sleep(10)
            except Exception as e:
                print("Error: {}".format(str(e)))

    except Exception as e:
        print("Unexpected error %s \n" % e)
        raise
    finally:        
        await module_client.shutdown()   

if __name__ == "__main__":
    asyncio.run(main())

The iotedge service says that my module is working fine. Also as I said, it sends telemetry which I can receive in the IoT hub. The direct method request is sent with the portal, directly in the edge module controls:

enter image description here

The error is

enter image description here

That confuses me because it is working when I directly connect to my device without edge runtime.

Here it is said that you need some specific network configuration, but I don't know how to do it and also I don't know if that is the problem in my case.

iot edge direct method handler in python


Solution

  • finally I could get the sample running :-) Could you check if you reference azure-iot-device~=2.5.1 in you requirements.txt?

    From https://github.com/Azure/azure-iot-sdk-python/releases I see that v2.3.0 fixed this:

    • Added handlers for receive method request
      • Deprecated receive method request API

    René