Send cloud-to-device messages (C2D) with IoT Hub (Python)

With Azure IoT It is possible to fully secure and secure bi-directional communications between millions of devices and a solution back end.

Microsoft is offering an example to test the cloud to device messaging. If you need to have this example you need to have python 2.x or 3.x installed on the Raspberry Pi. So you need the Visual C ++ redistribution package:

https://www.microsoft.com/en-us/download/confirmation.aspx?id=48145

and have to install the Azure IoT Hub Device SDK for Python and the Azure IoT Hub Service SDK for Python:

Now you can create a Python console app to receive and receive cloud-to-device messages from the IoT hub.

  • Using a text editor, create a SimulatedDevice.py  file.
  • Add the following import statements and variables at the start of the
  • SimulatedDevice. py  file:
import time 
import sys 
import iothub_client 
from iothub_client import IoTHubClient, IoTHubClientError, IoTHubTransportProvider, IoTHubClientResult 
from iothub_client import IoTHubMessage, IoTHubMessageDispositionResult, IoTHubError 

RECEIVE_CONTEXT = 0 
WAIT_COUNT = 10 
RECEIVED_COUNT = 0 
RECEIVE_CALLBACKS = 0
  • Add the following code to SimulatedDevice . py file. Replace the „{deviceConnectionString}“ placeholder value with the device connection
# choose AMQP or AMQP_WS as the transport protocol 
PROTOCOL = IoTHubTransportProvider.AMQP 
CONNECTION_STRING = "{deviceConnectionString}"
  • Add the following function to print received messages to the console:
def receive_message_callback(message, counter):
    global RECEIVE_CALLBACKS
    message_buffer = message.get_bytearray()
    size = len(message_buffer)
    print ( "Received Message [%d]:" % counter )
    print ( "    Data: <<<%s>>> & Size=%d" % (message_buffer[:size].decode('utf-8'), size) )
    map_properties = message.properties()
    key_value_pair = map_properties.get_internals()
    print ( "    Properties: %s" % key_value_pair )
    counter += 1
    RECEIVE_CALLBACKS += 1
    print ( "    Total calls received: %d" % RECEIVE_CALLBACKS )
    return IoTHubMessageDispositionResult.ACCEPTED

def iothub_client_init():
    client = IoTHubClient(CONNECTION_STRING, PROTOCOL)
    client.set_message_callback(receive_message_callback, RECEIVE_CONTEXT)
    return client


def print_last_message_time(client):
    try:
        last_message = client.get_last_message_receive_time()
        print ( "Last Message: %s" % time.asctime(time.localtime(last_message)) )
        print ( "Actual time : %s" % time.asctime() )
    except IoTHubClientError as iothub_client_error:
        if iothub_client_error.args[0].result == IoTHubClientResult.INDEFINITE_TIME:
            print ( "No message received" )
        else:
            print ( iothub_client_error )
  • Add the following code to initialize the client and wait to recieve the cloud-to-device message:
def iothub_client_init():
    client = IoTHubClient(CONNECTION_STRING, PROTOCOL)
    client.set_message_callback(receive_message_callback, RECEIVE_CONTEXT)
    return client

def iothub_client_sample_run():
    try:
        client = iothub_client_init()
        while True:
            print ( "IoTHubClient waiting for commands, press Ctrl-C to exit" )
            status_counter = 0
            while status_counter <= WAIT_COUNT:
                status = client.get_send_status()
                print ( "Send status: %s" % status )
                time.sleep(10)
                status_counter += 1

    except IoTHubError as iothub_error:
        print ( "Unexpected error %s from IoTHub" % iothub_error )
        return

    except KeyboardInterrupt:
        print ( "IoTHubClient sample stopped" )

    print_last_message_time(client)
  • Add the following main function:
if __name__ == '__main__':
    print ( "Starting the IoT Hub Python sample..." )
    print ( "    Protocol %s" % PROTOCOL )
    print ( "    Connection string=%s" % CONNECTION_STRING )

    iothub_client_sample_run()
  • Save and close SimulatedDevice.pyfile.

This SimulatedDevice.py file connects to your IoT hub and receives cloud-to-device messages. This means if you run this file on your Raspberry Pi it will detect when a message is send from the IoT Hub to your Raspberry Pi.

Now you create a Python console app that sends cloud-to-device messages to the simulated device app.  Microsoft also has an example for this case:

  • Using a text editor, create a SendCloudToDeviceMessage.pyfile.
  • Add the following importstatements and variables at the start of the SendCloudToDeviceMessage.py file:
import random
import sys
import iothub_service_client
from iothub_service_client import IoTHubMessaging, IoTHubMessage, IoTHubError


OPEN_CONTEXT = 0
FEEDBACK_CONTEXT = 1
MESSAGE_COUNT = 1
AVG_WIND_SPEED = 10.0
MSG_TXT = "{\"service client sent a message\": %.2f}"
  • Add the following code to pyfile. Replace the „{IoTHubConnectionString}“ placeholder value with the IoT Hub connection string for the hub you created and replace the „{deviceId}“ placeholder with the device ID of the device you added in the previous steps.
CONNECTION_STRING = "{IoTHubConnectionString}"
DEVICE_ID = "{deviceId}"
  • Add the following function to print feedback messages to the console:
def open_complete_callback(context):
    print ( 'open_complete_callback called with context: {0}'.format(context) )

def send_complete_callback(context, messaging_result):
    context = 0
    print ( 'send_complete_callback called with context : {0}'.format(context) )
    print ( 'messagingResult : {0}'.format(messaging_result) )
  • Add the following code to send a message to your device and handle the feedback message when the device acknowledges the cloud-to-device message:
def iothub_messaging_sample_run():
    try:

        iothub_messaging = IoTHubMessaging(CONNECTION_STRING)
        iothub_messaging.open(open_complete_callback, OPEN_CONTEXT)

        for i in range(0, MESSAGE_COUNT):
            print ( 'Sending message: {0}'.format(i) )
            msg_txt_formatted = MSG_TXT % (AVG_WIND_SPEED + (random.random() * 4 + 2))
            message = IoTHubMessage(bytearray(msg_txt_formatted, 'utf8'))

            # optional: assign ids
            message.message_id = "message_%d" % i
            message.correlation_id = "correlation_%d" % i
            # optional: assign properties
            prop_map = message.properties()
            prop_text = "PropMsg_%d" % i
            prop_map.add("Property", prop_text)
            iothub_messaging.send_async(DEVICE_ID, message, send_complete_callback, i)

        try:
            # Try Python 2.xx first
            raw_input("Press Enter to continue...\n")

        except:
            pass
            # Use Python 3.xx in the case of exception
            input("Press Enter to continue...\n")

        iothub_messaging.close()

    except IoTHubError as iothub_error:
        print ( "Unexpected error {0}" % iothub_error )
        return
    except KeyboardInterrupt:
        print ( "IoTHubMessaging sample stopped" )

  • Add the following main function:
if __name__ == '__main__':
    print ( "Starting the IoT Hub Service Client Messaging Python sample..." )
    print ( "    Connection string = {0}".format(CONNECTION_STRING) )
    print ( "    Device ID         = {0}".format(DEVICE_ID) )
    iothub_messaging_sample_run()
  • Now you have to run the applications on your Raspberry Pi. To do this you have to open a new command prompt/terminal and run the following command to listen for cloud-to-device messages:
python SimulatedDevice.py
  • After that open a new command prompt and run the following command to send a cloud-to-device message and wait for the message feedback:
python SendCloudToDeviceMessage.py
  • But the moment you start the SendCloudToDeviceMessage.py app you can see a change in the prompt command promptly where you started the SimulatedDevice.py app.

The command prompt could look like this:

Schreibe einen Kommentar