Get started with device management (Python)

Back-end apps can use Azure IoT Hub primitives, such as device twin and direct methods, to remotely start and monitor device management actions on devices. This tutorial shows you how a back-end app and a device app can work together to initiate and monitor a remote device reboot using IoT Hub.

Note

The features described in this article are only available in the standard tier of IoT hub. For more information about the basic and standard IoT Hub tiers, see How to choose the right IoT Hub tier.

Use a direct method to initiate device management actions (such as reboot, factory reset, and firmware update) from a back-end app in the cloud. The device is responsible for:

  • Handling the method request sent from IoT Hub.
  • Initiating the corresponding device-specific action on the device.
  • Providing status updates through reported properties to IoT Hub.

You can use a back-end app in the cloud to run device twin queries to report on the progress of your device management actions.

This tutorial shows you how to:

  • Use the Azure portal to create an IoT Hub and create a device identity in your IoT hub.
  • Create a simulated device app that contains a direct method that reboots that device. Direct methods are invoked from the cloud.
  • Create a Python console app that calls the reboot direct method in the simulated device app through your IoT hub.

At the end of this tutorial, you have two Python console apps:

dmpatterns_getstarted_device.py, which connects to your IoT hub with the device identity created earlier, receives a reboot direct method, simulates a physical reboot, and reports the time for the last reboot.

dmpatterns_getstarted_service.py, which calls a direct method in the simulated device app, displays the response, and displays the updated reported properties.

To complete this tutorial, you need the following:

Create an IoT hub

This section describes how to create an IoT hub using the Azure portal.

  1. Log in to the Azure portal.

  2. Choose +Create a resource, then choose Internet of Things.

  3. Click Iot Hub from the list on the right. You see the first screen for creating an IoT hub.

    Screenshot showing creating a hub in the Azure portal

    Fill in the fields.

    Subscription: Select the subscription to use for your IoT hub.

    Resource Group: You can create a new resource group or use an existing one. To create a new one, click Create new and fill in the name you want to use. To use an existing resource group, click Use existing and select the resource group from the dropdown list. For more information, see Use resource groups to manage your Azure resources.

    Region: This is the region in which you want your hub to be located. Select the location closest to you from the dropdown list.

    IoT Hub Name: Put in the name for your IoT Hub. This name must be globally unique. If the name you enter is available, a green check mark appears.

    Important

    The IoT hub will be publicly discoverable as a DNS endpoint, so make sure to avoid any sensitive information while naming it.

  4. Click Next: Size and scale to continue creating your IoT hub.

    Screenshot showing setting size and scale for a new IoT hub using the Azure portal

    On this screen, you can take the defaults and just click Review + create at the bottom.

    Pricing and scale tier: You can choose from several tiers depending on how many features you want and how many messages you send through your solution per day. The free tier is intended for testing and evaluation. It allows 500 devices to be connected to the IoT hub and up to 8,000 messages per day. Each Azure subscription can create one IoT Hub in the free tier.

    IoT Hub units: The number of messages allowed per unit per day depends on your hub's pricing tier. For example, if you want the IoT hub to support ingress of 700,000 messages, you choose two S1 tier units.

    For details about the other tier options, see Choosing the right IoT Hub tier.

    Advanced / Device-to-cloud partitions: This property relates the device-to-cloud messages to the number of simultaneous readers of the messages. Most IoT hubs only need four partitions.

  5. Click Review + create to review your choices. You see something similar to this screen.

    Screenshot reviewing information for creating the new IoT hub

  6. Click Create to create your new IoT hub. Creating the hub takes a few minutes.

Retrieve connection string for IoT hub

After your hub has been created, retrieve the connection string for the hub. This is used to connect devices and applications to your hub.

  1. Click on your hub to see the IoT Hub pane with Settings, and so on. Click Shared access policies.

  2. In Shared access policies, select the iothubowner policy.

  3. Under Shared access keys, copy the Connection string -- primary key to be used later.

    Show how to retrieve the connection string

    For more information, see Access control in the "IoT Hub developer guide."

Create a simulated device app

In this section, you will:

  • Create a Python console app that responds to a direct method called by the cloud
  • Simulate a device reboot
  • Use the reported properties to enable device twin queries to identify devices and when they last rebooted
  1. Using a text editor, create a dmpatterns_getstarted_device.py file.

  2. Add the following import statements at the start of the dmpatterns_getstarted_device.py file.

    import random
    import time, datetime
    import sys
    
    import iothub_client
    from iothub_client import IoTHubClient, IoTHubClientError, IoTHubTransportProvider, IoTHubClientResult, IoTHubError, DeviceMethodReturnValue
    
  3. Add variables including a CONNECTION_STRING variable and the client initialization. Replace the connection string with your device connection string.

    CONNECTION_STRING = "{deviceConnectionString}"
    PROTOCOL = IoTHubTransportProvider.MQTT
    
    CLIENT = IoTHubClient(CONNECTION_STRING, PROTOCOL)
    
    WAIT_COUNT = 5
    
    SEND_REPORTED_STATE_CONTEXT = 0
    METHOD_CONTEXT = 0
    
    SEND_REPORTED_STATE_CALLBACKS = 0
    METHOD_CALLBACKS = 0
    
  4. Add the following function callbacks to implement the direct method on the device.

    def send_reported_state_callback(status_code, user_context):
        global SEND_REPORTED_STATE_CALLBACKS
    
        print ( "Device twins updated." )
    
    def device_method_callback(method_name, payload, user_context):
        global METHOD_CALLBACKS
    
        if method_name == "rebootDevice":
            print ( "Rebooting device..." )
    
            time.sleep(20)
    
            print ( "Device rebooted." )
    
            current_time = str(datetime.datetime.now())
            reported_state = "{\"rebootTime\":\"" + current_time + "\"}"
            CLIENT.send_reported_state(reported_state, len(reported_state), send_reported_state_callback, SEND_REPORTED_STATE_CONTEXT)
    
            print ( "Updating device twins: rebootTime" )
    
        device_method_return_value = DeviceMethodReturnValue()
        device_method_return_value.response = "{ \"Response\": \"This is the response from the device\" }"
        device_method_return_value.status = 200
    
        return device_method_return_value
    
  5. Start the direct method listener and wait.

    def iothub_client_init():
        if CLIENT.protocol == IoTHubTransportProvider.MQTT or client.protocol == IoTHubTransportProvider.MQTT_WS:
            CLIENT.set_device_method_callback(device_method_callback, METHOD_CONTEXT)
    
    def iothub_client_sample_run():
        try:
            iothub_client_init()
    
            while True:
                print ( "IoTHubClient waiting for commands, press Ctrl-C to exit" )
    
                status_counter = 0
                while status_counter <= WAIT_COUNT:
                    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" )
    
    if __name__ == '__main__':
        print ( "Starting the IoT Hub Python sample..." )
        print ( "    Protocol %s" % PROTOCOL )
        print ( "    Connection string=%s" % CONNECTION_STRING )
    
        iothub_client_sample_run()
    
  6. Save and close the dmpatterns_getstarted_device.py file.

Note

To keep things simple, this tutorial does not implement any retry policy. In production code, you should implement retry policies (such as an exponential backoff), as suggested in the article, Transient Fault Handling.

Trigger a remote reboot on the device using a direct method

In this section, you create a Python console app that initiates a remote reboot on a device using a direct method. The app uses device twin queries to discover the last reboot time for that device.

  1. Using a text editor, create a dmpatterns_getstarted_service.py file.

  2. Add the following import statements at the start of the dmpatterns_getstarted_service.py file.

    import sys, time
    import iothub_service_client
    
    from iothub_service_client import IoTHubDeviceMethod, IoTHubError, IoTHubDeviceTwin
    
  3. Add the following variable declarations. Only replace placeholder values for IoTHubConnectionString and deviceId.

    CONNECTION_STRING = "{IoTHubConnectionString}"
    DEVICE_ID = "{deviceId}"
    
    METHOD_NAME = "rebootDevice"
    METHOD_PAYLOAD = "{\"method_number\":\"42\"}"
    TIMEOUT = 60
    WAIT_COUNT = 10
    
  4. Add the following function to invoke the device method to reboot the target device, then query for the device twins and get the last reboot time.

    def iothub_devicemethod_sample_run():
        try:
            iothub_twin_method = IoTHubDeviceTwin(CONNECTION_STRING)
            iothub_device_method = IoTHubDeviceMethod(CONNECTION_STRING)
    
            print ( "" )
            print ( "Invoking device to reboot..." )
    
            response = iothub_device_method.invoke(DEVICE_ID, METHOD_NAME, METHOD_PAYLOAD, TIMEOUT)
    
            print ( "" )
            print ( "Successfully invoked the device to reboot." )
    
            print ( "" )
            print ( response.payload )
    
            while True:
                print ( "" )
                print ( "IoTHubClient waiting for commands, press Ctrl-C to exit" )
    
                status_counter = 0
                while status_counter <= WAIT_COUNT:
                    twin_info = iothub_twin_method.get_twin(DEVICE_ID)
    
                    if twin_info.find("rebootTime") != -1:
                        print ( "Last reboot time: " + twin_info[twin_info.find("rebootTime")+11:twin_info.find("rebootTime")+37])
                    else:
                        print ("Waiting for device to report last reboot time...")
    
                    time.sleep(5)
                    status_counter += 1
    
        except IoTHubError as iothub_error:
            print ( "" )
            print ( "Unexpected error {0}".format(iothub_error) )
            return
        except KeyboardInterrupt:
            print ( "" )
            print ( "IoTHubDeviceMethod sample stopped" )
    
    if __name__ == '__main__':
        print ( "Starting the IoT Hub Service Client DeviceManagement Python sample..." )
        print ( "    Connection string = {0}".format(CONNECTION_STRING) )
        print ( "    Device ID         = {0}".format(DEVICE_ID) )
    
        iothub_devicemethod_sample_run()
    
  5. Save and close the dmpatterns_getstarted_service.py file.

Run the apps

You are now ready to run the apps.

  1. At the command prompt, run the following command to begin listening for the reboot direct method.

    python dmpatterns_getstarted_device.py
    
  2. At another command prompt, run the following command to trigger the remote reboot and query for the device twin to find the last reboot time.

    python dmpatterns_getstarted_service.py
    
  3. You see the device response to the direct method in the console.

Customize and extend the device management actions

Your IoT solutions can expand the defined set of device management patterns or enable custom patterns by using the device twin and cloud-to-device method primitives. Other examples of device management actions include factory reset, firmware update, software update, power management, network and connectivity management, and data encryption.

Device maintenance windows

Typically, you configure devices to perform actions at a time that minimizes interruptions and downtime. Device maintenance windows are a commonly used pattern to define the time when a device should update its configuration. Your back-end solutions can use the desired properties of the device twin to define and activate a policy on your device that enables a maintenance window. When a device receives the maintenance window policy, it can use the reported property of the device twin to report the status of the policy. The back-end app can then use device twin queries to attest to compliance of devices and each policy.

Next steps

In this tutorial, you used a direct method to trigger a remote reboot on a device. You used the reported properties to report the last reboot time from the device, and queried the device twin to discover the last reboot time of the device from the cloud.

To continue getting started with IoT Hub and device management patterns such as remote over the air firmware update, see:

Tutorial: How to do a firmware update

To learn how to extend your IoT solution and schedule method calls on multiple devices, see the Schedule and broadcast jobs tutorial.

To continue getting started with IoT Hub, see Getting started with IoT Edge.