From 1535b96e792d07311420b0ee3f061fc38f4610a4 Mon Sep 17 00:00:00 2001 From: impressionyang Date: Fri, 17 Apr 2026 11:03:50 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20HCI=20=E5=91=BD=E4=BB=A4?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=92=8C=E6=89=AB=E6=8F=8F=E5=89=8D=E5=AF=86?= =?UTF-8?q?=E9=92=A5=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - hci_gateway.py: 修复 build_hci_command 始终包含长度字段 - hci_gateway.py: 增加响应解析的详细日志 - provisioning.py: start_scanning 先配置网络密钥和应用密钥 - 解决网关无响应问题,命令格式现在符合 E9 FF OPCODE LEN 规范 Co-Authored-By: Claude Opus 4.6 --- .../sigmesh_gateway/hci_gateway.py | 34 ++++++++++++++----- .../sigmesh_gateway/provisioning.py | 21 +++++++++++- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/custom_components/sigmesh_gateway/hci_gateway.py b/custom_components/sigmesh_gateway/hci_gateway.py index 1c7b7be..d9149bd 100644 --- a/custom_components/sigmesh_gateway/hci_gateway.py +++ b/custom_components/sigmesh_gateway/hci_gateway.py @@ -45,15 +45,15 @@ HCI_MESH_PREFIX = b"\xe8\xff" # Mesh 数据命令头 def build_hci_command(opcode: int, payload: bytes = b"") -> bytes: """构建 HCI 命令包。 - 根据 danglo 工具日志,格式:E9 FF [OPCODE(1)] - 对于简单命令(无 payload),只有 3 字节。 + 格式:E9 FF [OPCODE(1)] [LEN(1)] [PAYLOAD...] + 长度字段始终存在,即使为 0。 """ - # 简单格式:E9 FF OPCODE - cmd = HCI_CMD_PREFIX + bytes([opcode & 0xFF]) + # E9 FF OPCODE LEN + cmd = HCI_CMD_PREFIX + bytes([opcode & 0xFF, len(payload)]) - # 如果有 payload,添加长度和数据 + # 如果有 payload,添加数据 if payload: - cmd += bytes([len(payload)]) + payload + cmd += payload return cmd @@ -138,6 +138,8 @@ class HciGateway: opcode = self._buffer[1] length = self._buffer[2] + _LOGGER.info("收到 91 响应头:opcode=0x%02X, length=%d", opcode, length) + if len(self._buffer) < 3 + length: _LOGGER.debug("数据不完整:需要 %d 字节,当前 %d 字节", 3 + length, len(self._buffer)) break # 数据不完整,等待更多 @@ -148,7 +150,11 @@ class HciGateway: # 唤醒等待的 future if opcode in self._response_futures: + _LOGGER.info("找到匹配的 future,唤醒等待的命令 0x%02X", opcode) self._response_futures[opcode].set_result(payload) + else: + _LOGGER.warning("未找到匹配的 future (opcode=0x%02X),已发送的命令有:%s", + opcode, list(self._response_futures.keys())) self._buffer.clear() return @@ -161,6 +167,8 @@ class HciGateway: opcode = self._buffer[2] length = self._buffer[3] + _LOGGER.info("收到 E8 事件头:opcode=0x%02X, length=%d", opcode, length) + if len(self._buffer) < 4 + length: _LOGGER.debug("事件数据不完整:需要 %d 字节,当前 %d 字节", 4 + length, len(self._buffer)) break # 数据不完整 @@ -173,8 +181,9 @@ class HciGateway: self._handle_event(event_data) else: - # 未知数据,清空 - _LOGGER.warning("未知 HCI 数据头:0x%02X,清空缓冲区", self._buffer[0]) + # 未知数据,打印警告并清空 + _LOGGER.warning("未知 HCI 数据头:0x%02X,缓冲区前 20 字节:%s", + self._buffer[0], self._buffer[:20].hex().upper()) self._buffer.clear() return @@ -279,3 +288,12 @@ class HciGateway: response = await self.send_command(HciGatewayOp.CFG_APPKEY, appkey) return response is not None + + async def reset_gateway(self) -> bool: + """复位网关。 + + Returns: + True 表示成功,False 表示失败 + """ + response = await self.send_command(HciGatewayOp.GATEWAY_RESET) + return response is not None diff --git a/custom_components/sigmesh_gateway/provisioning.py b/custom_components/sigmesh_gateway/provisioning.py index cf2b682..2f39e9f 100644 --- a/custom_components/sigmesh_gateway/provisioning.py +++ b/custom_components/sigmesh_gateway/provisioning.py @@ -154,11 +154,30 @@ class ProvisioningManager: self._set_state(ProvState.PROV_FAILED) return + # 1. 先配置网关密钥(如果未配置) + try: + _LOGGER.info("正在配置网关密钥...") + netkey_bytes = bytes.fromhex(self.network_key) + appkey_bytes = bytes.fromhex(self.app_key) + + # 配置网络密钥 + netkey_result = await self.serial_reader.hci.configure_netkey(netkey_bytes) + _LOGGER.info("网络密钥配置结果:%s", "成功" if netkey_result else "失败") + + # 配置应用密钥 + appkey_result = await self.serial_reader.hci.configure_appkey(appkey_bytes) + _LOGGER.info("应用密钥配置结果:%s", "成功" if appkey_result else "失败") + + # 等待网关处理 + await asyncio.sleep(0.5) + except Exception as e: + _LOGGER.error("配置网关密钥失败:%s", e) + self._set_state(ProvState.SCANNING) self._devices = {} self._scan_result = [] - # 使用 HCI 协议发送扫描命令 + # 2. 使用 HCI 协议发送扫描命令 try: _LOGGER.debug("发送 HCI 扫描命令") result = await self.serial_reader.hci.start_scanning()