HomeKit
HomeKit 桥(HAP over IP)已经默认编进二进制,但编进去不等于跑起来:feature 只
决定 "homekit" 是不是一个认得的 bridge 类型;要不要真的监听端口、要不要往局域网广播,
全看 bridges.toml 里有没有一条 enabled 的 [[bridge]]。
[[bridge]]name = "home"type = "homekit"pin = "031-45-154"port = 51826
export = [ "plug_bedroom.switch_s2_on_p1", "thermo_demo.temperature", "thermo_demo.humidity",]name / export / exclude / enabled 是所有 bridge 共有的字段,说明在
bridges.toml;本页只讲 type = "homekit" 的私有参数。
配对状态(含长期身份私钥)落在 <配置目录>/bridges/<name>/pairing.toml,这个文件的
mode 是 0600(创建时就带上,不留「先 0644 再 chmod」的窗口)。删掉它等于把所有已配对的
iPhone 踢掉,需要全部重新配对。
export 必须显式写,而且别写 设备名.*
Section titled “export 必须显式写,而且别写 设备名.*”这是本页最容易踩坏的地方,两件事要一起讲。
第一,没有「默认全导」。 一台 cuco.plug.v3 插座有 28 个实体,全导会把上电默认
状态、充电保护功率、超用电量告警阈值一股脑推到 HomeKit 里。
第二,通配写法多半过不了 rha check。 一台设备上大多数实体推不出语义(风扇有 7 个:
指示灯、蜂鸣、定时三条、自然风、摆头角度),而选中没有语义类的实体是硬错误。就算把
它们 exclude 掉,还剩一个 fan_s2_fan_level_p2(1-4 档)——它和 p6(1-100 无级)都是
档位,而 HomeKit 只有一根转速滑条,落选的那个照样报错。
逐条列出来是唯一稳妥的写法,也更说明意图:
export = [ "fan_circulator.fan_s2_on_p1", "fan_circulator.fan_s2_fan_level_p6", "fan_circulator.fan_s2_horizontal_swing_p4", "fan_circulator.physical_controls_locked_s7_physical_controls_locked_p1",]差在哪 rha check 都会当场列清楚,不会留到真机上。另外 power(瞬时功率)与 weight
(体重)在 HAP 里没有标准 Service,导出它们会在 check 时被点名——这不是 bug,是明说
「这两个出不去」,好过运行时静默少几个开关。
一台设备 = 一个配件
Section titled “一台设备 = 一个配件”同一台设备的多个实体会组合成一个配件,而不是散成一堆开关:风扇的开关、档位、摆头、
童锁合起来是「家庭」里的一个风扇,带转速滑条和摆头开关。这不需要额外配置,把那几个实体
列进 export 就行。
组合靠的是每个实体的语义类(class),见
devices.toml 的语义类。miot 设备的 class 由官方 spec 自动
推导,不用手标。
手动绑定 [[bridge.accessory]]
Section titled “手动绑定 [[bridge.accessory]]”自动推导覆盖不到时才需要:设备是 legacy 方言(官方 spec 里根本没有这个型号,推不出任何 语义)、厂商私有属性、或者你不同意推导结果。
[[bridge.accessory]]device = "fan_circulator"
[[bridge.accessory.service]] type = "fanv2" active = "fan_s2_on_p1" rotation_speed = "fan_s2_fan_level_p6" swing_mode = "fan_s2_horizontal_swing_p4" lock_physical_controls = "physical_controls_locked_s7_physical_controls_locked_p1"槽值写能力名(实体 id 点号之后那半)。也可以写成表来显式给档位——spec 没有取值域、 或取值域是字符串时用:
rotation_speed = { entity = "fan_level", steps = ["small_fan", "medium_fan", "large_fan"] }下面 accessory 那行说明列了两条规则,这里补它没讲的道理:
- 「完全接管」是为了让配置可读——写了块就以块为准,你在配置里看到什么就是什么,不会 有隐形多出来的服务。
- 「必须同时列进
export」被做成硬错误,正因为不拦就没有任何输出:不在 export 里的 那一槽会在组装时被静静丢掉,它压根没进候选集,连 check 的「表达不了」清单里都不会出现。device写错是同一类:它不会悄悄退回自动推导,那样你看到的是「我明明配了绑定,怎么还是 老样子」。两种都是静默的缺口,所以必须报出来。
accessory_information 与 protocol_information 不要手写
Section titled “accessory_information 与 protocol_information 不要手写”这两个服务名解析器认得——它们和其它服务一样在服务目录里——但它们是内部服务,不要
写进 [[bridge.accessory.service]]:
accessory_information—— 每个配件已经自动带一份,且固定占iid 1..=7。手写会造成 同一配件上有两份,iOS 会判整台配件非法,现象是配对成功之后全部 No Response。protocol_information—— 只挂在桥自身(aid=1)上,不属于任何用户配件。
这类错误的共同点是不报错、只是不工作,而且看起来像网络故障。同一个道理下, Service / Characteristic 的目录本身不开放给配置:UUID 打错一个字符,控制端只会静默 忽略那条特征;漏一个必需特征,iOS 判废整台配件。可配置的是绑定,不是目录。
目录里可以手写的服务是这 8 种(清单是手抄的,抄自
crates/rha-bridge-homekit/src/map.rs 的 ALL_SERVICES,可能落后于代码):outlet、
lightbulb、fanv2、switch、temperature_sensor、humidity_sensor、battery、
stateless_programmable_switch。服务名与槽名认不认得、必需特征齐不齐,全部在
rha check 阶段报掉——以它为准。
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
accessory | array | 可省略 | 手动绑定。自动推导覆盖不到时才需要(legacy 方言、厂商私有属性、或你不同意推导结果)。写了这个块就完全接管这台设备, 块里没提到的实体不会再自动冒出来; 块里绑的实体必须同时列进 export。 |
pin* | string | — | HomeKit 配对码, XXX-XX-XXX 的 8 位数字, 例 "031-45-154"。不能用 Apple 的弱口令黑名单值(如 111-11-111), iOS 会拒绝配对。 |
port | integer | 51826 | HAP 监听端口。 |
上表到 accessory 这一行为止:每种服务有哪些槽,这张表展不开,那层嵌套形状在
schema 里但渲染不出来。要查一个槽名叫什么,看上面的例子,或者直接写了跑 rha check
——认不得的服务名与槽名它会当场报掉,并列出它认得的。