跳转到内容

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,是明说 「这两个出不去」,好过运行时静默少几个开关。

同一台设备的多个实体会组合成一个配件,而不是散成一堆开关:风扇的开关、档位、摆头、 童锁合起来是「家庭」里的一个风扇,带转速滑条和摆头开关。这不需要额外配置,把那几个实体 列进 export 就行。

组合靠的是每个实体的语义类class),见 devices.toml 的语义类。miot 设备的 class 由官方 spec 自动 推导,不用手标。

自动推导覆盖不到时才需要:设备是 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_informationprotocol_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.rsALL_SERVICES,可能落后于代码):outletlightbulbfanv2switchtemperature_sensorhumidity_sensorbatterystateless_programmable_switch。服务名与槽名认不认得、必需特征齐不齐,全部在 rha check 阶段报掉——以它为准

字段类型默认说明
accessoryarray可省略

手动绑定。自动推导覆盖不到时才需要(legacy 方言、厂商私有属性、或你不同意推导结果)。写了这个块就完全接管这台设备, 块里没提到的实体不会再自动冒出来; 块里绑的实体必须同时列进 export。

pin*string

HomeKit 配对码, XXX-XX-XXX 的 8 位数字, 例 "031-45-154"。不能用 Apple 的弱口令黑名单值(如 111-11-111), iOS 会拒绝配对。

portinteger
≥ 1,≤ 65535
51826

HAP 监听端口。

上表到 accessory 这一行为止:每种服务有哪些槽,这张表展不开,那层嵌套形状在 schema 里但渲染不出来。要查一个槽名叫什么,看上面的例子,或者直接写了跑 rha check ——认不得的服务名与槽名它会当场报掉,并列出它认得的。