Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iotc updates #368

Merged
merged 14 commits into from
Jun 15, 2021
Merged
6 changes: 6 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ Release History
0.10.14
+++++++++++++++

**IoT Central updates**

* add support to run root/interface level device commands.
* add support to get command history for root/interface level device commands.
* interface_id parameter for commands "device command run" , "device command history" run changed to optional.

**IoT Hub updates**

* Fix for "az iot hub c2d-message receive" - the command will use the "ContentEncoding" header value (which indicates the message body encoding)
Expand Down
8 changes: 4 additions & 4 deletions azext_iot/central/commands_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ def run_command(
cmd,
app_id: str,
device_id: str,
interface_id: str,
command_name: str,
content: str,
interface_id=None,
token=None,
central_dns_suffix=CENTRAL_ENDPOINT,
api_version=ApiVersion.v1.value,
Expand All @@ -122,7 +122,7 @@ def run_command(
else:
provider = CentralDeviceProviderV1(cmd=cmd, app_id=app_id, token=token)

return provider.run_component_command(
return provider.run_command(
device_id=device_id,
interface_id=interface_id,
command_name=command_name,
Expand Down Expand Up @@ -163,9 +163,9 @@ def get_command_history(
cmd,
app_id: str,
device_id: str,
interface_id: str,
command_name: str,
token=None,
interface_id=None,
central_dns_suffix=CENTRAL_ENDPOINT,
api_version=ApiVersion.v1.value,
):
Expand All @@ -174,7 +174,7 @@ def get_command_history(
else:
provider = CentralDeviceProviderV1(cmd=cmd, app_id=app_id, token=token)

return provider.get_component_command_history(
return provider.get_command_history(
device_id=device_id,
interface_id=interface_id,
command_name=command_name,
Expand Down
4 changes: 2 additions & 2 deletions azext_iot/central/params.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ def load_central_arguments(self, _):
context.argument(
"interface_id",
options_list=["--interface-id", "-i"],
help="The name of the interface as specified in the device template. You can find it by navigating to Device"
" Template and view the interface identity under the corresponding device capability.",
help="The name of the interface/component as specified in the device template.You can find it by navigating"
" to Device Template and view the interface/component identity under the corresponding device capability.",
)
context.argument(
"command_name",
Expand Down
37 changes: 31 additions & 6 deletions azext_iot/central/providers/preview/device_provider_preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,39 +126,64 @@ def delete_device(self, device_id, central_dns_suffix=CENTRAL_ENDPOINT,) -> dict

return result

def run_component_command(
def run_command(
self,
device_id: str,
interface_id: str,
command_name: str,
payload: dict,
central_dns_suffix=CENTRAL_ENDPOINT,
) -> dict:
return central_services.device.run_component_command(

if interface_id:
return central_services.device.run_component_command(
cmd=self._cmd,
app_id=self._app_id,
token=self._token,
device_id=device_id,
interface_id=interface_id,
command_name=command_name,
payload=payload,
central_dns_suffix=central_dns_suffix,
api_version=ApiVersion.preview.value,
)

return central_services.device.run_command(
cmd=self._cmd,
app_id=self._app_id,
token=self._token,
device_id=device_id,
interface_id=interface_id,
command_name=command_name,
payload=payload,
central_dns_suffix=central_dns_suffix,
api_version=ApiVersion.preview.value,
)

def get_component_command_history(
def get_command_history(
self,
device_id: str,
interface_id: str,
command_name: str,
central_dns_suffix=CENTRAL_ENDPOINT,
) -> dict:
return central_services.device.get_component_command_history(

if interface_id:
return central_services.device.get_component_command_history(
cmd=self._cmd,
app_id=self._app_id,
token=self._token,
device_id=device_id,
interface_id=interface_id,
command_name=command_name,
central_dns_suffix=central_dns_suffix,
api_version=ApiVersion.preview.value,
)

return central_services.device.get_command_history(
cmd=self._cmd,
app_id=self._app_id,
token=self._token,
device_id=device_id,
interface_id=interface_id,
command_name=command_name,
central_dns_suffix=central_dns_suffix,
api_version=ApiVersion.preview.value,
Expand Down
60 changes: 54 additions & 6 deletions azext_iot/central/providers/v1/device_provider_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,39 +194,70 @@ def get_device_registration_summary(self, central_dns_suffix=CENTRAL_ENDPOINT):
central_dns_suffix=central_dns_suffix,
)

def run_component_command(
def run_command(
self,
device_id: str,
interface_id: str,
command_name: str,
payload: dict,
central_dns_suffix=CENTRAL_ENDPOINT,
):
return central_services.device.run_component_command(
if interface_id and self._is_interface_id_component(
device_id=device_id,
interface_id=interface_id,
central_dns_suffix=central_dns_suffix,
):
return central_services.device.run_component_command(
cmd=self._cmd,
app_id=self._app_id,
token=self._token,
device_id=device_id,
interface_id=interface_id,
command_name=command_name,
payload=payload,
central_dns_suffix=central_dns_suffix,
api_version=ApiVersion.v1.value,
)
return central_services.device.run_command(
cmd=self._cmd,
app_id=self._app_id,
token=self._token,
device_id=device_id,
interface_id=interface_id,
command_name=command_name,
payload=payload,
central_dns_suffix=central_dns_suffix,
api_version=ApiVersion.v1.value,
)

def get_component_command_history(
def get_command_history(
self,
device_id: str,
interface_id: str,
command_name: str,
central_dns_suffix=CENTRAL_ENDPOINT,
):
return central_services.device.get_component_command_history(

if interface_id and self._is_interface_id_component(
device_id=device_id,
interface_id=interface_id,
central_dns_suffix=central_dns_suffix,
):
return central_services.device.get_component_command_history(
cmd=self._cmd,
app_id=self._app_id,
token=self._token,
device_id=device_id,
interface_id=interface_id,
command_name=command_name,
central_dns_suffix=central_dns_suffix,
api_version=ApiVersion.v1.value,
)

return central_services.device.get_command_history(
cmd=self._cmd,
app_id=self._app_id,
token=self._token,
device_id=device_id,
interface_id=interface_id,
command_name=command_name,
central_dns_suffix=central_dns_suffix,
api_version=ApiVersion.v1.value,
Expand Down Expand Up @@ -272,3 +303,20 @@ def _dps_populate_essential_info(self, dps_info, device_status: DeviceStatus):
"error": error.get(device_status),
}
return filtered_dps_info

def _is_interface_id_component(
self, device_id: str, interface_id: str, central_dns_suffix=CENTRAL_ENDPOINT,
) -> bool:

current_device = self.get_device(device_id, central_dns_suffix)

template = central_services.device_template.get_device_template(
cmd=self._cmd,
app_id=self._app_id,
device_template_id=current_device.template,
token=self._token,
central_dns_suffix=central_dns_suffix,
api_version=ApiVersion.v1.value,
)

return bool(interface_id in template.components)
84 changes: 84 additions & 0 deletions azext_iot/central/services/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,53 @@ def get_device_credentials(
return _utility.try_extract_result(response)


def run_command(
cmd,
app_id: str,
token: str,
device_id: str,
command_name: str,
payload: dict,
central_dns_suffix=CENTRAL_ENDPOINT,
api_version=ApiVersion.v1.value,
):
"""
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
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)
"""
url = "https://{}.{}/{}/{}/commands/{}".format(
app_id, central_dns_suffix, BASE_PATH, device_id, 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 run_component_command(
cmd,
app_id: str,
Expand Down Expand Up @@ -352,6 +399,43 @@ def run_component_command(
return _utility.try_extract_result(response)


def get_command_history(
cmd,
app_id: str,
token: str,
device_id: str,
command_name: str,
central_dns_suffix=CENTRAL_ENDPOINT,
api_version=ApiVersion.v1.value,
):
"""
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
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
"""
url = "https://{}.{}/{}/{}/commands/{}".format(
app_id, central_dns_suffix, BASE_PATH, device_id, command_name
)
headers = _utility.get_headers(token, cmd)

# Construct parameters
query_parameters = {}
query_parameters["api-version"] = api_version

response = requests.get(url, headers=headers, params=query_parameters)
return _utility.try_extract_result(response)


def get_component_command_history(
cmd,
app_id: str,
Expand Down
9 changes: 9 additions & 0 deletions azext_iot/tests/central/json/device_template_int_test.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@
],
"displayName": "Component"
}
},
{
"@id": "urn:rigado:RS40_Occupancy_Sensor:testRootCommand:9",
"@type": "Command",
"commandType": "synchronous",
"displayName": {
"en": "testRootCommand"
},
"name": "testRootCommand"
}
],
"displayName": "larger-telemetry-device",
Expand Down
Loading