From e0b473c773a2f8f012a6b558b5d53ccf4fc4c94b Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 31 Jul 2025 11:00:58 +1000 Subject: [PATCH 1/3] tools: localhost: limit default table height Limit the default table height to 25 rows, as any more will typically roll off the bottom of the screen even when zoomed out. Signed-off-by: Jordan Yates --- src/infuse_iot/tools/localhost/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/infuse_iot/tools/localhost/index.html b/src/infuse_iot/tools/localhost/index.html index 416288d..53c9e97 100644 --- a/src/infuse_iot/tools/localhost/index.html +++ b/src/infuse_iot/tools/localhost/index.html @@ -42,7 +42,7 @@

Table Control

const dataTable = new Tabulator("#data-table", { layout: "fitDataTable", pagination:"local", - paginationSize:100, + paginationSize:25, paginationSizeSelector:[10, 25, 50, 100], paginationCounter:"rows", }); From 0e4979733b0b5b3c28d3937a4dfbe335841eaad8 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 31 Jul 2025 11:08:36 +1000 Subject: [PATCH 2/3] rpc_wrappers: lte_pdp_ctx: configurable family Make the PDP context family configurable, defaulting to IPv4v6 instead of the current IPv4 as recommended from Devzone. Signed-off-by: Jordan Yates --- scripts/apn_set.py | 9 +++++++-- src/infuse_iot/rpc_wrappers/lte_pdp_ctx.py | 17 +++++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/scripts/apn_set.py b/scripts/apn_set.py index 302cde6..2073681 100755 --- a/scripts/apn_set.py +++ b/scripts/apn_set.py @@ -25,6 +25,7 @@ class APNSetter: def __init__(self, args: argparse.Namespace): self.app_id = args.app self.apn = args.apn + self.family = args.family self.client = LocalClient(default_multicast_address(), 1.0) self.decoder = TDF() self.state = "Scanning" @@ -65,8 +66,7 @@ def announce_observed(self, live: Live, infuse_id: int, pkt: readings.announce): with self.client.connection(infuse_id, GatewayRequestConnectionRequest.DataType.COMMAND) as mtu: rpc_client = RpcClient(self.client, mtu, infuse_id) - ipv4 = 0 - family_bytes = ipv4.to_bytes(1, "little") + family_bytes = self.family.to_bytes(1, "little") apn_bytes = self.apn.encode("utf-8") + b"\x00" val_bytes = family_bytes + len(apn_bytes).to_bytes(1, "little") + apn_bytes @@ -102,6 +102,11 @@ def run(self): addr_group = parser.add_mutually_exclusive_group(required=True) addr_group.add_argument("--app", type=lambda x: int(x, 0), help="Application ID to configure") parser.add_argument("--apn", type=str, required=True, help="LTE APN value") + family_group = parser.add_mutually_exclusive_group() + family_group.add_argument("--ipv4", dest="family", action="store_const", const=0, help="IPv4") + family_group.add_argument("--ipv6", dest="family", action="store_const", const=1, help="IPv6") + family_group.add_argument("--ipv4v6", dest="family", action="store_const", default=2, const=2, help="IPv4v6") + family_group.add_argument("--nonip", dest="family", action="store_const", const=3, help="NonIP") args = parser.parse_args() diff --git a/src/infuse_iot/rpc_wrappers/lte_pdp_ctx.py b/src/infuse_iot/rpc_wrappers/lte_pdp_ctx.py index d10a1f7..ae931ce 100644 --- a/src/infuse_iot/rpc_wrappers/lte_pdp_ctx.py +++ b/src/infuse_iot/rpc_wrappers/lte_pdp_ctx.py @@ -43,13 +43,26 @@ class kv_store_value(ctypes.LittleEndianStructure): @classmethod def add_parser(cls, parser): parser.add_argument("--apn", "-a", type=str, required=True, help="Access Point Name") + family_group = parser.add_mutually_exclusive_group() + family_group.add_argument("--ipv4", dest="family", action="store_const", const=cls.PDPFamily.IPv4, help="IPv4") + family_group.add_argument("--ipv6", dest="family", action="store_const", const=cls.PDPFamily.IPv6, help="IPv6") + family_group.add_argument( + "--ipv4v6", + dest="family", + action="store_const", + default=cls.PDPFamily.IPv4v6, + const=cls.PDPFamily.IPv4v6, + help="IPv4v6", + ) + family_group.add_argument( + "--nonip", dest="family", action="store_const", const=cls.PDPFamily.NonIP, help="NonIP" + ) def __init__(self, args): self.args = args def request_struct(self): - # Hardcode IPv4 for now - family_bytes = self.PDPFamily.IPv4.to_bytes(1, "little") + family_bytes = self.args.family.to_bytes(1, "little") apn_bytes = self.args.apn.encode("utf-8") + b"\x00" apn_bytes = len(apn_bytes).to_bytes(1, "little") + apn_bytes From 30d8785ce9f37f95de5c7670a59cea60e85dcced Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 31 Jul 2025 11:25:57 +1000 Subject: [PATCH 3/3] infuse_iot: api_client: regenerate client Regenerate the cloud api client from the updated specification. Signed-off-by: Jordan Yates --- doc/APIClientRegen.md | 11 ++ ...ice_logger_state_by_device_id_and_index.py | 166 ++++++++++++++++ .../api_client/api/key/derive_device_key.py | 177 ++++++++++++++++++ src/infuse_iot/api_client/models/__init__.py | 18 ++ .../api_client/models/bt_le_route.py | 69 +++++++ .../api_client/models/bt_le_route_type.py | 10 + .../models/derive_device_key_body.py | 92 +++++++++ .../api_client/models/device_logger_state.py | 111 +++++++++++ .../api_client/models/downlink_route.py | 68 +++++++ .../models/forwarded_downlink_route.py | 81 ++++++++ .../models/forwarded_uplink_route.py | 89 +++++++++ .../api_client/models/key_interface.py | 11 ++ .../api_client/models/new_rpc_req.py | 27 +++ .../api_client/models/route_type.py | 6 + src/infuse_iot/api_client/models/rpc_req.py | 27 +++ .../api_client/models/rpc_req_data_header.py | 67 +++++++ src/infuse_iot/api_client/models/rpc_rsp.py | 10 + .../api_client/models/security_state.py | 99 ++++++++++ .../api_client/models/uplink_route.py | 68 +++++++ 19 files changed, 1207 insertions(+) create mode 100644 doc/APIClientRegen.md create mode 100644 src/infuse_iot/api_client/api/device/get_device_logger_state_by_device_id_and_index.py create mode 100644 src/infuse_iot/api_client/api/key/derive_device_key.py create mode 100644 src/infuse_iot/api_client/models/bt_le_route.py create mode 100644 src/infuse_iot/api_client/models/bt_le_route_type.py create mode 100644 src/infuse_iot/api_client/models/derive_device_key_body.py create mode 100644 src/infuse_iot/api_client/models/device_logger_state.py create mode 100644 src/infuse_iot/api_client/models/forwarded_downlink_route.py create mode 100644 src/infuse_iot/api_client/models/forwarded_uplink_route.py create mode 100644 src/infuse_iot/api_client/models/key_interface.py create mode 100644 src/infuse_iot/api_client/models/rpc_req_data_header.py create mode 100644 src/infuse_iot/api_client/models/security_state.py diff --git a/doc/APIClientRegen.md b/doc/APIClientRegen.md new file mode 100644 index 0000000..35ff6a9 --- /dev/null +++ b/doc/APIClientRegen.md @@ -0,0 +1,11 @@ +# Regenerating the API Client + +1. Download the latest API specification from https://api.infuse-iot.com/docs +2. Delete the previous API client: `rm -r ./src/infuse-iot/api_client` +3. Generate API client into the root directory: `openapi-python-client generate --path ./infuse-api.yaml` +4. Move API client to desired directory: `mv infuse-api-client/infuse_api_client/ ./src/infuse_iot/api_client/` +5. Move README: `mv infuse-api-client/README.md ./src/infuse_iot/api_client/` +6. Remove extraneous files: `rm -r infuse-api-client` +7. Manually fixup `README.md` for naming + +Some of these steps can possibly be automated with the `openapi-python-client` `--config` parameter in the future. diff --git a/src/infuse_iot/api_client/api/device/get_device_logger_state_by_device_id_and_index.py b/src/infuse_iot/api_client/api/device/get_device_logger_state_by_device_id_and_index.py new file mode 100644 index 0000000..5da2a95 --- /dev/null +++ b/src/infuse_iot/api_client/api/device/get_device_logger_state_by_device_id_and_index.py @@ -0,0 +1,166 @@ +from http import HTTPStatus +from typing import Any, Optional, Union, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.device_logger_state import DeviceLoggerState +from ...types import Response + + +def _get_kwargs( + device_id: str, + index: int, +) -> dict[str, Any]: + _kwargs: dict[str, Any] = { + "method": "get", + "url": f"/device/deviceId/{device_id}/loggerState/{index}", + } + + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Any, DeviceLoggerState]]: + if response.status_code == 200: + response_200 = DeviceLoggerState.from_dict(response.json()) + + return response_200 + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Any, DeviceLoggerState]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + device_id: str, + index: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, DeviceLoggerState]]: + """Get logger state by DeviceID and index + + Args: + device_id (str): + index (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, DeviceLoggerState]] + """ + + kwargs = _get_kwargs( + device_id=device_id, + index=index, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + device_id: str, + index: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, DeviceLoggerState]]: + """Get logger state by DeviceID and index + + Args: + device_id (str): + index (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, DeviceLoggerState] + """ + + return sync_detailed( + device_id=device_id, + index=index, + client=client, + ).parsed + + +async def asyncio_detailed( + device_id: str, + index: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Response[Union[Any, DeviceLoggerState]]: + """Get logger state by DeviceID and index + + Args: + device_id (str): + index (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Any, DeviceLoggerState]] + """ + + kwargs = _get_kwargs( + device_id=device_id, + index=index, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + device_id: str, + index: int, + *, + client: Union[AuthenticatedClient, Client], +) -> Optional[Union[Any, DeviceLoggerState]]: + """Get logger state by DeviceID and index + + Args: + device_id (str): + index (int): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Any, DeviceLoggerState] + """ + + return ( + await asyncio_detailed( + device_id=device_id, + index=index, + client=client, + ) + ).parsed diff --git a/src/infuse_iot/api_client/api/key/derive_device_key.py b/src/infuse_iot/api_client/api/key/derive_device_key.py new file mode 100644 index 0000000..98d3f49 --- /dev/null +++ b/src/infuse_iot/api_client/api/key/derive_device_key.py @@ -0,0 +1,177 @@ +from http import HTTPStatus +from typing import Any, Optional, Union + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.derive_device_key_body import DeriveDeviceKeyBody +from ...models.error import Error +from ...models.key import Key +from ...types import Response + + +def _get_kwargs( + *, + body: DeriveDeviceKeyBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/key/derived/device", + } + + _body = body.to_dict() + + _kwargs["json"] = _body + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Optional[Union[Error, Key]]: + if response.status_code == 200: + response_200 = Key.from_dict(response.json()) + + return response_200 + if response.status_code == 400: + response_400 = Error.from_dict(response.json()) + + return response_400 + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: Union[AuthenticatedClient, Client], response: httpx.Response +) -> Response[Union[Error, Key]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: DeriveDeviceKeyBody, +) -> Response[Union[Error, Key]]: + """Derive a device key for encryption + + Generate a derived key to use for device level encrpytion, if security state is provided, it will be + used to derive the key, otherwise the last stored security state will be used. + + Args: + body (DeriveDeviceKeyBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, Key]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: Union[AuthenticatedClient, Client], + body: DeriveDeviceKeyBody, +) -> Optional[Union[Error, Key]]: + """Derive a device key for encryption + + Generate a derived key to use for device level encrpytion, if security state is provided, it will be + used to derive the key, otherwise the last stored security state will be used. + + Args: + body (DeriveDeviceKeyBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, Key] + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: Union[AuthenticatedClient, Client], + body: DeriveDeviceKeyBody, +) -> Response[Union[Error, Key]]: + """Derive a device key for encryption + + Generate a derived key to use for device level encrpytion, if security state is provided, it will be + used to derive the key, otherwise the last stored security state will be used. + + Args: + body (DeriveDeviceKeyBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Union[Error, Key]] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: Union[AuthenticatedClient, Client], + body: DeriveDeviceKeyBody, +) -> Optional[Union[Error, Key]]: + """Derive a device key for encryption + + Generate a derived key to use for device level encrpytion, if security state is provided, it will be + used to derive the key, otherwise the last stored security state will be used. + + Args: + body (DeriveDeviceKeyBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Union[Error, Key] + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/src/infuse_iot/api_client/models/__init__.py b/src/infuse_iot/api_client/models/__init__.py index 1a80510..85e0306 100644 --- a/src/infuse_iot/api_client/models/__init__.py +++ b/src/infuse_iot/api_client/models/__init__.py @@ -3,6 +3,8 @@ from .algorithm import Algorithm from .application_version import ApplicationVersion from .board import Board +from .bt_le_route import BtLeRoute +from .bt_le_route_type import BtLeRouteType from .coap_file_stats import COAPFileStats from .coap_files_list import COAPFilesList from .created_board_properties import CreatedBoardProperties @@ -34,9 +36,11 @@ from .definitions_tdf_definitions import DefinitionsTDFDefinitions from .definitions_tdf_response import DefinitionsTDFResponse from .definitions_tdf_structs import DefinitionsTDFStructs +from .derive_device_key_body import DeriveDeviceKeyBody from .device import Device from .device_and_state import DeviceAndState from .device_id_field import DeviceIdField +from .device_logger_state import DeviceLoggerState from .device_metadata import DeviceMetadata from .device_metadata_update import DeviceMetadataUpdate from .device_metadata_update_operation import DeviceMetadataUpdateOperation @@ -46,9 +50,12 @@ from .downlink_message_status import DownlinkMessageStatus from .downlink_route import DownlinkRoute from .error import Error +from .forwarded_downlink_route import ForwardedDownlinkRoute +from .forwarded_uplink_route import ForwardedUplinkRoute from .health_check import HealthCheck from .interface_data import InterfaceData from .key import Key +from .key_interface import KeyInterface from .metadata_field import MetadataField from .new_board import NewBoard from .new_device import NewDevice @@ -61,7 +68,9 @@ from .rpc_message import RpcMessage from .rpc_params import RPCParams from .rpc_req import RpcReq +from .rpc_req_data_header import RPCReqDataHeader from .rpc_rsp import RpcRsp +from .security_state import SecurityState from .udp_downlink_route import UdpDownlinkRoute from .udp_uplink_route import UdpUplinkRoute from .uplink_route import UplinkRoute @@ -70,6 +79,8 @@ "Algorithm", "ApplicationVersion", "Board", + "BtLeRoute", + "BtLeRouteType", "COAPFilesList", "COAPFileStats", "CreatedBoardProperties", @@ -101,9 +112,11 @@ "DefinitionsTDFDefinitions", "DefinitionsTDFResponse", "DefinitionsTDFStructs", + "DeriveDeviceKeyBody", "Device", "DeviceAndState", "DeviceIdField", + "DeviceLoggerState", "DeviceMetadata", "DeviceMetadataUpdate", "DeviceMetadataUpdateOperation", @@ -113,9 +126,12 @@ "DownlinkMessageStatus", "DownlinkRoute", "Error", + "ForwardedDownlinkRoute", + "ForwardedUplinkRoute", "HealthCheck", "InterfaceData", "Key", + "KeyInterface", "MetadataField", "NewBoard", "NewDevice", @@ -128,7 +144,9 @@ "RpcMessage", "RPCParams", "RpcReq", + "RPCReqDataHeader", "RpcRsp", + "SecurityState", "UdpDownlinkRoute", "UdpUplinkRoute", "UplinkRoute", diff --git a/src/infuse_iot/api_client/models/bt_le_route.py b/src/infuse_iot/api_client/models/bt_le_route.py new file mode 100644 index 0000000..4532039 --- /dev/null +++ b/src/infuse_iot/api_client/models/bt_le_route.py @@ -0,0 +1,69 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.bt_le_route_type import BtLeRouteType + +T = TypeVar("T", bound="BtLeRoute") + + +@_attrs_define +class BtLeRoute: + """ + Attributes: + address (str): Bluetooth LE address of device + type_ (BtLeRouteType): Type of Bluetooth LE address (public or random) + """ + + address: str + type_: BtLeRouteType + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + address = self.address + + type_ = self.type_.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "address": address, + "type": type_, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + address = d.pop("address") + + type_ = BtLeRouteType(d.pop("type")) + + bt_le_route = cls( + address=address, + type_=type_, + ) + + bt_le_route.additional_properties = d + return bt_le_route + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/infuse_iot/api_client/models/bt_le_route_type.py b/src/infuse_iot/api_client/models/bt_le_route_type.py new file mode 100644 index 0000000..c5e65da --- /dev/null +++ b/src/infuse_iot/api_client/models/bt_le_route_type.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class BtLeRouteType(str, Enum): + PUBLIC = "public" + RANDOM = "random" + UNKNOWN = "unknown" + + def __str__(self) -> str: + return str(self.value) diff --git a/src/infuse_iot/api_client/models/derive_device_key_body.py b/src/infuse_iot/api_client/models/derive_device_key_body.py new file mode 100644 index 0000000..769123a --- /dev/null +++ b/src/infuse_iot/api_client/models/derive_device_key_body.py @@ -0,0 +1,92 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.key_interface import KeyInterface +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.security_state import SecurityState + + +T = TypeVar("T", bound="DeriveDeviceKeyBody") + + +@_attrs_define +class DeriveDeviceKeyBody: + """ + Attributes: + device_id (str): The ID of the device to send the RPC to as a hex string Example: d291d4d66bf0a955. + interface (KeyInterface): + security_state (Union[Unset, SecurityState]): + """ + + device_id: str + interface: KeyInterface + security_state: Union[Unset, "SecurityState"] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + device_id = self.device_id + + interface = self.interface.value + + security_state: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.security_state, Unset): + security_state = self.security_state.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "deviceId": device_id, + "interface": interface, + } + ) + if security_state is not UNSET: + field_dict["securityState"] = security_state + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.security_state import SecurityState + + d = dict(src_dict) + device_id = d.pop("deviceId") + + interface = KeyInterface(d.pop("interface")) + + _security_state = d.pop("securityState", UNSET) + security_state: Union[Unset, SecurityState] + if isinstance(_security_state, Unset): + security_state = UNSET + else: + security_state = SecurityState.from_dict(_security_state) + + derive_device_key_body = cls( + device_id=device_id, + interface=interface, + security_state=security_state, + ) + + derive_device_key_body.additional_properties = d + return derive_device_key_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/infuse_iot/api_client/models/device_logger_state.py b/src/infuse_iot/api_client/models/device_logger_state.py new file mode 100644 index 0000000..4ad7697 --- /dev/null +++ b/src/infuse_iot/api_client/models/device_logger_state.py @@ -0,0 +1,111 @@ +import datetime +from collections.abc import Mapping +from typing import Any, TypeVar, Union + +from attrs import define as _attrs_define +from attrs import field as _attrs_field +from dateutil.parser import isoparse + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DeviceLoggerState") + + +@_attrs_define +class DeviceLoggerState: + """ + Attributes: + last_reported_block (Union[Unset, int]): Last reported block number + last_reported_time (Union[Unset, datetime.datetime]): Last time logger state was reported + last_downloaded_block (Union[Unset, int]): Last downloaded block number + last_downloaded_wrap_count (Union[Unset, int]): Last downloaded block wrap count + last_downloaded_time (Union[Unset, datetime.datetime]): Last time logger state was downloaded + """ + + last_reported_block: Union[Unset, int] = UNSET + last_reported_time: Union[Unset, datetime.datetime] = UNSET + last_downloaded_block: Union[Unset, int] = UNSET + last_downloaded_wrap_count: Union[Unset, int] = UNSET + last_downloaded_time: Union[Unset, datetime.datetime] = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + last_reported_block = self.last_reported_block + + last_reported_time: Union[Unset, str] = UNSET + if not isinstance(self.last_reported_time, Unset): + last_reported_time = self.last_reported_time.isoformat() + + last_downloaded_block = self.last_downloaded_block + + last_downloaded_wrap_count = self.last_downloaded_wrap_count + + last_downloaded_time: Union[Unset, str] = UNSET + if not isinstance(self.last_downloaded_time, Unset): + last_downloaded_time = self.last_downloaded_time.isoformat() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if last_reported_block is not UNSET: + field_dict["lastReportedBlock"] = last_reported_block + if last_reported_time is not UNSET: + field_dict["lastReportedTime"] = last_reported_time + if last_downloaded_block is not UNSET: + field_dict["lastDownloadedBlock"] = last_downloaded_block + if last_downloaded_wrap_count is not UNSET: + field_dict["lastDownloadedWrapCount"] = last_downloaded_wrap_count + if last_downloaded_time is not UNSET: + field_dict["lastDownloadedTime"] = last_downloaded_time + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + last_reported_block = d.pop("lastReportedBlock", UNSET) + + _last_reported_time = d.pop("lastReportedTime", UNSET) + last_reported_time: Union[Unset, datetime.datetime] + if isinstance(_last_reported_time, Unset): + last_reported_time = UNSET + else: + last_reported_time = isoparse(_last_reported_time) + + last_downloaded_block = d.pop("lastDownloadedBlock", UNSET) + + last_downloaded_wrap_count = d.pop("lastDownloadedWrapCount", UNSET) + + _last_downloaded_time = d.pop("lastDownloadedTime", UNSET) + last_downloaded_time: Union[Unset, datetime.datetime] + if isinstance(_last_downloaded_time, Unset): + last_downloaded_time = UNSET + else: + last_downloaded_time = isoparse(_last_downloaded_time) + + device_logger_state = cls( + last_reported_block=last_reported_block, + last_reported_time=last_reported_time, + last_downloaded_block=last_downloaded_block, + last_downloaded_wrap_count=last_downloaded_wrap_count, + last_downloaded_time=last_downloaded_time, + ) + + device_logger_state.additional_properties = d + return device_logger_state + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/infuse_iot/api_client/models/downlink_route.py b/src/infuse_iot/api_client/models/downlink_route.py index b4a3a9c..53487a4 100644 --- a/src/infuse_iot/api_client/models/downlink_route.py +++ b/src/infuse_iot/api_client/models/downlink_route.py @@ -8,6 +8,8 @@ from ..types import UNSET, Unset if TYPE_CHECKING: + from ..models.bt_le_route import BtLeRoute + from ..models.forwarded_downlink_route import ForwardedDownlinkRoute from ..models.interface_data import InterfaceData from ..models.udp_downlink_route import UdpDownlinkRoute @@ -22,11 +24,19 @@ class DownlinkRoute: interface (RouteType): Interface of route interface_data (InterfaceData): udp (Union[Unset, UdpDownlinkRoute]): + bt_adv (Union[Unset, BtLeRoute]): + bt_peripheral (Union[Unset, BtLeRoute]): + bt_central (Union[Unset, BtLeRoute]): + forwarded (Union[Unset, ForwardedDownlinkRoute]): """ interface: RouteType interface_data: "InterfaceData" udp: Union[Unset, "UdpDownlinkRoute"] = UNSET + bt_adv: Union[Unset, "BtLeRoute"] = UNSET + bt_peripheral: Union[Unset, "BtLeRoute"] = UNSET + bt_central: Union[Unset, "BtLeRoute"] = UNSET + forwarded: Union[Unset, "ForwardedDownlinkRoute"] = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: @@ -38,6 +48,22 @@ def to_dict(self) -> dict[str, Any]: if not isinstance(self.udp, Unset): udp = self.udp.to_dict() + bt_adv: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.bt_adv, Unset): + bt_adv = self.bt_adv.to_dict() + + bt_peripheral: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.bt_peripheral, Unset): + bt_peripheral = self.bt_peripheral.to_dict() + + bt_central: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.bt_central, Unset): + bt_central = self.bt_central.to_dict() + + forwarded: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.forwarded, Unset): + forwarded = self.forwarded.to_dict() + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( @@ -48,11 +74,21 @@ def to_dict(self) -> dict[str, Any]: ) if udp is not UNSET: field_dict["udp"] = udp + if bt_adv is not UNSET: + field_dict["btAdv"] = bt_adv + if bt_peripheral is not UNSET: + field_dict["btPeripheral"] = bt_peripheral + if bt_central is not UNSET: + field_dict["btCentral"] = bt_central + if forwarded is not UNSET: + field_dict["forwarded"] = forwarded return field_dict @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.bt_le_route import BtLeRoute + from ..models.forwarded_downlink_route import ForwardedDownlinkRoute from ..models.interface_data import InterfaceData from ..models.udp_downlink_route import UdpDownlinkRoute @@ -68,10 +104,42 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: else: udp = UdpDownlinkRoute.from_dict(_udp) + _bt_adv = d.pop("btAdv", UNSET) + bt_adv: Union[Unset, BtLeRoute] + if isinstance(_bt_adv, Unset): + bt_adv = UNSET + else: + bt_adv = BtLeRoute.from_dict(_bt_adv) + + _bt_peripheral = d.pop("btPeripheral", UNSET) + bt_peripheral: Union[Unset, BtLeRoute] + if isinstance(_bt_peripheral, Unset): + bt_peripheral = UNSET + else: + bt_peripheral = BtLeRoute.from_dict(_bt_peripheral) + + _bt_central = d.pop("btCentral", UNSET) + bt_central: Union[Unset, BtLeRoute] + if isinstance(_bt_central, Unset): + bt_central = UNSET + else: + bt_central = BtLeRoute.from_dict(_bt_central) + + _forwarded = d.pop("forwarded", UNSET) + forwarded: Union[Unset, ForwardedDownlinkRoute] + if isinstance(_forwarded, Unset): + forwarded = UNSET + else: + forwarded = ForwardedDownlinkRoute.from_dict(_forwarded) + downlink_route = cls( interface=interface, interface_data=interface_data, udp=udp, + bt_adv=bt_adv, + bt_peripheral=bt_peripheral, + bt_central=bt_central, + forwarded=forwarded, ) downlink_route.additional_properties = d diff --git a/src/infuse_iot/api_client/models/forwarded_downlink_route.py b/src/infuse_iot/api_client/models/forwarded_downlink_route.py new file mode 100644 index 0000000..033b121 --- /dev/null +++ b/src/infuse_iot/api_client/models/forwarded_downlink_route.py @@ -0,0 +1,81 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.downlink_route import DownlinkRoute + + +T = TypeVar("T", bound="ForwardedDownlinkRoute") + + +@_attrs_define +class ForwardedDownlinkRoute: + """ + Attributes: + device_id (str): The ID of the forwarding device as a hex string Example: d291d4d66bf0a955. + route (DownlinkRoute): + auth (int): Auth level for the forwarding device packet + """ + + device_id: str + route: "DownlinkRoute" + auth: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + device_id = self.device_id + + route = self.route.to_dict() + + auth = self.auth + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "deviceId": device_id, + "route": route, + "auth": auth, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.downlink_route import DownlinkRoute + + d = dict(src_dict) + device_id = d.pop("deviceId") + + route = DownlinkRoute.from_dict(d.pop("route")) + + auth = d.pop("auth") + + forwarded_downlink_route = cls( + device_id=device_id, + route=route, + auth=auth, + ) + + forwarded_downlink_route.additional_properties = d + return forwarded_downlink_route + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/infuse_iot/api_client/models/forwarded_uplink_route.py b/src/infuse_iot/api_client/models/forwarded_uplink_route.py new file mode 100644 index 0000000..cebda74 --- /dev/null +++ b/src/infuse_iot/api_client/models/forwarded_uplink_route.py @@ -0,0 +1,89 @@ +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.uplink_route import UplinkRoute + + +T = TypeVar("T", bound="ForwardedUplinkRoute") + + +@_attrs_define +class ForwardedUplinkRoute: + """ + Attributes: + device_id (str): The ID of the forwarding device as a hex string Example: d291d4d66bf0a955. + route (UplinkRoute): + auth (int): Auth level for the forwarding device packet + rssi (int): RSSI of the packet + """ + + device_id: str + route: "UplinkRoute" + auth: int + rssi: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + device_id = self.device_id + + route = self.route.to_dict() + + auth = self.auth + + rssi = self.rssi + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "deviceId": device_id, + "route": route, + "auth": auth, + "rssi": rssi, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.uplink_route import UplinkRoute + + d = dict(src_dict) + device_id = d.pop("deviceId") + + route = UplinkRoute.from_dict(d.pop("route")) + + auth = d.pop("auth") + + rssi = d.pop("rssi") + + forwarded_uplink_route = cls( + device_id=device_id, + route=route, + auth=auth, + rssi=rssi, + ) + + forwarded_uplink_route.additional_properties = d + return forwarded_uplink_route + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/infuse_iot/api_client/models/key_interface.py b/src/infuse_iot/api_client/models/key_interface.py new file mode 100644 index 0000000..d83a4da --- /dev/null +++ b/src/infuse_iot/api_client/models/key_interface.py @@ -0,0 +1,11 @@ +from enum import Enum + + +class KeyInterface(str, Enum): + BT_ADV = "bt_adv" + BT_GATT = "bt_gatt" + SERIAL = "serial" + UDP = "udp" + + def __str__(self) -> str: + return str(self.value) diff --git a/src/infuse_iot/api_client/models/new_rpc_req.py b/src/infuse_iot/api_client/models/new_rpc_req.py index dbe9d95..7bd9efd 100644 --- a/src/infuse_iot/api_client/models/new_rpc_req.py +++ b/src/infuse_iot/api_client/models/new_rpc_req.py @@ -8,6 +8,7 @@ if TYPE_CHECKING: from ..models.rpc_params import RPCParams + from ..models.rpc_req_data_header import RPCReqDataHeader T = TypeVar("T", bound="NewRPCReq") @@ -23,11 +24,15 @@ class NewRPCReq: params (Union[Unset, RPCParams]): RPC request or response params (must be a JSON object with string or embedded json values - numbers sent as decimal strings) Example: {'primitive_vaue': '1000', 'struct_value': {'field': 'value'}}. + params_encoded (Union[Unset, str]): Base64 encoded params (if provided, will be used instead of params) + data_header (Union[Unset, RPCReqDataHeader]): """ command_id: Union[Unset, int] = UNSET command_name: Union[Unset, str] = UNSET params: Union[Unset, "RPCParams"] = UNSET + params_encoded: Union[Unset, str] = UNSET + data_header: Union[Unset, "RPCReqDataHeader"] = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: @@ -39,6 +44,12 @@ def to_dict(self) -> dict[str, Any]: if not isinstance(self.params, Unset): params = self.params.to_dict() + params_encoded = self.params_encoded + + data_header: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data_header, Unset): + data_header = self.data_header.to_dict() + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update({}) @@ -48,12 +59,17 @@ def to_dict(self) -> dict[str, Any]: field_dict["commandName"] = command_name if params is not UNSET: field_dict["params"] = params + if params_encoded is not UNSET: + field_dict["paramsEncoded"] = params_encoded + if data_header is not UNSET: + field_dict["dataHeader"] = data_header return field_dict @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: from ..models.rpc_params import RPCParams + from ..models.rpc_req_data_header import RPCReqDataHeader d = dict(src_dict) command_id = d.pop("commandId", UNSET) @@ -67,10 +83,21 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: else: params = RPCParams.from_dict(_params) + params_encoded = d.pop("paramsEncoded", UNSET) + + _data_header = d.pop("dataHeader", UNSET) + data_header: Union[Unset, RPCReqDataHeader] + if isinstance(_data_header, Unset): + data_header = UNSET + else: + data_header = RPCReqDataHeader.from_dict(_data_header) + new_rpc_req = cls( command_id=command_id, command_name=command_name, params=params, + params_encoded=params_encoded, + data_header=data_header, ) new_rpc_req.additional_properties = d diff --git a/src/infuse_iot/api_client/models/route_type.py b/src/infuse_iot/api_client/models/route_type.py index af7db05..26e019f 100644 --- a/src/infuse_iot/api_client/models/route_type.py +++ b/src/infuse_iot/api_client/models/route_type.py @@ -2,7 +2,13 @@ class RouteType(str, Enum): + BT_ADV = "bt_adv" + BT_CENTRAL = "bt_central" + BT_PERIPHERAL = "bt_peripheral" + HCI = "hci" + SERIAL = "serial" UDP = "udp" + UNKNOWN = "unknown" def __str__(self) -> str: return str(self.value) diff --git a/src/infuse_iot/api_client/models/rpc_req.py b/src/infuse_iot/api_client/models/rpc_req.py index 6d49853..a677d0a 100644 --- a/src/infuse_iot/api_client/models/rpc_req.py +++ b/src/infuse_iot/api_client/models/rpc_req.py @@ -9,6 +9,7 @@ if TYPE_CHECKING: from ..models.downlink_route import DownlinkRoute from ..models.rpc_params import RPCParams + from ..models.rpc_req_data_header import RPCReqDataHeader T = TypeVar("T", bound="RpcReq") @@ -23,12 +24,16 @@ class RpcReq: params (Union[Unset, RPCParams]): RPC request or response params (must be a JSON object with string or embedded json values - numbers sent as decimal strings) Example: {'primitive_vaue': '1000', 'struct_value': {'field': 'value'}}. + params_encoded (Union[Unset, str]): Base64 encoded params (if provided, will be used instead of params) + data_header (Union[Unset, RPCReqDataHeader]): route (Union[Unset, DownlinkRoute]): """ request_id: int command_id: int params: Union[Unset, "RPCParams"] = UNSET + params_encoded: Union[Unset, str] = UNSET + data_header: Union[Unset, "RPCReqDataHeader"] = UNSET route: Union[Unset, "DownlinkRoute"] = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) @@ -41,6 +46,12 @@ def to_dict(self) -> dict[str, Any]: if not isinstance(self.params, Unset): params = self.params.to_dict() + params_encoded = self.params_encoded + + data_header: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.data_header, Unset): + data_header = self.data_header.to_dict() + route: Union[Unset, dict[str, Any]] = UNSET if not isinstance(self.route, Unset): route = self.route.to_dict() @@ -55,6 +66,10 @@ def to_dict(self) -> dict[str, Any]: ) if params is not UNSET: field_dict["params"] = params + if params_encoded is not UNSET: + field_dict["paramsEncoded"] = params_encoded + if data_header is not UNSET: + field_dict["dataHeader"] = data_header if route is not UNSET: field_dict["route"] = route @@ -64,6 +79,7 @@ def to_dict(self) -> dict[str, Any]: def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: from ..models.downlink_route import DownlinkRoute from ..models.rpc_params import RPCParams + from ..models.rpc_req_data_header import RPCReqDataHeader d = dict(src_dict) request_id = d.pop("requestId") @@ -77,6 +93,15 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: else: params = RPCParams.from_dict(_params) + params_encoded = d.pop("paramsEncoded", UNSET) + + _data_header = d.pop("dataHeader", UNSET) + data_header: Union[Unset, RPCReqDataHeader] + if isinstance(_data_header, Unset): + data_header = UNSET + else: + data_header = RPCReqDataHeader.from_dict(_data_header) + _route = d.pop("route", UNSET) route: Union[Unset, DownlinkRoute] if isinstance(_route, Unset): @@ -88,6 +113,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: request_id=request_id, command_id=command_id, params=params, + params_encoded=params_encoded, + data_header=data_header, route=route, ) diff --git a/src/infuse_iot/api_client/models/rpc_req_data_header.py b/src/infuse_iot/api_client/models/rpc_req_data_header.py new file mode 100644 index 0000000..c134e1f --- /dev/null +++ b/src/infuse_iot/api_client/models/rpc_req_data_header.py @@ -0,0 +1,67 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="RPCReqDataHeader") + + +@_attrs_define +class RPCReqDataHeader: + """ + Attributes: + size (int): Amount of data expected + rx_ack_period (int): Send an ACK every N packets received Default: 0. + """ + + size: int + rx_ack_period: int = 0 + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + size = self.size + + rx_ack_period = self.rx_ack_period + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "size": size, + "rxAckPeriod": rx_ack_period, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + size = d.pop("size") + + rx_ack_period = d.pop("rxAckPeriod") + + rpc_req_data_header = cls( + size=size, + rx_ack_period=rx_ack_period, + ) + + rpc_req_data_header.additional_properties = d + return rpc_req_data_header + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/infuse_iot/api_client/models/rpc_rsp.py b/src/infuse_iot/api_client/models/rpc_rsp.py index ba8f387..e139cec 100644 --- a/src/infuse_iot/api_client/models/rpc_rsp.py +++ b/src/infuse_iot/api_client/models/rpc_rsp.py @@ -23,11 +23,14 @@ class RpcRsp: params (Union[Unset, RPCParams]): RPC request or response params (must be a JSON object with string or embedded json values - numbers sent as decimal strings) Example: {'primitive_vaue': '1000', 'struct_value': {'field': 'value'}}. + params_encoded (Union[Unset, str]): Base64 encoded params (provided if there was an issue decoding the RPC + params) """ route: "UplinkRoute" return_code: int params: Union[Unset, "RPCParams"] = UNSET + params_encoded: Union[Unset, str] = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: @@ -39,6 +42,8 @@ def to_dict(self) -> dict[str, Any]: if not isinstance(self.params, Unset): params = self.params.to_dict() + params_encoded = self.params_encoded + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( @@ -49,6 +54,8 @@ def to_dict(self) -> dict[str, Any]: ) if params is not UNSET: field_dict["params"] = params + if params_encoded is not UNSET: + field_dict["paramsEncoded"] = params_encoded return field_dict @@ -69,10 +76,13 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: else: params = RPCParams.from_dict(_params) + params_encoded = d.pop("paramsEncoded", UNSET) + rpc_rsp = cls( route=route, return_code=return_code, params=params, + params_encoded=params_encoded, ) rpc_rsp.additional_properties = d diff --git a/src/infuse_iot/api_client/models/security_state.py b/src/infuse_iot/api_client/models/security_state.py new file mode 100644 index 0000000..8348f79 --- /dev/null +++ b/src/infuse_iot/api_client/models/security_state.py @@ -0,0 +1,99 @@ +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="SecurityState") + + +@_attrs_define +class SecurityState: + """ + Attributes: + cloud_public_key (str): Cloud public ECC key as a base64 encoded string + device_public_key (str): Device public ECC key as a base64 encoded string + network_id (int): Current network ID + challenge (str): Challenge used in request as a base64 encoded string + challenge_response_type (int): Type of the challenge response + challenge_response (str): Challenge response as a base64 encoded string + """ + + cloud_public_key: str + device_public_key: str + network_id: int + challenge: str + challenge_response_type: int + challenge_response: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + cloud_public_key = self.cloud_public_key + + device_public_key = self.device_public_key + + network_id = self.network_id + + challenge = self.challenge + + challenge_response_type = self.challenge_response_type + + challenge_response = self.challenge_response + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "cloudPublicKey": cloud_public_key, + "devicePublicKey": device_public_key, + "networkId": network_id, + "challenge": challenge, + "challengeResponseType": challenge_response_type, + "challengeResponse": challenge_response, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + cloud_public_key = d.pop("cloudPublicKey") + + device_public_key = d.pop("devicePublicKey") + + network_id = d.pop("networkId") + + challenge = d.pop("challenge") + + challenge_response_type = d.pop("challengeResponseType") + + challenge_response = d.pop("challengeResponse") + + security_state = cls( + cloud_public_key=cloud_public_key, + device_public_key=device_public_key, + network_id=network_id, + challenge=challenge, + challenge_response_type=challenge_response_type, + challenge_response=challenge_response, + ) + + security_state.additional_properties = d + return security_state + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/src/infuse_iot/api_client/models/uplink_route.py b/src/infuse_iot/api_client/models/uplink_route.py index d07785a..4b66857 100644 --- a/src/infuse_iot/api_client/models/uplink_route.py +++ b/src/infuse_iot/api_client/models/uplink_route.py @@ -8,6 +8,8 @@ from ..types import UNSET, Unset if TYPE_CHECKING: + from ..models.bt_le_route import BtLeRoute + from ..models.forwarded_uplink_route import ForwardedUplinkRoute from ..models.interface_data import InterfaceData from ..models.udp_uplink_route import UdpUplinkRoute @@ -22,11 +24,19 @@ class UplinkRoute: interface (RouteType): Interface of route interface_data (InterfaceData): udp (Union[Unset, UdpUplinkRoute]): + bt_adv (Union[Unset, BtLeRoute]): + bt_peripheral (Union[Unset, BtLeRoute]): + bt_central (Union[Unset, BtLeRoute]): + forwarded (Union[Unset, ForwardedUplinkRoute]): """ interface: RouteType interface_data: "InterfaceData" udp: Union[Unset, "UdpUplinkRoute"] = UNSET + bt_adv: Union[Unset, "BtLeRoute"] = UNSET + bt_peripheral: Union[Unset, "BtLeRoute"] = UNSET + bt_central: Union[Unset, "BtLeRoute"] = UNSET + forwarded: Union[Unset, "ForwardedUplinkRoute"] = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: @@ -38,6 +48,22 @@ def to_dict(self) -> dict[str, Any]: if not isinstance(self.udp, Unset): udp = self.udp.to_dict() + bt_adv: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.bt_adv, Unset): + bt_adv = self.bt_adv.to_dict() + + bt_peripheral: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.bt_peripheral, Unset): + bt_peripheral = self.bt_peripheral.to_dict() + + bt_central: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.bt_central, Unset): + bt_central = self.bt_central.to_dict() + + forwarded: Union[Unset, dict[str, Any]] = UNSET + if not isinstance(self.forwarded, Unset): + forwarded = self.forwarded.to_dict() + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( @@ -48,11 +74,21 @@ def to_dict(self) -> dict[str, Any]: ) if udp is not UNSET: field_dict["udp"] = udp + if bt_adv is not UNSET: + field_dict["btAdv"] = bt_adv + if bt_peripheral is not UNSET: + field_dict["btPeripheral"] = bt_peripheral + if bt_central is not UNSET: + field_dict["btCentral"] = bt_central + if forwarded is not UNSET: + field_dict["forwarded"] = forwarded return field_dict @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.bt_le_route import BtLeRoute + from ..models.forwarded_uplink_route import ForwardedUplinkRoute from ..models.interface_data import InterfaceData from ..models.udp_uplink_route import UdpUplinkRoute @@ -68,10 +104,42 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: else: udp = UdpUplinkRoute.from_dict(_udp) + _bt_adv = d.pop("btAdv", UNSET) + bt_adv: Union[Unset, BtLeRoute] + if isinstance(_bt_adv, Unset): + bt_adv = UNSET + else: + bt_adv = BtLeRoute.from_dict(_bt_adv) + + _bt_peripheral = d.pop("btPeripheral", UNSET) + bt_peripheral: Union[Unset, BtLeRoute] + if isinstance(_bt_peripheral, Unset): + bt_peripheral = UNSET + else: + bt_peripheral = BtLeRoute.from_dict(_bt_peripheral) + + _bt_central = d.pop("btCentral", UNSET) + bt_central: Union[Unset, BtLeRoute] + if isinstance(_bt_central, Unset): + bt_central = UNSET + else: + bt_central = BtLeRoute.from_dict(_bt_central) + + _forwarded = d.pop("forwarded", UNSET) + forwarded: Union[Unset, ForwardedUplinkRoute] + if isinstance(_forwarded, Unset): + forwarded = UNSET + else: + forwarded = ForwardedUplinkRoute.from_dict(_forwarded) + uplink_route = cls( interface=interface, interface_data=interface_data, udp=udp, + bt_adv=bt_adv, + bt_peripheral=bt_peripheral, + bt_central=bt_central, + forwarded=forwarded, ) uplink_route.additional_properties = d