Python Azure IoT SDK: How to send and receive C2D messages

Introduction

Recently, Microsoft has released the new version of Python Azure IoT SDK (V2.0) (refer to this page on IoT blog: New version of the Python SDK released).  According to the release announcement, we should upgrade SDK from V1 to V2 since the v2 SDK aims to provide a simplified, more natural experience for developers. It’s designed in native Python.

In the previous tutorials, we have installed the new Python Azure IoT SDK on Windows 10 and made a demo Python project with Visual Studio to send simulation date to the Azure IoTHub. Then we showed how to invoke Direct Methods from Backend App. Also, device twins including reported properties and desired properties were demonstrated. Furthermore, device provision service with symmetric keys was presented. For more details, please refer to the following pervious tutorials:

  1. How to use Python Azure IoT SDK with Visual Studio
  2. Python Azure IoT SDK: How to receive direct methods from IoT Hub
  3. Python Azure IoT SDK: How to use device twins in IoT Hub
  4. Python Azure IoT SDK: How to use device provision service with symmetric keys

In this article, we will walk you through the steps required to send and receive cloud-to-device message with Python Azure IoT SDK.

Cloud-to-device messages

In the previous tutorial, we send device-to-cloud messages to achieve telemetry reporting. Sometimes, we also need cloud-to-device messages to achieve remote control and configuration. To guarantee at-least-once message delivery, the IoT hub persists cloud-to-device messages in per-device queues. For the IoT hub to remove the messages from the queue, the devices must explicitly acknowledge completion. This approach guarantees resiliency against connectivity and device failures. The life-cycle state graph is displayed in Fig. 1.

Fig. 1 The life-cycle state of cloud-to-device messages

For more information about cloud-to-device messages, please refer to this page “Understanding cloud-to-device messages”. In this tutorial, we will use Azure IoThub Service to send cloud-to-device messages from backend app and receive the messages from simulated devices.

Prerequisites

  1. Windows 10 with Visual Studio 2019 Community (“Python development” workload required)
  2. Python Azure IoT Device SDK: https://github.com/Azure/azure-iot-sdk-python/tree/master/azure-iot-device/samples
  3. Python Azure IoT Hub Service SDK: https://github.com/Azure/azure-iot-sdk-python/tree/master/azure-iot-hub

Install Azure IoTHub Service SDK for Python

The Azure IoTHub Service SDK for Python provides functionality for communicating with the Azure IoT Hub. We can use pip to install this SDK.

pip install azure-iot-hub --user

The installation will be finished automatically. The output is shown in Fig. 2.


Fig. 2 Install Azure IoTHub Service SDK for Python

Send cloud-to-device messages from backend app

This Python application will send cloud-to-device messages. First, we need the IoTHub connection string and device ID, which can be find in Azure Portal. Navigate to the Shared access policies of your Azure IoTHub and you will find connection string as shown in Fig. 3.

Fig.3 Connection string for Azure IoTHub

Then, you will need the device ID that you want to communicate with Azure IoTHub. You can find all the devices registered in your IoTHub on “IoT Devices” tab, which is shown in Fig. 4.


Fig. 4 Choose one IoT device in your Azure IoTHub

 Create a Python project with “Python Application” project temple, give a name such as “PythonIoTC2DDemo”. Copy and paste the following code to “PythonIoTC2DDemo.py”. Make sure that you substitute with your own connection string and device name in the code.

# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
 
import sys
import os
from azure.iot.hub import IoTHubRegistryManager
 
connection_str =  "HostName=***.azure-devices.net;SharedAccessKeyName=iothubowner;SharedAccessKey=***"
device_id =  "MyRPi"
send_message =  "Cloud to device message to be send to device"
 
try:
    # Create IoTHubRegistryManager
    registry_manager =  IoTHubRegistryManager(connection_str)
    print("Conn String: {0}".format(connection_str))
 
    # Send Message To Device
    registry_manager.send_c2d_message(device_id, send_message)
 
except Exception as ex:
    print("Unexpected error {0}".format(ex))
except KeyboardInterrupt:
    print("iothub_statistics stopped")

In this application, we will send “Cloud to device message to be send to device” to the device “MyRPi”. Once the messages are sent, we will see the output information as shown in Fig. 5.


Fig. 5 Debug output in Visual Studio

Receive cloud-to-device messages in local app

Create a Python project with “Python Application” project temple, give a name such as “PythonIoTDeviceDemo”. Copy and paste the following code to “PythonIoTDeviceDemo.py”. Make sure that you substitute with your own connection string for your device in the code.

# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
 
import os
import asyncio
from six.moves import input
import threading
from azure.iot.device.aio import IoTHubDeviceClient
 
 
async def  main():
    # The connection string for a device should never be stored in code. For the sake of simplicity we're using an environment variable here.
    conn_str =  "HostName=***.azure-devices.net;DeviceId=MyRPi;SharedAccessKey=***"
    # The client object is used to interact with your Azure IoT hub.
    device_client =  IoTHubDeviceClient.create_from_connection_string(conn_str)
 
    # connect the client.
    await device_client.connect()
 
    # define behavior for receiving a message
    async def  message_listener(device_client):
        while True:
            message =  await device_client.receive_message()  # blocking call
            print("the data in the message received was ")
            print(message.data)
            print("custom properties are")
            print(message.custom_properties)
 
    # define behavior for halting the application
    def stdin_listener():
        while True:
            selection =  input("Press Q to quit\n")
            if selection == "Q"  or selection == "q":
                print("Quitting...")
                break
 
    # Schedule task for message listener
    asyncio.create_task(message_listener(device_client))
 
    # Run the stdin listener in the event loop
    loop =  asyncio.get_running_loop()
    user_finished =  loop.run_in_executor(None, stdin_listener)
 
    # Wait for user to indicate they are done listening for messages
    await user_finished
 
    # Finally, disconnect
    await device_client.disconnect()
 
 
if __name__ == "__main__":
    asyncio.run(main())
 
    # If using Python 3.6 or below, use the following code instead of asyncio.run(main()):
    # loop = asyncio.get_event_loop()
    # loop.run_until_complete(main())
    # loop.close()

Once the Cloud-to-device messages are received, the string will be presented in the output windows, which is shown in Fig. 6.


Fig. 6 Messages received in device app

 

Summary

In this tutorial, we have presented how to send and receive cloud-to-device messages with Azure IoT Python SDK, including “Send cloud-to-device messages from backend app” and “Receive cloud-to-device messages in local app”.

 

Resources

  1. Microsoft Docs: Understanding cloud-to-device messages
  2. IoT Blog: New version of the Python SDK released
  3. Python Azure IoT Device SDK: https://github.com/Azure/azure-iot-sdk-python/tree/master/azure-iot-device/samples
  4. Python Azure IoT Hub Service SDK: https://github.com/Azure/azure-iot-sdk-python/tree/master/azure-iot-hub
  5. My Projects on Hackster: Jiong Shi
  6. Azure IoT Docs: Azure IoTHub

 

See Also

  1. How to use Python Azure IoT SDK with Visual Studio
  2. Python Azure IoT SDK: How to receive direct methods from IoT Hub
  3. Python Azure IoT SDK: How to use device twins in IoT Hub
  4. Python Azure IoT SDK: How to use device provision service with symmetric keys
  5. Build a Azure Sphere IoT Car with Remote Control