更新日期:2026-04-24(v4.2 第二轮回复后更新)| 基于 v4.1(Kevin 本地)+ v4 QsEdited(Liang 已回复)合并整理
本版本把 Liang 对 v4.0 的回复(QsEdited,2026-04-24)整合进 v4.1(Kevin 本地,2026-04-23),以便一次看完当前协议理解全貌。标记约定:💬;✅ = 已确认;🟡 = 部分回复,等待 Kevin / Beta 后续动作;⏳ = 长期待定。截至本次更新,没有项目单纯阻塞在 Liang 身上。
v4 → v4.1 增量(新问题、数据点、开发者模式、v4.1 补充章节)全部保留。
v4 QsEdited 里 Liang 的 11 处回复已按章节放入原文。
由 Liang 回复引出的实现细节(例:后台 4 小时降级、Android 返回提示、Cooking 界面文案、退避节奏调整)已写入正文。
v4.1 新出的问题(蓝针字节冲突、iOS 权限、27 秒断线、字节 6/7-8 数据点)清楚标注为「尚未发给 Liang」。
✅ 入仓后中继盒自动关机:定时器固件硬编码、不可通过 BLE 配置、不可延长禁用。0x55AA 到 0x07 每机型固定,1 秒内算正常;关机后用户重开会自动再广播。
✅ 12B 与 15B 的 MAC 字节序确实反向——有意设计,为中继盒固件代码方便。
✅ App 在前台时维持 15 秒扫描节奏(一直扫描)。
✅ 刚进入后台 → 行为与前台一致;连续 4 小时无连接后才降级为真正的后台模式。
✅ 蓝针设置命令字节 = 0x55B2(+ 探针地址)。Beta 先前回复 0x55B1 与锁刷新冲突,Liang 确认正确值为 0x55B2。
✅ 探针无休眠/唤醒协议——探针是实时设备,取出即持续发信号。无数据到达时只有 4 种可能(详见第一章末尾)。
✅ 12B 字节 6(报警状态 01→00)可作为静音命令 ack 信号——Liang 批准作为协议规范,因为有客诉反映中继盒报警声太吵。
✅ 12B 字节 7-8(F/C):v4.2 时非权威(App 用字节 4-5),但 V5 2026-05-07 起改为以字节 7/8 为权威——Liang 确认。
Kevin 下一步要做的事(🟡 阻塞在我们自己):
🟡 待 Kevin 回复: #17 — iOS 权限静默失效:Liang 初判一般系统行为,需 Kevin 构建带 log 的 iOS app 交 Liang 进一步诊断。
🟡 待 Kevin 回复: #18 — 27 秒断线:Liang 认可 45s 锁刷新做法,反问「心跳」指 12B 还是 15B 数据包。Kevin 需回复澄清。
长期待定(⏳ 无人阻塞,待机会):
⏳ #10 — CM4 设置目标温度——调用点未接线 + Fahrenheit > 99°F 边界。格式已知(
cm4_protocol.dart:159已实现CM4Command.configureProbe:SET_<probe>=A<unit><temp><meat><doneness>),但全代码库零调用点(cooking_page._pushTargetToDevice:761对 CM4 早返)。temp 槽两位数边界待 Liang 澄清。
AE03 —— App 发送命令给中继盒的通道(write / writeWithoutResponse)
AE05 —— 中继盒发送数据给 App 的通道(indicate 通知方式)
这是理解整个协议最关键的一点。0x55B1 不是心跳包,是独占锁命令。功能是防止多台手机同时控制同一台中继盒。
假设 A 和 B 两台手机附近都有同一台中继盒:
Step 1 — A 先连上并锁定:
A 手机扫描到中继盒广播 → BLE 连接
A 发送 0x55B1 → 中继盒锁定到 A
中继盒停止广播(B 手机扫描不到)
Step 2 — A 维持锁:
A 每 45 秒刷新一次 0x55B1(协议规定 60 秒内发一次,留 15 秒 margin)
锁的 TTL 是 60 秒
中继盒只给 A 推送 12B 设置响应和 15B 探针温度数据
Step 3 — A 停止刷新锁(闪退 / App 被杀 / 后台限制 BLE):
60 秒 TTL 到期,中继盒释放独占
中继盒重新开始广播
A 和 B 的扫描列表里都能看到中继盒
必须发 0x55B1:否则 60 秒后锁释放,用户的探针可能被其他手机抢走。
后台也要发:需要 Android 前台服务 / iOS bluetooth-central background mode。
间隔:固定 45 秒(规则定死,不再改动)。
根据参考设备实测,中继盒会通过 AE05 通道推送以下几种数据包:
中继盒每 3 秒自动推送一次(也响应 App 的 0x55AE 查询)。
实测样本:09 28 01 78 01 01 c3 5b ad dc 2f 0a
| 字节位 | 含义 | 说明 |
|---|---|---|
| 1 | 中继盒电量 | 原始值 × 10 = 百分比。例:0x09 → 90% |
| 2 | 中继盒固件版本 | 十六进制转十进制,显示 V{十进制}。例:0x28 → V40 |
| 3 | 中继盒当前显示单位 | 00=华氏 / 01=摄氏。App 忽略此字节,使用 App 自己的单位设置 |
| 4-5 | 报警目标温度 ADC | 小端(字节5高位,字节4低位)。例:0x78 0x01 → 0x0178 → 查内部NTC表 → 91°C / 195°F |
| 6 | 报警状态 | 00=未启用报警 / 01=已启用报警(静态配置标志,非瞬态“正在报警”指示;用户在设备上静音会禁用该设置从而回到00) |
| 7 | 华氏度报警参考值 | 中继盒预转换的华氏值(仅参考,例:0xC3 → 195°F) |
| 8 | 摄氏度报警参考值 | 中继盒预转换的摄氏值(仅参考,例:0x5B → 91°C) |
| 9-12 | 压缩 4 字节探针地址 | 这 4 字节是完整 6 字节 MAC 反转后取中间 4 字节。还原规则详见第三章字节序。 |
作用:
这个包同时承担了心跳和状态同步的双重作用。每 3 秒一次告诉 App:'我在,这是当前目标温度和报警状态'。
App 发送 0x55AD(静音)后,下一个 12B 包的字节 6 应该从 0x01 → 0x00。App 用这个作为命令确认信号,5 秒内无确认自动重试一次。
✅ Liang 批准此用法作为协议规范。
💬 可以考虑。因为有客诉认为中继盒一直在叫太吵了。
字节 7(°F)和字节 8(°C)是中继盒给出的报警目标字面值。V5 2026-05-07 起以此为权威:°F 模式下取字节 7(携带用户输入的整数 °F,未被固件内部 °C 量化破坏),°C 模式下取字节 8(按 useCelsius 选择)。字节 4-5 的 ADC + tempIntArray 往返已弃用——固件把 °F 输入量化成整数 °C 会丢精度(120°F→118°F bug,Liang 2026-05-07),现仅留作 dev log。代码见 booster_message.dart 的 alarmTempF/alarmTempC(权威)与 alarmTempRaw(已弃用)。
✅ Liang 确认(v4.2)App 只使用字节 4-5。⚠️ 已被 V5 2026-05-07 推翻——现以字节 7/8 为权威(见上)。
💬 确认用 4-5 字节。
探针活跃时中继盒推送(大约每 3-6 秒一次,跟随探针读数变化)。
实测样本:09 28 04 a5 06 af 09 88 ad dc 2f 32 0a 50 ad
| 字节位 | 含义 | 说明 |
|---|---|---|
| 1 | 中继盒电量 | 同 12 字节包,例:0x09 → 90% |
| 2 | 中继盒固件版本 | 同 12 字节包,例:0x28 → V40 |
| 3-4 | 探针内部温度 ADC | 大端(字节3高位,字节4低位),查 tempIntArray 反查温度。例:0x04A5 → 27°C |
| 5-6 | 探针环境温度 ADC | 大端(字节5高位,字节6低位),查 tempExtArray 反查温度。例:0x06AF → 28°C |
| 7 | 探针电量 | 原始值 × 10 = 百分比 |
| 8 | 探针固件版本 | 十六进制转十进制,显示 V{十进制}。例:0x88 → V136 |
| 9-14 | 完整 6 字节探针地址 | 线上原始顺序(on-wire reversed)。例:AD DC 2F 32 0A 50 → 反转得 MAC 50 0A 32 2F DC AD |
| 15 | RSSI 信号强度 | 有符号字节(0xD8 → -40 dBm,0xF3 → -13 dBm) |
线上原始字节:AD DC 2F 32 0A 50
反转后完整 MAC:50 0A 32 2F DC AD
MAC 位置 0 固定 0x50,位置 2 固定 0x32
MAC 位置 1 是颜色字节(v2 已确认,详见颜色映射表)
三种格式(根据中继盒型号不同):
2 字节(MW2 老款):55 AA — 全局入仓信号
3 字节(早期版本):55 AA XX
8 字节(CM1/CM2/CM3/MW3 新款):55 AA + 6 字节探针地址
8 字节例子:55 AA 2B 45 2F 32 0A 50
App 用 6 字节 MAC 匹配是哪根针入仓了,设置对应探针的 isDocked=true。
8 字节形式:按 MAC 匹配具体哪根针入仓
2/3 字节形式:如果字节 3 是有效探针标识符 → 标记对应探针 inactive;否则 → 仅记录 unknown slot,不生成探针状态更新。
在 2026-04-21 的实测中我们发现了关键现象:
0x55AA 到达 App 后,大约 70 毫秒内,中继盒会发送 BLE 断开 0x07(错误码 UNKNOWN)
紧接着中继盒 LED 熄灭,自动关机
这个关机行为是中继盒固件主动做的,不是 App 触发的
App 无法通过任何命令阻止这个自动关机
💬 收到 0x07 即表示中继盒已经关机了。
App 端的对应处理详见第九章「入仓后的自动关机行为」。
App 前台,有保存的设备(无论此时设备在线或离线)→ 按当前接收/发送策略继续尝试连接,即使设备发送了 0x55AA + 蓝牙地址。
App 后台,有保存的设备(无论此时设备在线或离线)→ 按当前接收/发送策略继续尝试连接,即使设备发送了 0x55AA + 蓝牙地址。
App 完全退出 → 完全退出,不占用手机系统资源,不占用手机蓝牙资源。
💬 探针由用户使用完、入仓后,App 列表界面对应 Booster 显示为灰色未连接状态——0423 版本已经显示正常。
温度探针是实时设备,没有休眠/唤醒协议——只要探针取出,中继盒就会持续发送 12B/15B 数据。因此 App 若收不到数据,必然是以下 4 种情形之一:
探针入仓,中继盒关机
中继盒没电自动关机
用户手动给中继盒关机
中继盒与手机断连
💬 不存在(休眠/唤醒协议)。温度探针是实时设备,只要探针取出,中继盒就会一直发信号。没收到信号时即是上述 4 种情况之一。
✅ 据此,App 设计中无须实现「探针唤醒」命令或轮询逻辑——数据缺失即进入重连/重扫流程。
55 AE 00 00
中继盒收到后立即回复一个 12 字节设置响应。注意:中继盒每 3 秒也会自动推送这个 12 字节包,所以 App 主动查询并非必须。
格式:0x55 [颜色命令字节] [单位] [温度字节] [6字节探针地址线上顺序]
| 字节位 | 含义 | 值 |
|---|---|---|
| 1 | 固定开头 | 0x55 |
| 2 | 颜色命令字节 | AF=黑针 / B0=白针 / B2=蓝针 |
| 3 | 单位 | 00=华氏 / 01=摄氏 |
| 4 | 温度值 | 直接查表 / 十进制转十六进制:171°F → 0xAB;77°C → 0x4D |
| 5-10 | 探针地址 | 6 字节线上顺序(和15字节包的字节 9-14 一样) |
例子 — 设置白针(MAC: 50 0D 32 2F 45 A4)为华氏 171°F:
55 B0 00 AB A4 45 2F 32 0D 50
【附加效果】 App 发送此命令后,中继盒的物理显示屏温度单位会同步切换到命令里的单位。
Beta 2026-04-17 曾回复 0x55B1,但 0x55B1 是锁刷新命令,会产生冲突(App 发心跳会被误认为设置蓝针目标温度)。v4.1 时我们的代码已用 0x55B2。Liang 在第二轮回复中正式确认:
💬 0x55B2 XX XX + 针地址。
✅ 蓝针设置命令字节 = 0x55B2。现有代码无需修改;以 Liang 的回复为准,覆盖 Beta 2026-04-17 的 0x55B1 回复。
| 颜色字节 | 探针类型 | 使用命令字节 |
|---|---|---|
| 0x0A | 黑针(长款) | 0x55AF |
| 0x0B | 黑针(短款) | 0x55AF |
| 0x0D | 白针 | 0x55B0 |
| 0x0E | 蓝针 | 0x55B2 |
0x0A = 黑针长款。0x0A 和 0x0B 都是黑针,只是长短不同,使用相同的命令字节 0x55AF。
55 AB 00 00 —— 设置为华氏
55 AB 00 01 —— 设置为摄氏
切换中继盒物理显示屏单位。
55 AD 00 00
停止中继盒蜂鸣器。下一个 12 字节响应里字节 6(报警状态)应该从 01→00 作为确认。
55 B1
作用:刷新 App 对中继盒的独占锁。详见本文档开头的锁机制章节。
间隔:固定 45 秒。协议规范 60 秒 TTL,45 秒给 15 秒 margin 应对偶发延迟。规则定死,不再改动。
当没有探针活跃时,中继盒每 3 秒会推送一个 2 字节包(电量 + 版本)。这不是命令,App 只是被动接收。我们已处理,不会报 unhandled 错误。
2026-04-21 的实测中我们发现了一个一直存在的 Bug:12B 和 15B 两个包的 MAC 字节顺序是反的!
详细情况:
15B 包的字节 9-14 是探针 MAC 的线上顺序(on-wire),这是反转的字节顺序:AD DC 2F 32 0A 50
12B 包的字节 9-12 是压缩后的 4 字节(去掉了固定的 0x50 和 0x32),需要还原出正向 MAC:50 0A 32 2F DC AD
v2 的代码里两个 MAC 的对比用了一样的字节序,所以从来没匹配成功,每次 12B 到达都会打出 SETTINGS_MAC_MISMATCH 警告
v4 已修复:比对时把 15B 的 rawAddressBytes 反转再比对
| 数据位置 | 字节序 |
|---|---|
| 15 字节包的内部温度 ADC(字节3-4) | 大端(high byte first) |
| 15 字节包的环境温度 ADC(字节5-6) | 大端(high byte first) |
| 12 字节包的报警目标 ADC(字节4-5) | 小端(low byte first)⚠️ 不一样! |
| 15 字节包的探针地址(字节9-14) | 线上反向顺序(on-wire reversed) |
| 12 字节包的压缩地址(字节9-12) | 还原后是正向 MAC,和 15B 的反向是相反的 |
| 设置目标温度命令里的探针地址 | 线上反向顺序(和 15B 一致) |
12B 重构出的完整 MAC 应该等于 15B 字节 9-14 反转后的 MAC。App 在每次收到 12B 时做这个对比,不一致时打 WARNING 日志。这是我们发现本章 MAC 字节序 bug 的关键手段,建议保留。
✅ 12B 和 15B 的 MAC 字节序确实是相反的。
💬 12B、15B 的数据长度是故意做区分两个不同类型,MAC 反转是中继盒固件代码上的方便。
程序使用数组:0°C 到 120°C(121 条记录)
[0] = 0x601,[120] = 0xCD
显示:0°C 以下显示 "LO";102°C–120°C 显示 "HI";超过 120°C 时硬钳制到 120°C
程序使用数组:0°C 到 274°C(275 条记录)
[0] = 0x6EF,[274] = 0x3B
显示:40°C 以下显示 "---";超过 274°C 时钳制显示在 274°C
探针入仓(收到 0x55AA)→ 直接显示灰色 + '已入仓'
不能显示 '重新连接中...'
不能显示加载动画
理由:探针入仓是用户主动操作,不是断线
【背景】 v2 旧规则已过时。原本规则 2 说 "真实断线 60 秒内不提示",但 v4 测试发现入仓引发的断线不应该进入 60 秒宽限期。
v4 新规则 —— 断线分类处理:
入仓引发的断线(0x55AA 后 1 秒内收到 0x07):跳过宽限期,进入 "正在关机中" 过渡状态(详见规则 5)
其他断线(没有近期 0x55AA 的 0x07,或 BLE 超时):前 90 秒 App 后台静默重连,UI 继续显示最后一次的温度数据
90 秒后仍未重连成功:才显示 '已断开'
App 怎么判断是入仓引发的断线?
在 AE05 的 RX 层检测到 [0x55, 0xAA] 开头的数据包时,立即给该设备打一个时间戳(_lastDockEventAt)。
收到 0x07 断开事件后,检查这个时间戳:如果在 1 秒内,就分类为 "入仓引发的关机",否则按 90 秒宽限期处理。
断线宽限期内(90 秒静默重连)不触发阈值报警
避免用缓存数据误报警(例:'牛排熟了!'但实际探针已断)
低电量报警例外:是持久状态,不受宽限期影响
用户主动点 '断开' → 立即显示已断开,不启动 60 秒计时
用户意图明确,不要掩盖
【背景】 入仓后中继盒会自动关机,但关机前有几秒延迟。如果直接把 UI 从 "已连接" 跳到 "已关机",用户看到的是一瞬间的闪烁。
v4 新规则 —— 入仓后的三态过渡:
t=0:收到 0x55AA,探针卡片立即变灰并显示 "已入仓"
t=0+70ms:收到 0x07 断开,中继盒卡片进入 "正在关机..." 过渡状态(灰色,但文字不同)
t=5s 到 t=10s:用户看到过渡状态,有时间理解发生了什么
t=10s:中继盒卡片变成 "已关机"
如果这 10 秒内中继盒意外重连(极少见),取消过渡计时器,保持连接状态
【背景】 v2 的阈值是 10 秒。在 2026-04-21 的实测中发现 15B 包到达间隔可能到 12-15 秒,导致探针卡片误闪烁成灰色。
旧阈值:10 秒(v2)
新阈值:20 秒(v4)
理由:正常情况下 15B 包每 3-6 秒一次,但偶尔会间隔到 12+ 秒,这不算真正的 dropout
20 秒给足够的缓冲,真正的断连(比如探针真的坏了或太远)仍然会被检测到
App 内置开发者模式,Liang 测试时可以用来导出完整协议日志给我们分析。
进入方式:
设备列表页面 3 秒内连续点击 "CulinaTech" 标题 5 次
进入后可见三个 tab:ALL / RX / TX
每条协议包带解码注释(例:0x55B1 → "legacy HEARTBEAT CLR_CNT")
导出文件名:culinatech_log_{时间戳}.txt(例:culinatech_log_20260423153012.txt)
建议 Liang 测试时:
连接中继盒 → 操作一段时间 → 进入开发者模式 → 导出 → 发给我们
有这个日志我们可以直接 grep 所有协议事件,比凭记忆还原问题高效得多
Android 在列表界面按 Return 键时,必须弹出提示:
【提示文案】 "If you wish to close the app, your phone will stop monitoring the temperature and you will no longer receive any alarms."
当中继盒处于未连接状态(入仓引发关机 / 电池耗尽 / 手动关机)时:
列表界面:探针 + Booster 都显示灰色
Cooking 界面:显示 "Booster box not connected to smartphone"
App 在前台时,重连扫描按 15 秒节奏执行
如果扫到的设备在已保存列表里(known devices)→ 自动连接
连接成功后立即发 0x55B1 锁定中继盒
原 v4.1 规则:App 进后台即停止主动扫描。
v4.2 修订规则:
刚进入后台 → 行为与前台一致(继续主动扫描)
进入后台 4 小时后 → 重连退避改为阶梯模式(1-5 次 15 秒 / 6-30 次 60 秒 / 31 次后 5 分钟);0x55B1 仍每 45 秒发一次
💬 刚进入后台,后台行为和前台行为保持一致。补充需求:app 在后台连续 4 小时无连接,转为后台模式(不主动扫描,只监听断开事件,锁刷新 45 秒一次)。
【背景】 v2 的重连扫描一次只扫描一个目标设备。如果用户有多台中继盒都断了,扫描会轮流找 A、B、C。结果:即使广播中的 B 在扫描 A 的窗口里出现,也会被忽略。
v4 新逻辑:
每次扫描构建一个完整的 "目标设备集合"(所有断开但保留的 known devices)
扫描一次,匹配任何一个目标设备都算成功
日志会打出 "scanning for N device(s): deviceA, deviceB, ..."
这样不管广播的是 A 还是 B,第一次出现就能被发现
【背景】 v2 的重连退避是全局的:如果设备 A 连续失败 5 次,整个重连循环会放慢到 60 秒间隔,即使设备 B 刚刚断开也要等 60 秒。
v4.2 退避表:
| 阶段 | 节奏 | 适用场景 |
|---|---|---|
| 第 1-5 次尝试 | 每 15 秒一次 | App 在前台 → 必须一直保持此节奏连续扫描 |
| 第 6-30 次尝试 | 每 60 秒一次 | App 在后台 → 中继盒可能关机了,省电(v4.2 第二轮收紧 6-15 → 6-30) |
| 第 31 次以后 | 每 5 分钟一次 | App 在后台 → 长期失败,保留连接意图但不浪费电(v4.2 第二轮收紧 16+ → 31+) |
每个设备独立计数,互不影响
连接成功后计数器清零
用户主动 "忘记设备" 后该设备的计数器被清除
💬 app 在前台时,1-5 次尝试阶段必须一直保持该节奏扫描;后两段(60 秒、5 分钟)仅适用于 app 在后台。
虽然中继盒关机了,但用户可能随时按电源键重开
App 后台安静地继续扫描(按退避节奏)
用户重开中继盒 → 中继盒重新广播 → App 下次扫描窗口命中 → 自动重连
在设备卡片上长按 → 弹出确认对话框 → 确认后:
从 known devices 存储里删除
从重连队列里删除
清除所有相关的状态(失败计数、过渡计时器、入仓时间戳等)
停止所有针对该设备的扫描和重连尝试
日志打出 DEVICE_FORGOTTEN 事件
iOS 下 BLE 需要三个权限同时生效:
Bluetooth
Location(iOS BLE 要求的,即使不用定位)
Background App Refresh
实测遇到的问题:客户首次安装后 BLE 正常,几天后连不上 —— 根因是 iOS 悄悄回收了其中一个权限(系统行为,不会通知用户)。当前解决方法:删除 App 重装。Android 无此问题。
💬 一般是系统行为。具体看是哪个权限——发个 app,开 log 的,我看看。
🟡 待 Kevin 回复: 下一步:Kevin 准备带 log 的 iOS 构建交给 Liang,Liang 进一步诊断是哪个权限被回收。
| 场景 | 行为 |
|---|---|
| A 手机锁定中继盒时,B 手机扫描 | 扫不到(中继盒完全停止广播) |
| A 手机持锁,正常刷新 45 秒一次 | B 手机永远看不到这个中继盒 |
| A 手机闪退 / App 被杀 | 中继盒不立刻释放锁,等 60 秒 TTL 到期后才释放 |
| 60 秒 TTL 到期后 | 中继盒重新开始广播,A 和 B 都能扫到 |
| B 先连上并发 0x55B1 | B 获得锁,A 再也连不上(除非 B 放手) |
| 用户主动在 App 里断开 | 只断 BLE 连接,不需要发任何释放锁命令 |
这是本次 v4 最重要的发现。Liang 已完整回复。
在 2026-04-21 的实测中我们多次观察到以下序列(iPhone + CM1_E4EF,实测日志时间戳):
13:05:15.408 #15 RX AE05 09 28 01 78 ... c3 5b ad dc 2f 0a (12B 设置响应)
13:05:15.409 #16 RX AE05 55 aa ad dc 2f 32 0a 50 (0x55AA 入仓通知)
13:05:15.473 BLE disconnected reason: UNKNOWN (0x07) (65ms 后断开)
... 几秒后 ...
中继盒 LED 熄灭,电源断开
每次都是一样的:0x55AA 到达后 65-72 毫秒内,中继盒发送 0x07 断开;再过几秒 LED 熄灭。
除了入仓触发的关机外,我们也观察到过 session uptime 大约 80 秒时的意外断线(非入仓场景)。这可能和第九章 #18 的 27 秒断线问题是同一个根因的不同表现形式。
入仓是一个完整的 "会话结束" 信号
中继盒固件把 0x55AA 当作 "用户做完菜了" 的信号
固件主动关闭 BLE 连接(0x07)来节省电力
然后延迟几秒后切断主电源(LED 熄灭)
💬 是的。
在 AE05 的 RX 层专门检测 [0x55, 0xAA] 开头的包
检测到即刻给该设备打时间戳 _lastDockEventAt = 现在时间
BLE 断开事件触发时,检查 _lastDockEventAt:如果在 1 秒内,分类为 DOCK_TRIGGERED_SHUTOFF
DOCK_TRIGGERED_SHUTOFF 路径:跳过 60 秒宽限期,进入 10 秒过渡状态("正在关机..."),然后变成 "已关机"
重连循环仍然保持(按退避节奏),用户重开中继盒后会自动连接
Q1. 这个自动关机定时器是固件硬编码还是可配置?
💬 固定。
Q2. 如果 BLE 连接还活跃(App 还在持锁),中继盒是否应该不关机?
💬 不是。中继盒是否关机取决于用户:用户把探针放回中继盒后,中继盒关机;或中继盒没电了自动关机。
Q3. 是否可以让 App 通过 BLE 命令告诉中继盒 "不要自动关机",用户按电源键再关?
💬 不可以。
Q4. 0x55AA 后到 0x07 的 70ms 延迟是固定的吗?是否和中继盒类型有关?
💬 每个机型是固定的;可能因为延时的原因,0x55AA 后到 0x07 在 1 秒内算正常。
Q5. 从关机恢复:用户重开中继盒后,中继盒会重新广播自己吗?(目前 App 假设是)
💬 是的,会。
与本章的入仓触发关机不同,v4.1 还记录了另一个现象:session uptime 约 27 秒时出现的意外断线(非入仓场景)。当前我们用 45s 的 0x55B1 锁刷新来绕过这个问题。Liang 对此的回复:
💬 45 秒锁刷新是正确做法。你说的心跳是指 12B 的数据包还是 15B 的数据包?
解读:Liang 认可了 45s 的做法,并要求我们澄清「心跳」指哪类数据包,以便进一步定位 27s 断线的根因。
🟡 待 Kevin 回复: 下一步:Kevin 回复 Liang,明确 27s 断线测量参照的是 12B 还是 15B 数据包间隔。
| # | 问题 | 状态 |
|---|---|---|
| 1 | 内温显示范围上限 120°C | ✅ 已确认(v2) |
| 2 | 探针颜色字节 0x0A = 黑针长款 | ✅ 已确认(v2) |
| 3 | 0x55B1 真实作用 = 独占锁 | ✅ 已确认(v2) |
| 4 | 12 字节 / 15 字节是不同的包 | ✅ 已确认(v2) |
| 5 | 断线重连机制正常 | ✅ 已确认(v2) |
| 6 | 锁刷新间隔 = 45 秒(定死) | ✅ 已确认(v2) |
| 7 | 手机 A 锁定时手机 B 能否扫到中继盒:不能 | ✅ 已确认(v2) |
| 8 | A 手机闪退后:等 60 秒 TTL 到期才释放锁 | ✅ 已确认(v2) |
| 9 | 用户主动断开:不用发释放锁命令 | ✅ 已确认(v2) |
| 10 | CM4 设置目标温度命令格式 | ⏳ 待确认(长期待定) |
| 11 | 入仓后中继盒自动关机的定时器:固件硬编码 | ✅ 已确认(v4.2 第一轮) |
| 12 | BLE 连接活跃时不自动关机:不行,关机仅由用户/电量触发 | ✅ 已确认(v4.2 第一轮) |
| 13 | 12B 和 15B 的 MAC 字节序反向:有意设计(固件便利) | ✅ 已确认(v4.2 第一轮) |
| 14 | 探针无休眠/唤醒协议;无数据时必为 4 种情形之一(入仓关机 / 没电 / 手动关机 / 断连) | ✅ 已确认(v4.2 第二轮) |
| 15 | 0x55AA 到 0x07 的延迟:每机型固定,1 秒内算正常 | ✅ 已确认(v4.2 第一轮) |
| 16 | 蓝针设置命令字节 = 0x55B2(+ 针地址)。覆盖 Beta 先前的 0x55B1 回复 | ✅ 已确认(v4.2 第二轮) |
| 17 | iOS permissions 悄悄失效:一般系统行为;需 Kevin 提供带 log 的 app 让 Liang 进一步诊断 | 🟡 部分回复(待 Kevin 发 log) |
| 18 | 27 秒断线根本原因;Liang 认可 45s 锁刷新做法,反问「心跳」指 12B 还是 15B | 🟡 部分回复(待 Kevin 澄清) |
| 19 | 12B 字节 6 作为静音命令 ack 信号—Liang 批准纳入协议规范(客诉反映中继盒太吵) | ✅ 已确认(v4.2 第二轮) |
| 20 | 12B 字节 7-8 是权威报警目标(V5 2026-05-07):°F 模式取字节 7、°C 模式取字节 8;字节 4-5 ADC 往返已弃用 | ✅ 已确认(v4.2 第二轮) |
构建一个带完整协议 log 输出的 iOS 测试 app,交给 Liang 诊断 iOS 权限回收问题(#17)。
回复 Liang:v4.1 记录的 27 秒断线测量基于 12B 数据包间隔 还是 15B 数据包间隔?(#18)
若走 #19 协议规范化方向,把「字节 6 = 静音命令 ack」写入对外协议文档;配合客诉改善中继盒报警声体验。
CM4 设置目标温度(#10)——格式已知(cm4_protocol.dart:159 的 configureProbe:SET_<probe>=A<unit><temp><meat><doneness>),但 cooking_page._pushTargetToDevice:761 对 CM4 早返,零调用点。Fahrenheit > 99°F 是 spec 边界缺口(temp 槽两位数),待 Liang 澄清。Transport-split 重构 C4 阶段一并接线。
最多同时连接 8 台设备(有客户实际买了 8 个 CM1 同时用)。App 架构已 refactor 为 Map<deviceId, DeviceConnection>,每个设备独立 BLE 连接、独立心跳、独立重连队列。
探针 UI Header 显示 <BoosterName> <Color> 格式(如 Liang V5 spec 2026-05-14 确认),用户可以看到颜色名。
固件版本显示为 V{十进制}(例:0x28 → V40)。
信号强度显示:≥ -40 dBm → 4 格,≥ -60 dBm → 3 格,< -60 dBm → 2 格。
内温显示范围:0°C-120°C。低于 0°C 显示 "LO",高于 120°C 显示 "HI"。
外温显示范围:40°C-274°C。低于 40°C 显示 "---",超过 274°C 触发全屏报警并钳制在 274°C。
— 文档结束 —