azext_iot/central/services/device.py (750 lines of code) (raw):

# coding=utf-8 # -------------------------------------------------------------------------------------------- # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- from typing import List import requests from azext_iot.central.common import API_VERSION, API_VERSION_PREVIEW from azext_iot.central.models.edge import EdgeModule from azext_iot.common.auth import get_aad_token from knack.log import get_logger from azure.cli.core.azclierror import ( AzureResponseError, ResourceNotFoundError, BadRequestError, ) from azext_iot.constants import CENTRAL_ENDPOINT from azext_iot.central.services import _utility from azext_iot.central.models.devicetwin import DeviceTwin from azext_iot.central.models.ga_2022_07_31 import (DeviceGa, RelationshipGa) from azext_iot.central.models.enum import DeviceStatus from azure.cli.core.util import should_disable_connection_verify from azext_iot.common.utility import dict_clean, parse_entity logger = get_logger(__name__) BASE_PATH = "api/devices" MODEL = "Device" REL_MODEL = "Relationship" def get_device( cmd, app_id: str, device_id: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ) -> DeviceGa: """ Get device info given a device id Args: cmd: command passed into az device_id: unique case-sensitive device id, app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: device: dict """ api_version = API_VERSION result = _utility.make_api_call( cmd, app_id=app_id, method="GET", url="https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, device_id), payload=None, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, ) return _utility.get_object(result, MODEL, api_version) def list_devices( cmd, app_id: str, filter: str, token: str, api_version=API_VERSION_PREVIEW, max_pages=0, central_dns_suffix=CENTRAL_ENDPOINT, ) -> List[DeviceGa]: """ Get a list of all devices in IoTC app Args: cmd: command passed into az app_id: name of app (used for forming request URL) filter: only show filtered devices (only in preview version now) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: list of devices """ # Have to use preview version for $filter api_version = API_VERSION_PREVIEW devices = [] url = "https://{}.{}/{}".format(app_id, central_dns_suffix, BASE_PATH) headers = _utility.get_headers(token, cmd) # Construct parameters query_parameters = {"api-version": api_version} if filter is not None: query_parameters["$filter"] = filter warning = "This command may take a long time to complete if your app contains a lot of devices." logger.warning(warning) pages_processed = 0 while (max_pages == 0 or pages_processed < max_pages) and url: response = requests.get( url, headers=headers, params=query_parameters if pages_processed == 0 else None, ) result = _utility.try_extract_result(response) if "value" not in result: raise AzureResponseError("Value is not present in body: {}".format(result)) devices.extend( [ _utility.get_object(device, MODEL, api_version) for device in result["value"] ] ) url = result.get("nextLink", None) pages_processed = pages_processed + 1 return devices def get_device_registration_summary( cmd, app_id: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ) -> dict: """ Get device registration summary for a given app Args: cmd: command passed into az app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: registration summary """ api_version = API_VERSION registration_summary = {status.value: 0 for status in DeviceStatus} url = "https://{}.{}/{}?api-version={}".format( app_id, central_dns_suffix, BASE_PATH, api_version ) headers = _utility.get_headers(token, cmd) logger.warning( "This command may take a long time to complete if your app contains a lot of devices" ) while url: response = requests.get( url, headers=headers, verify=not should_disable_connection_verify() ) result = _utility.try_extract_result(response) if "value" not in result: raise AzureResponseError("Value is not present in body: {}".format(result)) for device in result["value"]: registration_summary[ (_utility.get_object(device, MODEL, api_version))._device_status.value ] += 1 print("Processed {} devices...".format(sum(registration_summary.values()))) url = result.get("nextLink") return registration_summary def create_device( cmd, app_id: str, device_id: str, device_name: str, template: str, simulated: bool, organizations: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ) -> DeviceGa: """ Create a device in IoTC Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id device_name: (non-unique) human readable name for the device template: (optional) string that maps to the device_template_id of the device template that this device is to be an instance of simulated: if IoTC is to simulate data for this device token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: device: dict """ api_version = API_VERSION if not device_name: device_name = device_id url = "https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, device_id) headers = _utility.get_headers(token, cmd, has_json_payload=True) # Construct parameters query_parameters = {} query_parameters["api-version"] = api_version payload = {"displayName": device_name, "simulated": simulated, "enabled": True} if template: payload["template"] = template if organizations: payload["organizations"] = organizations.split(",") data = _utility.get_object(payload, MODEL, api_version) json = _utility.to_camel_dict(dict_clean(parse_entity(data))) response = requests.put(url, headers=headers, json=json, params=query_parameters) result = _utility.try_extract_result(response) return _utility.get_object(result, MODEL, api_version) def update_device( cmd, app_id: str, device_id: str, device_name: str, template: str, simulated: bool, enabled: bool, organizations: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ) -> DeviceGa: """ Update a device in IoTC Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id device_name: (non-unique) human readable name for the device template: (optional) string that maps to the device_template_id of the device template that this device is to be an instance of simulated: if IoTC is to simulate data for this device enabled: if device is enabled token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: device: dict """ api_version = API_VERSION url = "https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, device_id) headers = _utility.get_headers(token, cmd, has_json_payload=True) # Construct parameters query_parameters = {} query_parameters["api-version"] = api_version current_device = get_device( cmd=cmd, app_id=app_id, device_id=device_id, token=token, api_version=api_version, central_dns_suffix=central_dns_suffix, ) payload = dict_clean(parse_entity(current_device)) if device_name is not None: payload["displayName"] = device_name if template is not None: payload["template"] = template if enabled is not None: payload["enabled"] = enabled if simulated is not None: payload["simulated"] = simulated if organizations is not None: payload["organizations"] = organizations.split(",") # sanitize device payload based on apiversion data = _utility.get_object(payload, MODEL, api_version) json = _utility.to_camel_dict(dict_clean(parse_entity(data))) response = requests.patch( url, headers=headers, json=json, params=query_parameters, ) result = _utility.try_extract_result(response) return _utility.get_object(result, MODEL, api_version) def delete_device( cmd, app_id: str, device_id: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ) -> dict: """ Delete a device from IoTC Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id, token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: {"result": "success"} on success Raises error on failure """ api_version = API_VERSION return _utility.make_api_call( cmd, app_id=app_id, method="DELETE", url="https://{}.{}/{}/{}".format(app_id, central_dns_suffix, BASE_PATH, device_id), payload=None, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, ) def list_relationships( cmd, app_id: str, device_id: str, token: str, api_version=API_VERSION, max_pages=0, central_dns_suffix=CENTRAL_ENDPOINT, ) -> List[RelationshipGa]: api_version = API_VERSION url = "https://{}.{}/{}/{}/relationships".format( app_id, central_dns_suffix, BASE_PATH, device_id ) headers = _utility.get_headers(token, cmd, has_json_payload=True) # Construct parameters query_parameters = {} query_parameters["api-version"] = api_version relationships = [] pages_processed = 0 while (max_pages == 0 or pages_processed < max_pages) and url: response = requests.get( url, headers=headers, params=query_parameters if pages_processed == 0 else None, ) result = _utility.try_extract_result(response) if "value" not in result: raise AzureResponseError("Value is not present in body: {}".format(result)) relationships.extend( [ _utility.get_object(relationship, REL_MODEL, api_version) for relationship in result["value"] ] ) url = result.get("nextLink", None) pages_processed = pages_processed + 1 return relationships def create_relationship( cmd, app_id: str, device_id: str, target_id: str, rel_id: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ): api_version = API_VERSION payload = {"id": rel_id, "source": device_id, "target": target_id} response = _utility.make_api_call( cmd, app_id=app_id, method="PUT", url=f"https://{app_id}.{central_dns_suffix}/api/devices/{device_id}/relationships/{rel_id}", payload=payload, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, ) return _utility.get_object(response, REL_MODEL, api_version) def update_relationship( cmd, app_id: str, device_id: str, rel_id: str, target_id: str, token: str, api_version: str, central_dns_suffix=CENTRAL_ENDPOINT, ) -> RelationshipGa: """ Update a relationship in IoTC Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id rel_id: unique case-sensitive relationship id target_id: (optional) unique case-sensitive device id token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: device: dict """ api_version = API_VERSION payload = {"target": target_id} response = _utility.make_api_call( cmd, app_id=app_id, method="PATCH", url=f"https://{app_id}.{central_dns_suffix}/api/devices/{device_id}/relationships/{rel_id}", payload=payload, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, ) return _utility.get_object(response, REL_MODEL, api_version) def delete_relationship( cmd, app_id: str, device_id: str, rel_id: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ) -> dict: """ Delete a relationship from IoTC Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id, rel_id: unique case-sensitive relationship id, token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: {"result": "success"} on success Raises error on failure """ api_version = API_VERSION return _utility.make_api_call( cmd, app_id=app_id, method="DELETE", url=f"https://{app_id}.{central_dns_suffix}/api/devices/{device_id}/relationships/{rel_id}", payload=None, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, ) def get_device_credentials( cmd, app_id: str, device_id: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Get device credentials from IoTC Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id, token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: device_credentials: dict """ api_version = API_VERSION return _utility.make_api_call( cmd, app_id=app_id, method="GET", url="https://{}.{}/{}/{}/credentials".format(app_id, central_dns_suffix, BASE_PATH, device_id), payload=None, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, ) def run_command( cmd, app_id: str, token: str, device_id: str, component_name: str, module_name: str, command_name: str, payload: dict, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Execute a direct method on a device Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id component_name: name of device component module_name: name of device module command_name: name of command to execute payload: params for command token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: result (currently a 201) """ api_version = API_VERSION url = "https://{}.{}/{}/{}".format( app_id, central_dns_suffix, BASE_PATH, device_id ) if module_name is not None: url += f'/modules/{module_name}' if component_name is not None: url += f'/components/{component_name}' url += f'/commands/{command_name}' headers = _utility.get_headers(token, cmd) # Construct parameters query_parameters = {} query_parameters["api-version"] = api_version response = requests.post( url, headers=headers, json=payload, params=query_parameters ) # execute command response has caveats in it due to Async/Sync device methods # return the response if we get 201, otherwise try to apply generic logic if response.status_code == 201: return response.json() return _utility.try_extract_result(response) def get_command_history( cmd, app_id: str, token: str, device_id: str, component_name: str, module_name: str, command_name: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Get command history Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id component_name: name of device component module_name: name of device module command_name: name of command to view execution history token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: Command history (List) - currently limited to 1 item """ api_version = API_VERSION url = "https://{}.{}/{}/{}".format( app_id, central_dns_suffix, BASE_PATH, device_id ) if module_name is not None: url += f'/modules/{module_name}' if component_name is not None: url += f'/components/{component_name}' url += f'/commands/{command_name}' return _utility.make_api_call( cmd, app_id=app_id, method="GET", url=url, payload=None, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, ) def get_module_command_history( cmd, app_id: str, token: str, device_id: str, module_name: str, component_name: str, command_name: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Get module command history Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id module_name: name of the device module component_name: name of the device component command_name: name of command to view execution history token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: Module command history (List) """ api_version = API_VERSION url = "https://{}.{}/{}/{}/modules/{}/components/{}/commands/{}".format( app_id, central_dns_suffix, BASE_PATH, device_id, module_name, component_name, command_name ) if component_name is None: url = f"https://{app_id}.{central_dns_suffix}/api/devices/{device_id}/modules/{module_name}/commands/{command_name}" return _utility.make_api_call( cmd, app_id=app_id, method="GET", url=url, payload=None, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, ) def get_device_twin( cmd, app_id: str, device_id: str, token: str, central_dns_suffix=CENTRAL_ENDPOINT, ) -> DeviceTwin: """ Get device twin given a device id Args: cmd: command passed into az device_id: unique case-sensitive device id, app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: twin: dict """ if not token: aad_token = get_aad_token(cmd.cli_ctx, resource="https://apps.azureiotcentral.com")[ "accessToken" ] token = "Bearer {}".format(aad_token) url = f"https://{app_id}.{central_dns_suffix}/system/iothub/devices/{device_id}/get-twin?extendedInfo=true" headers = _utility.get_headers(token, cmd) # Construct parameters response = requests.get( url, headers=headers, verify=not should_disable_connection_verify(), ) response_data = _utility.try_extract_result(response) message = response_data.get("message") if ( message == f"Twin for device {device_id} was not found" or response_data.get("code") is not None ): # there is an error raise ResourceNotFoundError(f"Twin for device '{device_id}' was not found") else: return DeviceTwin(response_data) def run_manual_failover( cmd, app_id: str, device_id: str, ttl_minutes: int = None, token: str = None, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Execute a manual failover of device across multiple IoT Hubs to validate device firmware's ability to reconnect using DPS to a different IoT Hub. Args: cmd: command passed into az app_id: id of an app (used for forming request URL) device_id: unique case-sensitive device id ttl_minutes: (OPTIONAL) An optional value to specify the expiration time of this manual failover test before the device moves back to it's original IoT Hub. This has a default value of 30 minutes, but can optionally be any positive integer between 1 and 30. token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix:(OPTIONAL) {centralDnsSuffixInPath} as found in docs Returns: result (currently a 200) """ url = "https://{}.{}/{}/{}/manual-failover".format( app_id, central_dns_suffix, "system/iothub/devices", device_id ) headers = _utility.get_headers(token, cmd) json = {} if ttl_minutes: json = {"ttl": ttl_minutes} else: print( """Using default time to live - see https://github.com/iot-for-all/iot-central-high-availability-clients#readme for more information""" ) response = requests.post( url, headers=headers, verify=not should_disable_connection_verify(), json=json ) _utility.log_response_debug(response=response, logger=logger) return _utility.try_extract_result(response) def run_manual_failback( cmd, app_id: str, device_id: str, token: str, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Execute a manual failback for device. Reverts the previously executed failover command by moving the device back to it's original IoT Hub. Args: cmd: command passed into az app_id: id of an app (used for forming request URL) device_id: unique case-sensitive device id token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: result (currently a 200) """ url = "https://{}.{}/{}/{}/manual-failback".format( app_id, central_dns_suffix, "system/iothub/devices", device_id ) headers = _utility.get_headers(token, cmd) response = requests.post( url, headers=headers, verify=not should_disable_connection_verify() ) _utility.log_response_debug(response=response, logger=logger) return _utility.try_extract_result(response) def purge_c2d_messages( cmd, app_id: str, device_id: str, token: str, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Purges cloud to device (C2D) message queue for the specified device. Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id, token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: { message: 'Cloud to device (C2D) message queue purged for device {device_id}.\\n Total messages purged: {totalMessagesPurged}.' } on success Raises error on failure """ url = "https://{}.{}/{}/{}/c2d".format( app_id, central_dns_suffix, "system/iothub/devices", device_id ) headers = _utility.get_headers(token, cmd) response = requests.delete(url, headers=headers) return _utility.try_extract_result(response) def list_device_modules( cmd, app_id: str, device_id: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ) -> List[EdgeModule]: """ Get edge device modules Args: cmd: command passed into az device_id: unique case-sensitive device id, app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: modules: list """ if not token: aad_token = get_aad_token(cmd.cli_ctx, resource="https://apps.azureiotcentral.com")[ "accessToken" ] token = "Bearer {}".format(aad_token) url = f"https://{app_id}.{central_dns_suffix}/system/iotedge/devices/{device_id}/modules" headers = _utility.get_headers(token, cmd) # Construct parameters response = requests.get( url, headers=headers, verify=not should_disable_connection_verify(), ) response_data = _utility.try_extract_result(response).get("modules") if not response_data: raise BadRequestError(f"Device '{device_id}' is not an IoT Edge device.") return [EdgeModule(dict_clean(module)) for module in response_data] def restart_device_module( cmd, app_id: str, device_id: str, module_id: str, token: str, central_dns_suffix=CENTRAL_ENDPOINT, ) -> EdgeModule: """ Restart a device module Args: cmd: command passed into az device_id: unique case-sensitive device id, module_id: unique case-sensitive module id, app_id: name of app (used for forming request URL) token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: module: dict """ if not token: aad_token = get_aad_token(cmd.cli_ctx, resource="https://apps.azureiotcentral.com")[ "accessToken" ] token = "Bearer {}".format(aad_token) url = f"https://{app_id}.{central_dns_suffix}/system/iotedge/devices/{device_id}/modules/$edgeAgent/directmethods" json = { "methodName": "RestartModule", "payload": {"schemaVersion": "1.0", "id": module_id}, } headers = _utility.get_headers(token, cmd) # Construct parameters response = requests.post( url, json=json, headers=headers, verify=not should_disable_connection_verify(), ) return response.json() def get_device_attestation( cmd, app_id: str, device_id: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Gets the attestation for a device. Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: device_attestation: dict """ api_version = API_VERSION return _utility.make_api_call( cmd, app_id=app_id, method="GET", url=f"https://{app_id}.{central_dns_suffix}/api/devices/{device_id}/attestation", payload=None, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, ) def delete_device_attestation( cmd, app_id: str, device_id: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Remove an individual device attestation. Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id, token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: {"result": "success"} on success Raises error on failure """ api_version = API_VERSION return _utility.make_api_call( cmd, app_id=app_id, method="DELETE", url=f"https://{app_id}.{central_dns_suffix}/api/devices/{device_id}/attestation", payload=None, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, ) def update_device_attestation( cmd, app_id: str, device_id: str, payload: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Update an individual device attestation via patch Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id, payload: attestation key definition in JSON token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: {"result": "success"} on success Raises error on failure """ api_version = API_VERSION return _utility.make_api_call( cmd, app_id=app_id, method="PATCH", url=f"https://{app_id}.{central_dns_suffix}/api/devices/{device_id}/attestation", payload=payload, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, ) def create_device_attestation( cmd, app_id: str, device_id: str, payload: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Create an individual device attestation Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id, payload: attestation key definition in JSON token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: {"result": "success"} on success Raises error on failure """ api_version = API_VERSION return _utility.make_api_call( cmd, app_id=app_id, method="PUT", url=f"https://{app_id}.{central_dns_suffix}/api/devices/{device_id}/attestation", payload=payload, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, ) def list_device_components( cmd, app_id: str, device_id: str, module_name: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ) -> List[dict]: """ List the components in device or device module Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id, module_name: name of the device module, token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: components: dict """ api_version = API_VERSION url = f"https://{app_id}.{central_dns_suffix}/api/devices/{device_id}" if module_name is not None: url += f"/modules/{module_name}" url += "/components" return _utility.make_api_call( cmd, app_id=app_id, method="GET", url=url, payload=None, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, ) def list_modules( cmd, app_id: str, device_id: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ) -> List[dict]: """ List the modules in a device Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id, token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: modules: dict """ api_version = API_VERSION return _utility.make_api_call( cmd, app_id=app_id, method="GET", url=f"https://{app_id}.{central_dns_suffix}/api/devices/{device_id}/modules", payload=None, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, ) def get_device_properties_or_telemetry_value( cmd, app_id: str, device_id: str, module_name: str, component_name: str, telemetry_name: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Get device properties or telemetry value for device / component / module / module component Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id, moduleName: name of the device module, component_name: name of the device component, token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: properties/telemetry value: dict """ api_version = API_VERSION url = f"https://{app_id}.{central_dns_suffix}/api/devices/{device_id}" if module_name is not None: url += f"/modules/{module_name}" if component_name is not None: url += f"/components/{component_name}" if telemetry_name is not None: url += f"/telemetry/{telemetry_name}" else: url += "/properties" return _utility.make_api_call( cmd, app_id=app_id, method="GET", url=url, payload=None, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, ) def replace_properties( cmd, app_id: str, device_id: str, module_name: str, component_name: str, payload: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Replace properties for device / component / module / module component Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id module_name: name of the device module component_name: name of the device component payload: properties in JSON token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: properties: dict """ api_version = API_VERSION url = f"https://{app_id}.{central_dns_suffix}/api/devices/{device_id}" if module_name is not None: url += f"/modules/{module_name}" if component_name is not None: url += f"/components/{component_name}" url += "/properties" return _utility.make_api_call( cmd, app_id=app_id, method="PUT", url=url, payload=payload, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, ) def update_properties( cmd, app_id: str, device_id: str, module_name: str, component_name: str, payload: str, token: str, api_version=API_VERSION, central_dns_suffix=CENTRAL_ENDPOINT, ): """ Update properties for device / component / module / module component Args: cmd: command passed into az app_id: name of app (used for forming request URL) device_id: unique case-sensitive device id moduleName: name of the device module component_name: name of the device component payload: properties in JSON token: (OPTIONAL) authorization token to fetch device details from IoTC. MUST INCLUDE type (e.g. 'SharedAccessToken ...', 'Bearer ...') central_dns_suffix: {centralDnsSuffixInPath} as found in docs Returns: properties: dict """ api_version = API_VERSION url = f"https://{app_id}.{central_dns_suffix}/api/devices/{device_id}" if module_name is not None: url += f"/modules/{module_name}" if component_name is not None: url += f"/components/{component_name}" url += "/properties" return _utility.make_api_call( cmd, app_id=app_id, method="PATCH", url=url, payload=payload, token=token, api_version=api_version, central_dnx_suffix=central_dns_suffix, )