# IoTHub Python SDK Migration Guide This guide details how to update existing code that uses an `azure-iot-device` V2 release to use a V3 release instead. While the APIs remain mostly the same, there are a few differences you may need to account for in your application, as we have removed some of the implicit behaviors present in V2 in order to provide a more reliable and consistent user experience. ## Connecting to IoTHub One of the primary changes in V3 is the removal of automatic connections when invoking other APIs on the `IoTHubDeviceClient` and `IoTHubModuleClient`. You must now make an explicit manual connection before sending or receiving any data. ### V2 ```python from azure.iot.device import IoTHubDeviceClient client = IoTHubDeviceClient.create_from_connection_string("") client.send_message("some message") ``` ### V3 ```python from azure.iot.device import IoTHubDeviceClient client = IoTHubDeviceClient.create_from_connection_string("") client.connect() client.send_message("some message") ``` Note that many people using V2 may already have been doing manual connects, as for some time, this has been our recommended practice. Note also that this change does *not* affect automatic reconnection attempts in the case of network failure. Once the manual connect has been successful, the client will (under default settings) still attempt to retain that connected state as it did in V2. ## Receiving data from IoTHub Similarly to the above, there is an additional explicit step you must now make when trying to receive data. In addition to setting your handler, you must explicitly start/stop receiving. Note also that the above step of manually connecting must also be done before starting to receive data. ### V2 ```python from azure.iot.device import IoTHubDeviceClient client = IoTHubDeviceClient.create_from_connection_string("") # define behavior for receiving a message def message_handler(message): print("the data in the message received was ") print(message.data) print("custom properties are") print(message.custom_properties) # set the message handler on the client client.on_message_received = message_handler ``` ### V3 ```python from azure.iot.device import IoTHubDeviceClient client = IoTHubDeviceClient.create_from_connection_string("") # define behavior for receiving a message def message_handler(message): print("the data in the message received was ") print(message.data) print("custom properties are") print(message.custom_properties) # set the message handler on the client client.on_message_received = message_handler # connect and start receiving messages client.connect() client.start_message_receive() ``` Note that this must be done not just for receiving messages, but receiving any data. Consult the chart below to see which APIs you will need for the type of data you are receiving. | Data Type | Handler name | Start Receive API | Stop Receive API | |---------------------------------|----------------------------------------------|--------------------------------------------------|-------------------------------------------------| | Messages | `.on_message_received` | `.start_message_receive()` | `.stop_message_receive()` | | Method Requests | `.on_method_request_received` | `.start_method_request_receive()` | `.stop_method_request_receive()` | | Twin Desired Properties Patches | `.on_twin_desired_properties_patch_received` | `.start_twin_desired_properties_patch_receive()` | `.stop_twin_desired_properties_patch_receive()` | Finally, it should be clarified that the following receive APIs that were deprecated in V2 have been fully removed in V3: * `.receive_message()` * `.receive_message_on_input()` * `.receive_method_request()` * `.receive_twin_desired_properties_patch()` All receives should now be done using the handlers in the table above. ## Modified Client Options - IoTHubDeviceClient/IoTHubModuleClient Some keyword arguments provided at client creation have changed or been removed | V2 | V3 | Explanation | |-----------------------------|-------------|----------------------------------------| | `auto_connect` | **REMOVED** | Initial manual connection now required | | `ensure_desired_properties` | **REMOVED** | No more implicit twin updates | ## Shutting down - IoTHubDeviceClient/IoTHubModuleClient While using the `.shutdown()` method when you are completely finished with an instance of the client has been a highly recommended practice for some time, some early versions of V2 did not require it. As of V3, in order to ensure a graceful exit, you must make an explicit shutdown. ### V2 ```python from azure.iot.device import IoTHubDeviceClient client = IoTHubDeviceClient.create_from_connection_string("") # ... # # ... ``` ### V3 ```python from azure.iot.device import IoTHubDeviceClient client = IoTHubDeviceClient.create_from_connection_string("") # ... # # ... client.shutdown() ``` ## Shutting down - ProvisioningDeviceClient As with the IoTHub clients mentioned above, the Provisioning clients now also require shutdown. This was implicit in V2, but now it must be explicit and manual to ensure graceful exit. ### V2 ```python from azure.iot.device import ProvisioningDeviceClient client = ProvisioningDeviceClient.create_from_symmetric_key( provisioning_host="", registration_id="", id_scope="", symmetric_key=", ) registration_result = client.register() # Shutdown is implicit upon successful registration ``` ### V3 ```python from azure.iot.device import ProvisioningDeviceClient client = ProvisioningDeviceClient.create_from_symmetric_key( provisioning_host="", registration_id="", id_scope="", symmetric_key=", ) registration_result = client.register() # Manual shutdown for graceful exit client.shutdown() ```