WiFi 蓝牙绑定流程
约 6512 字大约 22 分钟
2026-07-02
简介
WiFi 蓝牙绑定用于没有屏幕或键盘的设备首次接入。手机小程序通过 BLE 把 WiFi 名称、WiFi 密码和平台绑定 token 写入设备;设备连上路由器后,再通过 MQTT 向联犀平台上报 appBindToken,平台确认后小程序完成设备绑定。
这条链路只把蓝牙作为临时配网通道,设备真正上线和绑定仍以联犀 MQTT 设备身份、设备服务消息和绑定接口为准。设备服务报文可参考 设备服务。
首次绑定与更换 WiFi 的区别
网络管理权限与本地窗口
官方小程序通过既有项目权限限制网络管理入口:项目拥有者或明确的项目管理授权可以继续,普通成员不能操作。设备通过本地菜单开启限时蓝牙窗口,网络传输不依赖物模型或新增云端接口,沿用下文 E5 v2 能力通知;不增加 E6 签名命令。
入口权限检查不是 BLE 链路的身份认证。物理开启的窗口不能保证拒绝第三方 BLE 客户端,因此只应在本人操作期间开启,用完关闭。设备可以离线,手机仍需联网查询已有项目权限;查询失败不能当作已授权。
支持菜单的设备可分别提供“添加 / 更换 Wi-Fi”与“配网并绑定”。绑定入口二次确认后沿用 E4 Token 流程;普通换网不发送 Token,也不变更归属。候选 Wi-Fi 先隔离保存,设备收到 appBindToken code=200 且仍有 IP 后提交网络;小程序随后调用绑定接口才完成归属。手机绑定失败不撤销已提交的新网络;云端绑定已经成功而设备随后掉电时,恢复旧 Wi-Fi 也不意味着云端绑定被回滚。
首次绑定负责建立设备归属;已绑定设备更换 WiFi 只修改网络配置,两者不能混用。
| 项目 | 首次绑定 | 保留绑定换网 |
|---|---|---|
| WiFi 下发 | BLE E1 → E2 → E3 | 复用 BLE E1 → E2 → E3 |
| 绑定 token | 创建并通过 E4 下发 | 不创建、不下发 |
| 设备密钥和归属 | 按原注册、绑定流程建立 | 保留,不解绑、不重新注册 |
| 成功判定 | 联网及平台绑定完成 | 设备连接新 WiFi、获得 IP 且配置持久化完成 |
| 云服务暂不可达 | 可能阻止首次绑定 | 单独显示云端离线,不因此撤销已保存的新网络 |
发布边界:下文“保留绑定换网”是正在实现的扩展约定,尚未完成设备和手机验收,不代表所有现有固件已支持。客户端必须确认设备能力,不得仅凭
FFF0服务存在就启用换网,也不得把旧固件自动降级成解绑重配。
首次绑定整体流程
BLE 通道
本节定义联犀 WiFi 蓝牙配网的通道、字节格式、时序和兼容边界。首次绑定与保留绑定换网复用基础命令,网络保存策略由设备固件负责。
LLSync 蓝牙辅助配网不直接完成设备归属绑定。设备连上 WiFi 后通过 MQTT appBindToken 关联设备与 Token,小程序取得成功通知后调用平台绑定接口确认项目归属。
| 项目 | 值 |
|---|---|
| Service UUID | 0xFFF0 |
| App 写特征 | 0xFFE1 |
| 设备通知特征 | 0xFFE3 |
| 设备信息协议版本 | 0x02;WiFi 配网广播使用完整版本字节 |
| WiFi 模式 | 仅支持 STA:0x01 |
设备广播 manufacturer data 固定携带:
| 字段 | 长度 | 说明 |
|---|---|---|
| Company ID | 2 字节 | 当前兼容值 0xFEE7,线上小端字节为 E7 FE |
| 协议版本 | 1 字节 | WiFi 配网模式直接写入 02;不包含 BLE 绑定状态 |
| MAC | 6 字节 | 设备 MAC |
| ProductID | 10 字节 | 联犀产品 ID,UTF-8/ASCII 字节,不足 10 字节时可能以 0x00 填充 |
解析偏移示例:
byte[0..1] Company ID
byte[2] WiFi 配网协议版本,完整字节 0x02 表示版本 2
byte[3..8] MAC
byte[9..18] ProductID,解析后去掉末尾 0x00 填充以上偏移针对包含 Company ID 的厂商数据。Linux BlueZ 的 ManufacturerData 已将 Company ID 作为字典键,取出 0xFEE7 对应的值后,17 字节正文从版本字节开始, MAC 位于正文 [1..6],ProductID 位于 [7..16]。不要重复跳过 Company ID, 也不要套用其他蓝牙工作模式的版本/绑定状态位段。
配网命令
小程序通过 FFE1 写入命令,设备通过 FFE3 通知结果。
| 阶段 | App 写入 | 设备上报 | 成功条件 |
|---|---|---|---|
| 读取设备信息 | E0 | 08 00 LL ... | 能解析设备名、版本、MTU |
| 设置 WiFi 模式 | E1 01 | E0 00 01 00 | result 为 0x00 |
| 写入 WiFi | E2 00 LL SSID/PWD | E1 00 01 00 | result 为 0x00 |
| 请求联网 | E3 | E2 00 LL 01 00 ... | Station 状态为 0x00 |
| 写入 token | E4 00 LL TOKEN | E3 00 01 00 | result 为 0x00 |
| 读取日志 | E5 | E4 00 LL TYPE MSG | 用于失败排查 |
| MTU 协商结果 | 09 RESULT_H RESULT_L | 失败回退时可能收到 0C 00 02 MTU_H MTU_L | 不代表 WiFi 连接或绑定成功 |
表内 00 LL 仅简写未分片且正文长度小于 256 的情况。所有长度按字节计算,中文等 UTF-8 字符不能按字符个数计长。字节值使用十六进制表示。
通知帧、分片与 MTU
完整 GATT UUID 为:
- 服务:
0000FFF0-65D0-4E20-B56A-E493541BA4E2。 - 手机写入:
0000FFE1-65D0-4E20-B56A-E493541BA4E2。 - 设备通知:
0000FFE3-65D0-4E20-B56A-E493541BA4E2,手机须先启用通知订阅。
通知格式为 TYPE FLAG_LEN_H LEN_L PAYLOAD。第二字节高两位是分片标志,剩余十四位表示当前片正文长度:
| 高两位 | 字节掩码 | 含义 |
|---|---|---|
00 | 00 | 不分片 |
01 | 40 | 首片 |
10 | 80 | 中间片 |
11 | C0 | 尾片 |
例如每片长度计算为 ((FLAG_LEN_H & 0x3F) << 8) | LEN_L,必须等于收到的通知长度减 3。接收方先拼接同类型的正文,再解析设备名、SSID 和状态。首片里出现状态零不表示收到完整成功结果。
同一连接串行发送一个逻辑报文的所有分片;协议没有片序号,不能乱序重排或自行去重内容相同的片。缺首片、跨类型续片、长度不符、断线、超过接收上限或重组超时均丢弃半包。当前小程序重组上限为 4096 字节、时限 10 秒;新连接必须清空旧缓存。
ATT MTU 默认 23,GATT value 可用长度为 ATT MTU 减 3;通知帧自身再占 3 字节。设备名或 SSID 因此可能在默认 MTU 下被分片,不能假设提高 MTU 后就永远没有分片。
设备信息的 MTU 字段最高位 0x8000 表示请求手机协商,当前小程序按 field & 0x1FFF 读取数据长度。手机协商后写入:
09 00 00 协商成功,由底层 MTU 事件同步实际值
09 FF FF 协商失败,设备回退默认 ATT MTU设备接口也接受 09 MTU_H MTU_L 直接提供实际 ATT MTU(非零且不是 FFFF)。回退通知 0C 00 02 00 14 表示可用 GATT 数据长度 20,不是 ATT MTU 20。
E0 读取设备信息
小程序连接设备并订阅 FFE3 后,先通过 FFE1 写入:
E0设备通过 FFE3 回复:
08 LEN_H LEN_L LLSYNC_VERSION MTU_H MTU_L NAME_LEN DEVICE_NAMEDEVICE_NAME 最长 48 字节,LEN = 4 + NAME_LEN。必须收到完整名称再核对身份。后续平台绑定使用设备实际返回的设备名;已绑定换网必须与所选设备精确匹配,不能用同产品附近另一设备替代。
E1 设置 WiFi 模式
当前仅支持 STA 模式。
E1 01设备回复:
E0 00 01 RESULTRESULT = 0x00 表示成功,0x01 表示失败。
E2 下发 WiFi 信息
WiFi 信息负载格式:
E2 LEN_H LEN_L SSID_LEN SSID_BYTES PWD_LEN PWD_BYTES发送端的 LEN 统计 SSID_BYTES.length + PWD_BYTES.length,不包含 SSID_LEN 和 PWD_LEN 两个长度字节。现有设备解析器兼容包含这两个字节的旧客户端长度,但必须验证实际字段边界和整包长度;新客户端统一使用前一种口径。
SSID 为 1—32 字节;当前 BLE 凭据解析入口接受密码 0—63 字节,0 表示开放网络。虽然部分芯片驱动接受 64 字节 PSK,不能据此绕过 BLE 入口限制。字符串不允许内嵌 NUL。
开放测试网络 A 的命令为 E2 00 01 01 41 00;对应回复 E1 00 01 00 仅表示参数受理,不代表联网或持久化成功。
设备回复:
E1 00 01 RESULTRESULT = 0x00 表示设置成功,0x01 表示失败。
E3 请求 WiFi 连接
小程序写入:
E3设备连接路由器后回复:
E2 LEN_H LEN_L WIFI_MODE STATION_STATUS SOFTAP_STATUS SSID_LEN SSID其中:
| 字段 | 说明 |
|---|---|
WIFI_MODE | 当前仅支持 STA:0x01 |
STATION_STATUS | 0x00 表示已连接,0x01 表示未连接 |
SOFTAP_STATUS | 当前不使用 |
SSID_LEN/SSID | 已连接时返回当前 SSID;未连接时 SSID_LEN = 0 |
LEN = 4 + SSID_LEN。现有适配器在未连接时也可能返回候选 SSID,因此成功必须同时验证 STA 模式、完整报文和 STATION_STATUS=00,不能以 SSID 非空判断。
网络 A 的完整成功通知示例为 E2 00 05 01 00 00 01 41。原协议仅区分连接与其他状态,不携带请求 ID、持久化阶段或密码错误细分码;不能把这些字段擅自塞进原报文。保留绑定换网在保存完成后使用该联网反馈,首次绑定还需继续 Token 步骤。
E4 下发绑定 token
绑定 token 负载格式:
E4 LEN_H LEN_L TOKEN_BYTES设备拿到 token 后,通过 MQTT 向平台上报 appBindToken。平台返回成功后,设备通过 BLE 回复:
E3 00 01 RESULTRESULT = 0x00 表示 token 处理成功,0x01 表示失败。注意这里的 BLE 成功码仍是 0x00,不要和 MQTT 服务响应里的 code=200 混用。
当前 Token 写入入口接受 1—32 字节,LEN 等于 Token 实际字节长度。换网不调用此命令;写入成功和平台绑定成功是不同阶段,不能用 GATT 写成功代替设备回执。
E5 获取配网日志
配网失败后,小程序可写入:
E5设备通过 E4 返回日志:
E4 LEN_H LEN_L LOG_TYPE MSG_CONTENTLOG_TYPE 含义:
| 值 | 含义 |
|---|---|
0x00 | 设备可能存储的未上报错误日志 |
0x01 | 本次配网产生的错误日志 |
0x02 | 普通配网过程日志 |
现有 HAL 兼容差异:当前实现也会直接发送 UTF-8 日志正文,即 E4 LEN_H LEN_L MSG_CONTENT,没有 LOG_TYPE。客户端在正文首字节为 00/01/02 时按类型前缀解码,否则把完整正文按 UTF-8 读取。外层长度包含全部正文,不存在第二个日志长度字段。日志可分片;没有日志时不能保证有回复,读取超时只表示未取得日志,不应覆盖原失败原因。
保留绑定换网(未发布扩展)
本地闭环与入口
用户从设备网络菜单开启限时 BLE 换网窗口。即使原路由器已经关闭,也不依赖云端唤起。在线远程唤起仅是可选入口,不能作为换网前提。
- 小程序连接设备,核对广播 ProductID 和设备信息中的 DeviceName,并确认换网能力和模式。
- 设备在限时窗口内接收候选 WiFi;小程序复用 STA、WiFi 写入和请求联网命令,不进入
E4绑定流程。 - 候选配置与正式列表隔离。设备尝试连接并取得 IP,然后可靠保存新列表。
- 设备完成保存后通过 BLE 返回本次请求的成功结果;小程序不能把写入受理、获得 IP 或历史云端在线状态当作最终成功。
- 密码错误、超时或取消时丢弃候选,继续使用原有网络。提交中断电须能恢复一致列表,不能因半写配置丢失所有旧网络。
- 小程序漏收最终通知时显示“结果未确认”;扩展须支持重连读取最近一次结果,并按设备身份和请求 ID 关联,不根据 BLE 断开推断成功。
换网不需要新增平台状态属性;设备自己的屏幕与小程序通过 BLE 展示过程和错误。OTA 或拍照执行中拒绝进入换网,进入前先结束语音会话。WiFi 密码、设备密钥、绑定 token 均不得进入日志或结果通知。
开发分支扩展与标准联网反馈的边界
基础联网成功继续复用上述 FFE3 E2,不以自定义状态通知替代。以下 FFE3 E5 是现有未发布分支的额外能力/事务通知,不属于所有设备必备命令;正在评估收敛,不应作为新第三方客户端的稳定对接合同。
开发分支已有如下设备到小程序的状态通知封包,正式发布前仍须完成本地闭环语义和兼容性验证:
FFE3 Notify: E5 00 0C VERSION MODE STAGE ERROR REQUEST_ID[8]| 字段 | 长度 | 约束 |
|---|---|---|
E5 | 1 字节 | 设备通知类型,不是手机写入命令 |
00 0C | 2 字节 | 大端负载长度 12;整包 15 字节 |
VERSION | 1 字节 | 扩展版本;客户端不接受未支持版本 |
MODE | 1 字节 | 区分保留绑定换网与其他配网模式 |
STAGE | 1 字节 | 本次换网阶段;最终成功必须发生在持久化完成后 |
ERROR | 1 字节 | 非敏感错误码,不携带密码或认证材料 |
REQUEST_ID | 8 字节 | 对应 16 位十六进制请求 ID,用于隔离迟到结果 |
不能混淆两个方向的 E5:手机向 FFE1 写入单字节 E5 仍表示读取日志,设备使用 E4 返回日志;这里的 FFE3 E5 是新增通知类型,不改变原日志命令。客户端按特征方向、报文长度和扩展版本解码。
当前本地闭环使用 VERSION=2, MODE=1:0 空闲、1 待受控启动、2 BLE 等待、3 候选受理/连接中、6 持久化提交、7 已保存、8 失败、9 待物理确认;4、5 是旧流程阶段,本地流程不进入。错误值保留:0 无、1 重启中断、2 超时、3 取消、4 鉴权(旧流程保留)、5 网络、6 存储。版本 1 使用旧云端确认语义,新客户端不接受版本 1 换网,也不将其阶段 7 解释成本地保存成功。
阶段 7 只有在实际关联 SSID 与候选一致、取得 IP、正式列表保存和回读以及成功终态持久化全部完成后产生。客户端仍须收到标准 E2 成功和正确 SSID;等待期间收到另一请求或失败状态时,迟到 E2 无效。阶段通知与 E2 可以交错到达,不能强制以通知到达次序判定成功。
基础协议没有“能力查询”或“最近一次结果重查”的标准命令。版本 2 的设备成功后保留 30 秒 BLE 结果窗口,在终态接收重复 E3 时仅重发标准联网结果,不再次连接或写入配置;该幂等行为仅限本扩展,不能推断旧固件也如此。窗口结束释放蓝牙并重启正常联网。
小程序等待结果异常时最多重连原 BLE 设备一次,核对 ProductID、DeviceName、同一请求 ID 和阶段 7 后才发送 E3 重查;仍须收到目标 SSID 的标准联网成功。此路径不发送模式、WiFi 密码或绑定 Token;旧请求、不支持版本、未提交阶段、窗口已结束及查询失败均不能宣称成功。取消后的迟到结果无效。页面内重试已提交的同一请求也只查询,不覆盖配置;超出设备结果窗口后不得承诺仍能恢复读取。
最近网络与自动重连
Watcher 开发分支按以下策略保留最近成功使用的 10 组网络,而不是每次换网清空旧 WiFi;尚待真实网络切换及断电验收:
- 新网络成功保存后加入列表,相同 SSID 更新密码而不重复占位。
- 成功连接后更新最近使用顺序;重复连接列表首项不反复写 Flash。
- 最近顺序独立存储,不因普通重连重写 WiFi 密码;排序记录损坏时保留有效凭据,回退存储顺序。
- 第 11 组网络成功加入时,淘汰最久未成功使用的一组;候选连接失败不淘汰旧网络。
- 当前连接正常时不主动切网;断开后扫描已保存网络,优先最近成功使用的可见网络,失败再尝试其他网络。
- 所有已保存网络不可用时保留凭据,显示离线并允许用户从本地菜单换网。
- 有已保存网络时持续重试,不因启动联网超时自动停止扫描或开启热点;首次无凭据的配网入口不变。
- 当前按 SSID 区分配置;不同地点同名但不同密码的多份配置不在此约定范围内。
网络容量与选择策略是固件能力,不要求手机批量下发十组配置,也不允许手机读取设备保存的密码。
超时、重试与安全边界
- GATT 写入完成只表示传输完成,业务流程须等待对应设备通知。模式和凭据受理失败立即结束当前尝试,不继续下发 Token。
- 当前客户端设备信息、模式设置、凭据受理各等待 10 秒,联网等待 70 秒,Token 结果等待 60 秒,日志等待 10 秒;这些是客户端等待策略,不是线上报文中的字段。
- 密码错误与 AP 不可达在基础联网通知里都属于非连接状态,详细原因通过设备 UI 或脱敏日志展示;没有细分码时不得猜测为密码错误。
- 一次连接只执行一个配网流程;取消后清除等待器、精确解绑通知回调,旧异步结果不得改变新流程。
- 基础凭据命令正文没有应用层加密字段,不能宣称 SSID/密码已由此协议加密。设备应通过物理操作开启短时配网窗口;如产品要求链路加密,应另行落实 BLE 链路安全并实测,不能仅靠设备名称核对代替身份认证。
- 不在日志、截图、错误回执中输出密码、Token 或设备密钥。配网未完成不清绑定;恢复出厂是独立的用户确认操作。
发布前验证
- 协议:首次绑定兼容、身份不匹配、未知版本、重复请求、迟到通知、BLE 断开和结果重查。
- 存储:同名更新、十槽淘汰、失败不覆盖、各提交阶段断电恢复。
- 实机:两个已保存网络之间往返自动连接、错误密码、DHCP 失败、WiFi 可用但云端不可达。
- 手机:Android/iOS 小程序分别验收;BlueZ 或模拟测试不能替代手机测试。
小程序侧首次绑定实现要点
小程序端应以 ProvisionSessionService 作为唯一配网状态机,页面只负责 WiFi 输入、进度展示和结果展示。
const ADV_SERVICE_UUID = '0000FFF0-0000-1000-8000-00805F9B34FB'
const SERVICE_UUID = '0000FFF0-65D0-4E20-B56A-E493541BA4E2'
const WRITE_UUID = '0000FFE1-65D0-4E20-B56A-E493541BA4E2'
const NOTIFY_UUID = '0000FFE3-65D0-4E20-B56A-E493541BA4E2'
function parseAdvertisingData(bytes: number[]) {
const productIDBytes = bytes.slice(9, 19).filter((v) => v !== 0)
return {
// WiFi 配网广播使用完整版本字节,不套用其他 BLE 模式的状态位。
protocolVersion: bytes[2],
mac: bytes.slice(3, 9).map((v) => v.toString(16).padStart(2, '0')).join(':'),
productID: new TextDecoder().decode(new Uint8Array(productIDBytes)),
}
}
function buildWifiInfoCommand(ssidBytes: number[], pwdBytes: number[]) {
const len = ssidBytes.length + pwdBytes.length
return new Uint8Array([0xe2, len >> 8, len & 0xff, ssidBytes.length, ...ssidBytes, pwdBytes.length, ...pwdBytes])
}
function buildTokenCommand(tokenBytes: number[]) {
return new Uint8Array([0xe4, tokenBytes.length >> 8, tokenBytes.length & 0xff, ...tokenBytes])
}推荐顺序:
- 扫描
FFF0或解析 manufacturer data,得到ProductID、MAC 和候选设备名。 - 连接设备后订阅
FFE3,再写入E0。 - 收到设备信息后再按
E1 -> E2 -> E3 -> E4顺序推进。 - 设备返回 token 成功后,小程序使用
ProductID + DeviceName + token调用平台绑定接口。 - 任一阶段失败时,优先写入
E5拉取设备日志,再展示失败原因。
设备端绑定报文
设备联网后发布到:
$thing/up/service/{ProductID}/{DeviceName}报文:
{
"method": "appBindToken",
"msgToken": "DEVICE_NAME-123456",
"params": {
"token": "APP_CREATE_BIND_TOKEN"
}
}设备订阅:
$thing/down/service/{ProductID}/{DeviceName}平台响应:
{
"method": "appBindToken",
"msgToken": "DEVICE_NAME-123456",
"code": 200,
"msg": "success"
}设备端只有收到 code == 200 才能发送 Token 处理成功通知;这不是项目归属绑定完成。小程序还须等待绑定接口成功,再回读设备归属,不得以 GATT 写成功或该 MQTT 回执直接显示整体绑定成功。
MQTT 动态注册与认证
一型一密设备首次联网时,设备本地通常还没有设备级密钥,需要先完成动态注册,再用注册结果发起正式 MQTT 连接。动态注册和正式接入是两套不同的 MQTT 连接与认证规则,不要混用。
动态注册连接
设备本地没有 DevicePsk 时,先使用产品级密钥发起 MQTT 动态注册。
| 项目 | 规则 |
|---|---|
| ClientID | register&{ProductID}&{DeviceName} |
| Username | 可任意填写 |
| Password | 可任意填写 |
| 上行 Topic | $ext/up/register/{ProductID}/{DeviceName} |
| 下行 Topic | $ext/down/register/{ProductID}/{DeviceName} |
| 签名密钥 | 产品密钥 ProductSecret |
| 签名规则 | Base64(HEX(HMAC-SHA1(data, ProductSecret_ASCII))) |
动态注册签名使用 ProductSecret 时,直接使用控制台显示的字符串 ASCII 字节,不要对 ProductSecret 做 Base64 解码。
动态注册成功后,平台返回的 payload 中可能包含:
| 字段 | 说明 |
|---|---|
psk | 签名认证设备使用的设备级密钥 |
clientCert | 证书认证设备使用的客户端证书 |
clientKey | 证书认证设备使用的客户端私钥 |
不要只依赖 encryptionType 判断认证方式。当前版本里 encryptionType 可能固定为 1,设备端应以 psk、clientCert、clientKey 是否为空判断:
| 返回内容 | 认证方式 |
|---|---|
psk 非空,clientCert/clientKey 为空 | 签名认证 |
clientCert/clientKey 非空,psk 为空 | 证书认证 |
正式 MQTT 连接
动态注册拿到设备级密钥或证书后,应断开注册连接,再重新建立正式设备连接。
| 项目 | 规则 |
|---|---|
| ClientID | {ProductID}&{DeviceName} |
| Username | {ProductID}&{DeviceName};12010126;{connid};{expiry} |
| Password | {token};hmacsha256 |
| 签名密钥 | 动态注册返回的 psk,或控制台设备密钥 |
签名认证设备生成 MQTT password 时,应按 mqtt认证 的密钥认证规则处理设备密钥。也就是说,动态注册返回的 psk 是正式 MQTT 认证用的设备级密钥,设备端应按 MQTT 认证文档生成 username/password。
设备端持久化要求
量产设备必须把动态注册返回的 psk、证书或私钥保存到安全存储中,例如 ESP32 NVS 或加密分区。后续重启时,如果本地已经存在设备级密钥,应直接走正式 MQTT 连接,不应每次启动都重复动态注册。
Demo 工程为了方便联调,可能会清空或不持久化设备级密钥,因此重启后再次出现:
dev psk not exist, do dyn reg!这条日志本身不表示失败,只表示当前设备本地没有设备级密钥,正在进入动态注册流程。
ESP32 SDK 示例
ESP32 示例工程为 unitedrhino-iot-ble-esp32。核心改动点:
- BLE 配网通道使用本文上方整理的
FFF0 / FFE1 / FFE3和E0-E5报文。 - WiFi 密码不写入日志,只记录 SSID 和密码长度。
- 设备没有本地
DevicePsk时先走 MQTT 动态注册,注册成功后再走正式 MQTT 认证。 - MQTT 绑定上报使用
appBindToken + msgToken + code=200。
设备端上报 token 的关键代码形态:
HAL_Snprintf(
topic_content,
sizeof(topic_content),
"{\"method\":\"appBindToken\",\"msgToken\":\"%s-%u\",\"params\":{\"token\":\"%s\"}}",
dev_info->device_name,
HAL_GetTimeMs(),
info->token_str
);WiFi 信息日志建议:
ESP_LOGI(TAG, "wifi ssid %s, password length %d", wifi_config.sta.ssid, passwd_len);常见问题
| 现象 | 可能原因 | 排查方式 |
|---|---|---|
| 小程序扫描不到设备 | 设备未广播 FFF0 或 manufacturer data 不完整 | 确认广播中包含协议版本、MAC、ProductID |
| 写入 WiFi 后失败 | SSID/密码长度或编码不正确 | 检查 E2 的 2 字节长度、SSID 长度、密码长度 |
| 设备联网失败 | WiFi 密码错误或路由器不可达 | 看 E2 上报的 Station 状态,并用 E5 拉日志 |
| 动态注册失败 | ProductSecret、签名规则、Broker 域名或注册 Topic 不正确 | 检查 register&ProductID&DeviceName、$ext/up/down/register 和签名 |
| MQTT 认证失败 | 把动态注册签名规则和正式 MQTT 认证规则混用 | 检查正式连接的 clientID、username、password |
| token 阶段失败 | 小程序未创建绑定 token 或设备未上报平台 | 检查 E4 写入内容和 MQTT appBindToken 报文 |
| 平台绑定失败 | ProductID 或 DeviceName 与平台设备身份不一致 | 对比广播 ProductID、设备信息 DeviceName 和平台设备列表 |
更新日志
2026/9/30 07:09
查看所有更新日志
9e711-文档:修正配网广播版本解析示例于34d0e-文档:明确蓝牙Token回执不代表归属绑定完成于6d791-文档:恢复本地蓝牙配网协议与权限边界于83cf0-文档:补齐蓝牙换网许可与版本兼容合同于c2896-文档:纠正WiFi配网广播版本与BlueZ偏移于b7b86-文档:说明换网结果只读恢复与窗口限制于8b876-文档:补充最近网络保存与离线重试边界于d195f-文档:明确本地换网能力版本与成功回执边界于87e0e-文档:补齐蓝牙配网报文边界与保留绑定换网说明于7e927-文档站全面重构:目录重排、首页重写、案例独立成站、应用市场下线于c358e-Merge #4 into master from codex/wifi-ble-bind-doc于
