How to implement realtime Communication between Device and Azure Function over IoT Hub

Patrick Schneider 86 Reputation points
2021-04-21T09:57:08.5+00:00

Hello,

i would like to implement a low-delay (near-realtime) control loop over Azure IoT Hub.
(I am aware of the problems and challenges of the time relevant control via the cloud)

Control Loop:
The microcontroller sends the current position of an actuator to the IoT Hub.

Input:
{"deviceId":"MyDevice","position_x":14.00,"position_y":24.00,"position_z":75.00}

The cloud service automatically execute a short calculation and send a response to the microcontroller with the new velocity.

Return:
{"deviceId":"MyDevice","velocity":3.00}

The service should run through this loop with a minimum of delay.

Current status:

As a first Step i created an IoT Hub and ran the given Quickstart-Examples (in python).
(https://learn.microsoft.com/en-us/azure/iot-hub/quickstart-send-telemetry-python)

In the next stage I used the MSP432E401Y Microcontroller from Texas Instruments instead of the SimulatedDevice.py.

After that I added Eventgrid + Azure Function.

Overview:
89917-image.png

The Azure Function is in python and looks like:

function.json:

{  
    "scriptFile": "init.py",  
    "bindings": [  
    {  
         "type": "eventGridTrigger",  
         "name": "eventGridEvent",  
         "direction": "in"  
    }  
    ]  
}  

init.py:

 import json  
 import logging  
 import azure.functions as func  
 import datetime  
  
 import random  
 import sys  
 from azure.iot.hub import IoTHubRegistryManager  
      
 MESSAGE_COUNT = 1  
 AVG_WIND_SPEED = 10.0  
 MSG_TXT = "{\"service client sent a message\": %.2f}"  
      
 CONNECTION_STRING = "HostName=XXXX.azure-devices.net;SharedAccessKeyName=service;SharedAccessKey=XXXXX"  
 DEVICE_ID = "XXXX"  
      
 def iothub_messaging_sample_run():  
     try:  
         # Create IoTHubRegistryManager  
         registry_manager = IoTHubRegistryManager(CONNECTION_STRING)  
      
         for i in range(0, MESSAGE_COUNT):  
             print ( 'Sending message: {0}'.format(i) )  
             data = MSG_TXT % (AVG_WIND_SPEED + (random.random() * 4 + 2))  
      
             props={}  
             # optional: assign system properties  
             props.update(messageId = "Return_message_%d" % i)  
             props.update(correlationId = "correlation_%d" % i)  
             props.update(contentType = "application/json")  
      
             # optional: assign application properties  
             prop_text = "PropMsg_%d" % i  
             props.update(testProperty = prop_text)  
      
             registry_manager.send_c2d_message(DEVICE_ID, data, properties=props)  
      
     except Exception as ex:  
         print ( "Unexpected error {0}" % ex )  
         return  
     except KeyboardInterrupt:  
         print ( "IoT Hub C2D Messaging service sample stopped" )  
      
 def main(eventGridEvent: func.EventGridEvent) -> None:  
      
     result = json.dumps({  
         'id': eventGridEvent.id,  
         'data': eventGridEvent.get_json(),  
         'topic': eventGridEvent.topic,  
         'subject': eventGridEvent.subject,  
         'event_type': eventGridEvent.event_type,  
     })  
      
     logging.info('Python EventGrid trigger processed an event: %s', result)  
      
     iothub_messaging_sample_run()  
      
     msg_data = eventGridEvent.get_json()  
     logging.info(msg_data)  
          
     if 'properties' in msg_data and 'position' in msg_data['properties']:  
         logging.info(msg_data['properties']['position'])  

It works! But i am sure there is an easier or more efficient way to go (like Input + Output Binding in EventGrid). I tried it but didn't get it to work.

Question:
After I used the Provision Service to connect the device to cloud and used the authentication type "X.509 CA Signed" a "Connection String" isn't longer available.

Therefore my workaround over the connection string no longer work.

Could somebody explain me, how to fix it.

With best regards
Patrick

Azure Functions
Azure Functions
An Azure service that provides an event-driven serverless compute platform.
4,248 questions
Azure IoT Hub
Azure IoT Hub
An Azure service that enables bidirectional communication between internet of things (IoT) devices and applications.
1,115 questions
Azure Event Grid
Azure Event Grid
An Azure event routing service designed for high availability, consistent performance, and dynamic scale.
313 questions
0 comments No comments
{count} votes

Accepted answer
  1. Sander van de Velde 28,311 Reputation points MVP
    2021-05-04T11:53:13.523+00:00

    Hi @Patrick Schneider ,

    I have limited experience with Python too.

    I was able to get a Python Azure Function triggered:

    93593-image.png

    the function.json looks like this:

    {  
     "scriptFile": "__init__.py",  
     "bindings": [  
       {  
       "type": "eventHubTrigger",  
       "name": "events",  
       "direction": "in",  
       "eventHubName": "samples-workitems",  
       "connection": "mybeerliftconnection",  
       "consumerGroup": "pfa"  
       }  
     ]  
    }  
    

    in the portal:

    93537-image.png

    The mybeerliftconnection references the public eventhub-compatible endpoint of the IoT hub:

    Endpoint=sb://iothub-ns-[hidden].servicebus.windows.net/;SharedAccessKeyName=iothubowner;SharedAccessKey=[secret]=;EntityPath=beerlift-weu-ih  
    

    It is stored in the application settings of the Azure Function App:

    93549-image.png

    1 person found this answer helpful.
    0 comments No comments

5 additional answers

Sort by: Most helpful
  1. Patrick Schneider 86 Reputation points
    2021-05-04T05:54:49.917+00:00

    Hello @Sander van de Velde ,

    I went through and understood the tutorials you linked. But things that should work according to the instructions still do not work.

    Example:
    https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-event-iot-trigger?tabs=python

    The C# Script works fine, but when I do the same with the python example it doesn't work:
    When I send data from a simulated device (10 Messages) in the C#-Function-App the Messages enter but in the python-Function-App no messages are arriving.

    I am sure this should work:

    JSON:
    {
    "scriptFile": "init.py",
    "bindings": [
    {
    "type": "eventHubTrigger",
    "name": "event",
    "direction": "in",
    "eventHubName": "samples-workitems",
    "connection": "iot-XXXX-XXXX-001_events_IOTHUB",
    "consumerGroup": "consumergroup-001"
    }
    ]
    }

    Do you have any idea what the reason for this is?

    Hope you could help me.

    With best regards
    Patrick

    0 comments No comments