跳转到内容

mibeacon(小米 BLE)

小米的蓝牙温湿度计、体重秤这类设备不停地往外广播 MiBeacon 帧。rha 被动监听这些 广播,不连接设备、不配对、不发任何东西。接一台只要 MAC 和型号。

[[device]]
name = "thermo_livingroom"
adapter = "mibeacon"
mac = "A4:C1:38:CC:BB:AA"
model = "lywsd03mmc"

它依赖 bluer(BlueZ 的 D-Bus 绑定),只在 Linux 上被注册。在 macOS 开发机上,配了 adapter = "mibeacon" 的设备会被 rha check / rha doctor 直接报 unknown adapter

这是有意的:让它在校验期就报错,好过「误过之后到 run 时才发现设备根本没被驱动」。 同一份配置拿到 Linux 主机上部署时这段就生效了,不用改。

还有一个 feature 维度:mibeacon 同时是一个默认开启的 cargo feature。Linux 上若用 --no-default-features 构建(静态 musl 变体就是),它一样不会被注册,一样报 unknown adapter。要 BLE 就用 glibc 全功能变体。

值是设备自己送上来的,没有「问」这个动作——它名下的实体 poll_tier 是空的。

BLE 射频是共享的:一个进程只能有一条 BlueZ 扫描会话(BlueZ 会把所有调用了 StartDiscovery 的 client 的 filter 取并集,各开各的会互相改变对方看到的扫描行为)。 所以射频由中心 Hub 独占,各协议 adapter 只订阅自己关心的 service data。配 10 台 BLE 设备不会开 10 条连接,它们共用同一条扫描会话。

明文广播的设备不用配——包括原厂固件的 lywsd03mmc先不写 bindkey 试一次,收不到 值再去取。

设备发的是加密帧而你没配 bindkey 时,那一帧被丢弃,日志里留一条 mibeacon frame skipped ... encrypted frame but no bindkey,监听照常继续——现象是 实体一直没有值,而不是报错退出rha check 不会提前告诉你这件事:它离线时无从知道 这台设备发的是哪一种帧。

bindkey32 个 ASCII 十六进制字符(16 字节),长度或字符不对在 check 阶段就报 bindkey must be 32 ascii hex chars。它同样是 Secret,建议 ${ENV}

从哪拿:和 miot 的 token 出自同一条命令——

Terminal window
rha miot-token --username <米家账号>

BLE 设备那一行打的是 bindkey=(同行还给 mac,正好是上面 mac 字段要填的),而不是 miot 页说的 token=。云端给的密钥不是 32 hex 时那行会带一句 提示——那是旧版设备,rha 的 MiBeacon v5 解密用不了。

model 决定这台设备暴露哪些实体,是一张写死的小表——不像 miot 那样从 spec.d 读:

model 实体
lywsd03mmc temperature(℃)、humidity(%)、battery(%)
miscale weight(kg)、battery(%)

写别的值在 check 阶段报 unknown model,并把支持清单列出来。

字段类型默认说明
bindkeystring
Secret
可省略

解密广播用的绑定密钥, 32 个十六进制字符(16 字节, MiBeacon v5 的 AES-128-CCM)。 同样由 rha miot-token 打印; 云端给的长度不是 32 位时那条命令会当场标出来 "rha 的 MiBeacon v5 解密用不了", 不必等到这里才发现。

只有加密广播才需要: 明文广播的设备整条不配也能跑。反过来, 设备发的是加密帧 而这里空着(或者 key 配错), 协议循环不会退出, 只会每帧记一条 mibeacon frame skipped 的 warn(原因分别是缺 bindkey 与 MIC 校验不过), 实体则一直没值 —— 刻意如此: 配置问题不该让 supervise 反复重启, 那样日志被刷满反而看不见根因。

长度/字符不合法在 rha check 阶段就会被拦下(bindkey must be 32 ascii hex chars)。

敏感值。建议写成 ${ENV} 由环境变量插值, 不要把明文提交进配置文件。该值绝不进日志与 trace。

mac*string

设备的 BLE 广播地址, 六段冒号分隔的十六进制(A4:C1:38:CC:BB:AA), 大小写随意。 rha miot-token 会为每台 BLE 设备打印这个 mac=(同一行还有 bindkey)。

它是订阅键: 中心 Hub 只把地址完全相同的广播喂给这台设备(见 rha_ble)。 所以写错的表现是彻底安静 —— 没有报错、没有告警、实体永远 null, 因为陌生 地址的帧在 Hub 那层就丢了。发现"设备一直没值"时先核这一行。

填广播地址即可, 不用管 MiBeacon 帧内那个小端序 MAC —— 那是协议内部的事。

model*string

型号。这是 rha 内部的短名(如 lywsd03mmc), 不是米家云端那串型号 —— rha miot-token 打印的 model=miaomiaoce.… 粘过来是不认的; 认不出时 rha check 会报错并列出当前支持的全部短名。

它只决定声明哪些实体, 不参与解帧: 广播里认出来的量一律按自己的名字上报, 声明里没有的那条会被内核当未知实体丢掉(日志 report for unknown entity dropped), 声明了而设备不发的那条则一直是 null。所以型号挑错不会报错, 只会 表现成"实体列表对不上/部分实体永远没值"。