手机让设备“向前移动一步”,等待结果时连接断了。界面出现重试按钮,用户再点一次,设备会走一步,还是两步?
问题在于,手机没收到结果,并不能证明设备没执行。这篇超维方程技术笔记讨论业务指令的重试,不涉及某款设备的实测。
图:超维方程技术团队绘制。写入确认、动作完成和重启后核对是不同环节,不能只靠重发请求获得确定结果。
先区分写入确认和动作完成
Bluetooth 的 ATT 规范里,写请求的响应确认的是属性写入;无响应写入则没有对应的写响应。[1] 如果你的业务把“收到某个属性值”解释为启动一个耗时动作,还需要另外定义动作完成的反馈。
例如,消息可以依次经历“已接收”“已接受”“执行中”“已完成”。不是所有产品都需要这四个状态,但界面不能把第一个状态直接显示成最后一个。
收到写响应,也不代表执行机构已经到位。这里要等什么结果,应由业务协议决定。
能表达目标状态,就少表达相对动作
“把亮度设为 40%”与“亮度增加 10%”有不同的重试语义。前者重复处理,目标值仍是 40%;后者重复处理,结果会继续变化。
这不意味着所有指令都能改成目标状态。移动、投料或触发一次采样等动作,仍可能需要单独识别每次请求。
可以为一次业务动作分配 request_id。重发时沿用同一个标识,设备在约定范围内识别重复请求,并返回之前的结果或当前进度。新动作才使用新标识。
| 收到的请求 | 一种可评审的处理方式 |
|---|---|
| 新标识、新动作 | 校验参数与权限后,接受执行 |
| 相同标识、相同参数,仍在执行 | 返回执行中,不再次启动 |
| 相同标识、相同参数,已经完成 | 返回已保存的结果 |
| 相同标识、不同参数 | 拒绝冲突,要求调用方核查 |
这张表是应用层设计建议,不是 BLE 协议自动提供的保证。
去重记录也有生命周期
仅在内存里保存最近几个标识,设备重启后就可能忘记。若断电发生在动作完成之后、结果保存之前,下一次重试仍有歧义。
对于不可逆动作,需要结合持久化记录、动作执行顺序、位置或状态传感器,设计重启后的核对过程。只加一个请求编号,不能宣称实现了跨断电的“恰好执行一次”。
还要确定标识作用域和保留时间。不同控制端、不同设备和新的会话之间,应避免把无关动作误判为重复。过期请求是否允许再次执行,也要写进协议。
测试应包含“执行了,但没回信”
正常收发只能验证最顺利的路径。更有价值的测试是:动作已经开始,结果返回前断连;动作完成后重发;相同标识携带不同参数;设备重启后再收到旧请求。
观察实际动作次数,不能只看手机日志打印了几次“成功”。涉及运动或其他不可逆动作时,先在仿真或无负载测试设备上验证。
对用户而言,超时后的正确提示有时是“结果尚未确认,正在查询设备状态”,而不是立即邀请他再执行一次。
参考:Bluetooth Core Specification:Attribute Protocol。[1]
作者:超维方程技术团队。