From e7d55a07d42d72cf283e77e728db8e11cea7dcd8 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 30 Jul 2026 15:53:36 +1000 Subject: [PATCH 1/3] tools: gateway: internal consistency fix Use the response bytes object directly in a callback, instead of manually reconstructing it from a different argument. Signed-off-by: Jordan Yates --- src/infuse_iot/tools/gateway.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/infuse_iot/tools/gateway.py b/src/infuse_iot/tools/gateway.py index 5600f30..309aa75 100644 --- a/src/infuse_iot/tools/gateway.py +++ b/src/infuse_iot/tools/gateway.py @@ -21,7 +21,7 @@ import infuse_iot.definitions.rpc as defs import infuse_iot.definitions.tdf as tdf_defs import infuse_iot.epacket.interface as interface -from infuse_iot import rpc, tdf +from infuse_iot import tdf from infuse_iot.commands import InfuseCommand from infuse_iot.common import InfuseID, InfuseType from infuse_iot.database import ( @@ -295,8 +295,8 @@ def _pub_keys_cb(self, pkt: PacketReceived, rc: int, response: bytes, _): # Notify connection success self._connected_notification(infuse_id) - def _bt_connect_cb(self, pkt: PacketReceived, rc: int, response: bytes, _): - resp = defs.bt_connect_infuse.response.from_buffer_copy(pkt.payload[ctypes.sizeof(rpc.ResponseHeader) :]) + def _bt_connect_cb(self, _pkt: PacketReceived, rc: int, response: bytes, _): + resp = defs.bt_connect_infuse.response.from_buffer_copy(response) if_addr = interface.Address.BluetoothLeAddr.from_rpc_struct(resp.peer) infuse_id = self._common.ddb.infuse_id_from_bluetooth(if_addr) From 408782da31e8d250002d68693d8e165054144e64 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 30 Jul 2026 15:56:15 +1000 Subject: [PATCH 2/3] tools: ota_upgrade: set times on connections Ensure that the local gateways and remote devices have synchronised times before starting the upgrade process. This ensures time isn't wasted by regenerating interface keys on each packet. Signed-off-by: Jordan Yates --- src/infuse_iot/tools/ota_upgrade.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/infuse_iot/tools/ota_upgrade.py b/src/infuse_iot/tools/ota_upgrade.py index ebed674..bd8cf46 100644 --- a/src/infuse_iot/tools/ota_upgrade.py +++ b/src/infuse_iot/tools/ota_upgrade.py @@ -21,7 +21,7 @@ from infuse_iot.commands import InfuseCommand from infuse_iot.common import InfuseID -from infuse_iot.definitions.rpc import bt_file_copy_basic, file_write_basic, rpc_enum_file_action +from infuse_iot.definitions.rpc import bt_file_copy_basic, file_write_basic, rpc_enum_file_action, time_set from infuse_iot.epacket.packet import Auth, HopReceived from infuse_iot.generated.tdf_definitions import readings from infuse_iot.rpc_client import RpcClient @@ -29,6 +29,7 @@ GatewayRequestConnectionRequest, LocalClient, ) +from infuse_iot.time import InfuseTime from infuse_iot.util.argparse import InfuseDeviceId, ValidFile, ValidRelease, add_server_port_parser from infuse_iot.util.crc import crc16_ccitt from infuse_iot.zephyr.errno import errno @@ -163,6 +164,20 @@ def gateway_diff_load(self): sys.exit(f"Failed to save diff file to gateway (({errno.strerror(-return_code)}))") print(f"'{self._single_diff}' written to gateway") + def set_device_time(self, mtu: int, infuse_id: int) -> bool: + rpc_client = RpcClient(self._client, mtu, infuse_id) + rpc_client.set_timeout(2.0) + + params = time_set.request(InfuseTime.epoch_time_from_unix(time.time())) + hdr, _rsp = rpc_client.run_standard_cmd( + time_set.COMMAND_ID, + Auth.DEVICE, + bytes(params), + time_set.response.from_buffer_copy, + ) + # Command completed and succeeded + return hdr is not None and hdr.return_code == 0 + def run_file_upload(self, live: Live, mtu: int, source: HopReceived): self.state_update(live, f"Uploading patch file to {source.infuse_id:016X}") rpc_client = RpcClient(self._client, mtu, source.infuse_id) @@ -215,6 +230,11 @@ def run(self): if self._single_diff: self.gateway_diff_load() + # Set the gateways time at script startup + with self._client.connection(InfuseID.GATEWAY, GatewayRequestConnectionRequest.DataType.COMMAND, 10) as mtu: + if not self.set_device_time(mtu, InfuseID.GATEWAY): + sys.exit("Failed to set time on local gateway") + with Live(self.progress_table(), refresh_per_second=4) as live: for source, announce in self._client.observe_announce(): self.state_update(live, "Scanning") @@ -302,6 +322,9 @@ def run(self): with self._client.connection( source.infuse_id, GatewayRequestConnectionRequest.DataType.COMMAND, self._conn_timeout ) as mtu: + # Set time on the remote device to keep keys in sync + if not self.set_device_time(mtu, source.infuse_id): + break if self._single_diff: self.run_file_copy(live, mtu, source) else: From b0d1481b97966e91c6e3a03b13ccaec3c1effdd8 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 30 Jul 2026 15:57:31 +1000 Subject: [PATCH 3/3] tools: ota_upgrade: increase copy timeout Unlike `run_file_upload`, the client timeout associated with `run_file_copy` needs to be large enough to contain the entire copy process, as the local gateway manages the copy itself. Signed-off-by: Jordan Yates --- src/infuse_iot/tools/ota_upgrade.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/infuse_iot/tools/ota_upgrade.py b/src/infuse_iot/tools/ota_upgrade.py index bd8cf46..02d7108 100644 --- a/src/infuse_iot/tools/ota_upgrade.py +++ b/src/infuse_iot/tools/ota_upgrade.py @@ -201,6 +201,7 @@ def run_file_upload(self, live: Live, mtu: int, source: HopReceived): def run_file_copy(self, live: Live, mtu: int, source: HopReceived): self.state_update(live, f"Copying patch file to {source.infuse_id:016X}") rpc_client = RpcClient(self._client, mtu, InfuseID.GATEWAY) + rpc_client.set_timeout(60.0) params = bt_file_copy_basic.request( source.interface_address.val.to_rpc_struct(),