Exception while Registering a device using DPS in python

Parth Shah 0 Reputation points
2023-06-08T09:56:57.1833333+00:00

Code Aim:- When "create device" is received on the device twin of the device it creates the device using DPS with the name received in the field "device-name" on the device twin.

Provided code below is giving me this exception when "createDPSDevice" function is called.

Exception is:

Task exception was never retrieved
future: <Task finished name='Task-7' coro=<main.<locals>.twin_patch_listener() done, defined at C:\Users\parth\Desktop\Evaluation_Submission_Parth_Shah\Azure_Practical\Azure_DPS_Create.py:68> exception=ClientError('Unexpected failure')>
Traceback (most recent call last):
  File "C:\Users\parth\AppData\Local\Programs\Python\Python311\Lib\site-packages\azure\iot\device\provisioning\aio\async_provisioning_device_client.py", line 29, in handle_result
    return await callback.completion()
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\parth\AppData\Local\Programs\Python\Python311\Lib\site-packages\azure\iot\device\common\async_adapter.py", line 91, in completion
    return await self.future
           ^^^^^^^^^^^^^^^^^
azure.iot.device.exceptions.ServiceError: register request returned a service error status code 401
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "C:\Users\parth\Desktop\Evaluation_Submission_Parth_Shah\Azure_Practical\Azure_DPS_Create.py", line 99, in twin_patch_listener
    registration_result = await provisioning_device_client.register()
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\parth\AppData\Local\Programs\Python\Python311\Lib\site-packages\azure\iot\device\provisioning\aio\async_provisioning_device_client.py", line 83, in register
    result = await handle_result(register_complete)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\parth\AppData\Local\Programs\Python\Python311\Lib\site-packages\azure\iot\device\provisioning\aio\async_provisioning_device_client.py", line 43, in handle_result
    raise exceptions.ClientError("Unexpected failure") from e
azure.iot.device.exceptions.ClientError: Unexpected failure

Code is:

import asyncio
from six.moves import input
import threading
from azure.iot.device.aio import IoTHubDeviceClient
# import dht11
import time
from azure.iot.hub import IoTHubRegistryManager
from azure.iot.hub.models import Twin, TwinProperties
import subprocess
from azure.iot.device.aio import ProvisioningDeviceClient

enr_grp_key = "<ENROLLMENT GROUP KEY>"
reg_id=""
provisioning_host = "azure-devices-provisioning.net"
id_scope = "<Id_SCOPE>"
powershell_script = f'''
$KEY = '{enr_grp_key}'
$REG_ID = '{reg_id}'
$hmacsha256 = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha256.key = [Convert]::FromBase64String($KEY)
$sig = $hmacsha256.ComputeHash([Text.Encoding]::ASCII.GetBytes($REG_ID))
$derivedkey = [Convert]::ToBase64String($sig)
Write-Output $derivedkey
'''

SAS_key =""

IOTHUB_CONNECTION_STRING = "<IoT_HUB_CONN STRING"
DEVICE_ID = "<DEVICE NAME CONTAINING DEVICE TWIN>"

iothub_registry_manager = IoTHubRegistryManager(IOTHUB_CONNECTION_STRING)

twin = iothub_registry_manager.get_twin(DEVICE_ID)

operation_patch = {
    "device-name": "",
    "operation": ""
}

loop = asyncio.get_event_loop()

async def main():
    conn_str = "DEVICE CONN STRING CONTAINING DEVICE TWIN"
    device_client = IoTHubDeviceClient.create_from_connection_string(conn_str)

    # connect the client.
    await device_client.connect()

    
    async def createDPSDevice(reg_id,SAS_key):
        provisioning_device_client = ProvisioningDeviceClient.create_from_symmetric_key(
                                                    provisioning_host=provisioning_host,
                                                    registration_id=reg_id,
                                                    id_scope=id_scope,
                                                    symmetric_key=SAS_key,
                                                )
        
        registration_result = await provisioning_device_client.register()

    # define behavior for receiving a twin patch
    async def twin_patch_listener(device_client):
        while True:    
            patch = await device_client.receive_twin_desired_properties_patch()  # blocking call
            last_device_name = patch['device-name']
            reg_id = last_device_name
            print(patch)
            if(patch['operation'] == "create device"):
                print("Inside: ",patch)
                patch["operation"] = ""
                patch["device-name"] = ""
                print("Generating SAS Key...")
                with open('script.ps1', 'w') as file:
                    file.write(powershell_script)

                shell_command = ['powershell.exe', '-File', 'script.ps1']
                p = subprocess.Popen(shell_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                output, error = p.communicate()
                SAS_key = output.decode('utf-8')
                print("Generated SAS key is: ", SAS_key)
                twin_patch = Twin(properties= TwinProperties(desired=patch))
                iothub_registry_manager.update_twin(DEVICE_ID, twin_patch, None)

                
                asyncio.create_task(createDPSDevice(reg_id,SAS_key))


            print("Last Device Name: ", last_device_name)
                

    # 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 twin patch
    asyncio.create_task(twin_patch_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())


Community Center Not monitored
0 comments No comments
{count} votes

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.