通过RPC使用Bluetooth低功耗(BLE)与Shelly设备通信
%20Using%20RPC.png?inst-v=8eb5b645-f616-454e-a1eb-47030b06b1ec)
概述
Bluetooth低功耗(BLE)已成为现代智能设备无线通信的核心技术,提供高效且低功耗的连接。Shelly设备作为智能家居生态系统的重要组成部分,利用BLE实现无缝通信与控制。Shelly的BLE通信的一个关键方面是通过BLE实现远程过程调用(RPC)协议,使设备与控制器之间能够进行复杂的交互。本文将深入探讨使用BLE与Shelly设备通信的技术细节,重点介绍通用属性配置文件(GATT)、句柄以及基于RPC的读写操作机制。
先决条件
在深入探讨通过 BLE 和 RPC 与 Shelly 设备通信的技术细节之前,首先需要对以下概念有基本的了解:
Bluetooth低功耗(BLE): 一种为低功耗和低成本设计的无线个人区域网络技术。BLE被广泛应用于物联网设备,实现高效通信。
通用属性配置文件 (GATT): 一种BLE协议,定义了设备间数据的结构和交换方式。GATT将数据组织为服务和特征。
远程过程调用 (RPC): 一种协议,允许程序像本地调用一样在远程设备上执行过程(子程序)。
JSON: 一种用于构建RPC请求和响应的轻量级数据交换格式。
Shelly 的 BLE RPC 架构
通过 BLE 和 RPC 与 Shelly 设备通信涉及到建立连接、与特定 GATT 服务和特征交互、构建并发送 RPC 请求、接收和解析响应的无缝集成。这个统一的工作流程确保了与 Shelly 设备的高效可靠通信,使其能够在不同系统和编程语言之间实现多样化集成。
Shelly 设备中的关键 GATT 组件
Shelly GATT 服务 UUID: 标识负责RPC通信的主服务。
SHELLY_GATT_SERVICE_UUID = "5f6d4f53-5f52-5043-5f53-56435f49445f" RPC数据特征UUID: 处理RPC请求和响应数据的传输。
RPC_CHAR_DATA_UUID = "5f6d4f53-5f52-5043-5f64-6174615f5f5f" RPC发送控制特征UUID: 管理传输控制,特别是用于向 Shelly 设备发送数据长度信息。
RPC_CHAR_TX_CTL_UUID = "5f6d4f53-5f52-5043-5f74-785f63746c5f" RPC接收控制特征UUID: 处理接收控制,主要用于从 Shelly 设备接收数据长度信息。
RPC_CHAR_RX_CTL_UUID = "5f6d4f53-5f52-5043-5f72-785f63746c5f" 注意:这些 UUID 是 Shelly 设备专用的,请参考 Shelly 官方文档或使用 BLE 扫描工具以识别相应的 UUID。
Shelly 的 BLE 上 RPC 关键要素
JSON-RPC 2.0 协议
Shelly 的 Gen2+ 设备使用 JSON-RPC 2.0 用于监控和控制功能的协议。该协议是对称的,允许双方——客户端和设备——互相调用方法并发送通知。JSON-RPC 2.0 确保了结构化和标准化的通信,促进了客户端应用与 Shelly 设备之间的可靠交互。
命名空间约定
Shelly 将其 RPC 方法组织在 命名空间 用于分类功能,提升清晰度和可维护性。以下是一些主要命名空间及示例方法:
-
Shelly 命名空间: 处理系统管理、配置和状态。
Shelly.FactoryReset
Shelly.ResetWiFiConfig
Shelly.ListTimezones
-
开关命名空间: 管理离散电源输出,通常是继电器。
Switch.Set
Switch.GetConfig
注意:上述命名空间和方法仅为示例。Shelly 的 RPC 实现还包含许多其他命名空间下的丰富方法,以支持多样化的设备功能。
帧类型
用户与设备之间的通信由三种类型的帧组成:
请求帧: 用于向设备发送命令。
响应帧: 用于接收设备的回复。
通知帧: 用于接收设备的非请求更新。
Shelly RPC 协议中的帧结构
请求帧
请求帧是一个用于在 Shelly 设备上调用方法的 JSON 对象。它包含以下属性:
jsonrpc (字符串):指定使用的JSON-RPC版本,通常为"2.0"。此字段可省略。
id (数字或字符串):请求的标识符,用于匹配响应帧。必需。
src (字符串):请求来源的名称(例如"user_1")。必需。
method(字符串):要调用的过程名称(例如:"Shelly.GetDeviceInfo")。必需。
params (对象):方法所需的参数(例如{"id":1})。可选。
响应帧
响应帧是 Shelly 设备针对请求帧返回的 JSON 对象。它包含以下属性:
id (数字或字符串):通信的标识符。必需。
src(字符串):响应来源的名称(通常为 Shelly 设备)。必需。
dst (字符串):目标名称(通常是请求者)。必需。
result (对象):如果请求成功,调用过程的结果。与error字段互斥。
error (对象):如果请求失败,包含错误描述。与result字段互斥。
通知帧
通知帧是 Shelly 设备发送给客户端,用于通知某些事件或状态变化且不期望响应的 JSON 对象。它包含以下属性:
src(字符串):通知来源的名称(例如 Shelly 设备)。必需。
dst (字符串):目标名称(例如"user_1")。必需。
method (字符串):调用的方法(例如"NotifyStatus")。必需。
params (对象):包含相关数据的通知参数。必需。
与 Shelly 设备通信的分步指南
1. 建立BLE连接
目标: 使用 Shelly 设备的唯一 BLE 地址进行连接。
流程:
设备发现: 首先扫描附近的 BLE 设备以识别 Shelly 设备。这可以通过你所选编程环境中的 BLE 扫描工具或库实现。Shelly 设备可通过其名称或 BLE 地址识别。
发起连接: 识别后,使用其 BLE 地址发起与 Shelly 设备的连接。该连接为后续所有交互奠定基础。请确保系统的 BLE 硬件正常,且 Shelly 设备处于可接受连接的状态。
注意事项:
连接超时: BLE连接有时不稳定或耗时较长。应实现超时机制,处理连接尝试超过合理时间的情况。
重连逻辑: 在意外断开时,重连策略确保应用能自动恢复,无需手动干预。
2. 交互GATT服务和特征
目标: 访问并使用RPC通信所需的特定GATT服务和特征。
流程:
服务发现: 连接后,执行服务发现以获取 Shelly 设备提供的可用 GATT 服务列表。通过其预定义的 UUID 定位 Shelly GATT 服务。
特征发现: 在 Shelly GATT 服务中,通过各自的 UUID 确认 RPC Data、RPC TX Control 和 RPC RX Control 特征。这些特征对于发送 RPC 请求和接收响应至关重要。请参考 Shelly 设备中的关键 GATT 组件.
注意事项:
UUID准确性: 确保使用正确的UUID,避免通信错误。错误的UUID会导致读取或写入失败。
特征可用性: 某些 Shelly 设备可能因型号或固件版本不同而存在 GATT 配置差异。请实现检查以确认所有所需特征均已存在后再继续操作。
3. 构建RPC请求
目标: 按正确格式创建 RPC 请求,以实现与 Shelly 设备的期望操作。
流程:
JSON结构: RPC请求结构为包含特定字段的JSON对象:
id:请求的唯一标识符,确保响应能够与各自的请求相关联。
src: 来源标识,如“user_1”,表示请求的起点。
method:要调用的 RPC 方法,例如 “Shelly.GetDeviceInfo”。
params: RPC方法所需的可选参数。
{ "id": 123456789, "src": "user_1", "method": "Shelly.GetDeviceInfo", "params": {} } 编码: 将JSON对象转换为UTF-8编码的字节数组。该字节数组将通过 BLE 发送到 Shelly 设备。
计算长度: 确定编码RPC请求的字节长度。该长度信息对于告知 Shelly 设备即将接收数据的大小至关重要。
打包长度: 将计算的长度转换为4字节大端整数。此打包长度写入RPC发送控制特征以指示即将传输的数据大小。
注意事项:
唯一请求ID: 每个RPC请求应有唯一id,以准确匹配响应。
参数验证: 请确保传递给 RPC 方法的参数有效且符合预期格式。无效参数可能导致请求格式错误并引发 Shelly 设备的错误。
4. 发送RPC请求
目标: 通过 BLE 将构建好的 RPC 请求发送给 Shelly 设备。
流程:
写入长度到发送控制特征: 首先将RPC请求的打包长度写入RPC发送控制特征。这会告知 Shelly 设备即将接收数据的大小,使其准备好接收实际的 RPC 请求。
引入短暂延迟: 写入长度后,等待短暂延迟(例如1秒) 以便 Shelly 设备处理长度信息。这样可确保在发送实际数据前,客户端与设备之间的同步。
写入RPC请求到数据特征: 接着将编码的RPC请求字节写入RPC数据特征。此操作将实际命令或查询发送至 Shelly 设备,促使其执行指定的 RPC 方法。
注意事项:
带响应的写操作: 使用期望 Shelly 设备响应(确认)的写操作。这可确保设备已成功接收并处理写入请求。
错误处理: 实现确认写操作成功的机制。处理写入失败的情况,如连接问题或设备无响应,通过重试或提示用户。
5. 接收和解析RPC响应
目标: 接收来自 Shelly 设备的响应,确保数据完整性和正确性。
流程:
从接收控制特征读取响应长度: 首先从RPC接收控制特征读取响应长度。该长度指示即将接收的响应数据大小,帮助客户端确定预期字节数。
解包长度: 将接收到的4字节大端整数转换为实际字节长度。此解包长度决定需读取的响应数据总大小。
分块读取响应数据: 由于BLE的MTU(最大传输单元)限制,从RPC数据特征分块读取响应数据(通常为20字节)。持续读取直到接收完整响应(由响应长度指示)。
累积响应数据: 每读取一块,将其追加到缓冲区或字节数组中,重建完整响应。
解码并解析响应: 全部块接收完毕后,将累积字节解码为UTF-8字符串并解析JSON对象。解析后的响应包含RPC调用结果或错误字段。
验证响应: 确认响应中的id与原请求id匹配,确保响应对应正确请求。同时检查result字段确认成功执行,或处理错误信息。
注意事项:
分块读取: BLE有限的MTU大小要求分块读取数据,避免截断或丢失。实现逻辑处理部分读取并累积数据,直到完整响应接收完毕。
超时: 实现读取超时机制,以防 Shelly 设备未响应或连接中断时出现无限等待。
数据完整性: 验证完整响应已接收并正确解析,确保通信准确可靠。
常见挑战处理
通过 BLE 和 RPC 与 Shelly 设备通信是一种强大的方式,但也存在一些挑战。有效应对这些挑战可确保集成的健壮性和可靠性。
MTU大小管理
问题: BLE的最大传输单元(MTU)定义单次传输的数据包最大尺寸。超出MTU会导致数据截断或传输失败。
解决方案:
分块读写: 实现逻辑将大数据负载拆分为符合MTU大小(通常20字节)的小块,确保数据可靠传输且不超出BLE限制。
示例方法:
确定待发送数据总长度。
将数据分割为不超过20字节的块。
依次写入每个块到相应特征。
动态MTU调整: 部分BLE库和设备支持协商更大MTU。若支持,可调整MTU以优化传输效率。
示例考虑:
在开始传输前,如库和设备支持,申请更大MTU。
协商失败时回退至标准块大小。
最佳实践:
确定MTU能力: 验证 Shelly 设备和 BLE 客户端是否都支持更大的 MTU,以最大化数据吞吐量。
实现回退机制: 动态MTU协商失败时,默认使用标准块大小以保持兼容性。
超时与重试
问题: BLE连接可能不稳定,导致超时或通信中断,尤其在干扰多或多设备连接环境中。
解决方案:
实现超时机制: 为连接尝试、读写操作和数据处理设置合理超时,防止应用无限等待响应。
示例方法:
定义各操作最大等待时间。
操作超时后,优雅处理,重试或通知用户。
重试逻辑: 针对临时失败(如连接断开或写入失败)实现重试机制。限制重试次数,避免无限循环和资源浪费。
示例方法:
失败后等待短暂时间再重试。
采用指数退避策略,逐渐延长重试间隔。
最佳实践:
指数退避: 逐步增加重试间隔,减少重复失败概率,尤其在高干扰环境。
用户通知: 在重试耗尽后通知用户,便于手动干预。
错误处理
问题: BLE通信中可能出现特征不可用、响应格式错误或RPC特定错误等多种问题。
解决方案:
全面异常处理: 在通信各阶段实现健壮的错误捕获机制,包括处理BLE异常、JSON解析错误和RPC相关问题。
示例方法:
关键操作使用try-catch块包裹。
记录详细错误信息,便于调试和问题解决。
验证检查: 彻底验证响应数据完整性,包括匹配响应ID与请求ID,确认存在预期字段如result或error。
示例方法:
接收响应后,检查id是否匹配原请求。
确保响应包含result字段或error字段以判断结果。
最佳实践:
日志记录: 维护详细通信日志,记录尝试、成功和失败,有助于排查和理解系统行为。
优雅降级: 对非关键错误,允许系统继续运行,优雅处理失败,避免崩溃或影响其他操作。
结论
通过 BLE 和 RPC 与 Shelly 设备通信,为打造先进的智能家居集成和自动化解决方案提供了强大途径。通过理解 BLE 架构、GATT 服务和 RPC 机制,开发者可以根据自身需求构建健壮高效的通信框架。本指南为建立无缝通信提供了详细路线图,助你充分发挥 Shelly 智能功能在各类编程语言和平台上的潜力。
我们重视您的反馈!
感谢您花时间阅读我们的文章!内容是否对您有帮助或有趣?
您的见解能帮助我们改进。若方便,
请通过以下邮箱与我们分享您的反馈: