homebridge-websocket-platform
v1.1.1
Published
Homebridge platform plugin to create/update HomeKit accessories dynamically via WebSocket.
Maintainers
Readme
homebridge-websocket-platform
一个通过 WebSocket 动态创建/更新 HomeKit 配件的 Homebridge 平台插件。
- 你通过 WS 发送“配件定义(services + characteristics)”,插件会在 Homebridge 内创建/更新对应的 Accessory。
- 你通过 WS 读写 Characteristic,插件会同步更新 HomeKit,并广播变更事件。
Important: 这是一个“可自由定义任意 HAP Service/Characteristic”的插件。它不做业务语义限制(例如空调、传感器、开关),只要 HAP 里存在对应的 Service/Characteristic 名称就能用。
1. 安装
在 Homebridge 的插件目录(或你自己的开发目录)安装依赖并构建:
npm install
npm run build如果你是以开发方式运行,请确保 Homebridge 能加载到本插件的 dist/dynamic-platform.js。
2. Homebridge 配置
在你的 Homebridge 配置里添加平台(建议仅监听本机):
{
"platform": "homebridge-websocket-platform",
"name": "homebridge-websocket-platform",
"listen": "127.0.0.1:1888",
"token": "change-me",
"maxBufferedAmount": 1048576
}字段说明:
platform: 必须是homebridge-websocket-platformname: 任意显示名称listen: WebSocket 监听地址;推荐host:port(例如127.0.0.1:1888),也支持仅填端口(例如1888)token: 必填;客户端必须提供该 token(见下文)maxBufferedAmount: 可选;当某个客户端发送太慢(WebSocketbufferedAmount超过该字节数)时,服务端会丢弃对该客户端的 outgoing 消息,避免内存持续增长(默认1048576)
安全提醒
这个插件要求 token 鉴权,但你仍然应该:
- 优先仅监听本机:
127.0.0.1:1888 - 不要把 token 暴露在公网或不可信网络
3. WebSocket 连接
WebSocket 地址:
ws://<host>:<port>
鉴权(两种方式任选其一):
- Query:
ws://<host>:<port>?token=... - Header:
Authorization: Bearer <token>
连接成功后服务端会立即推送:
{
"event": "hello",
"data": {
"platform": "homebridge-websocket-platform",
"plugin": "homebridge-websocket-platform"
}
}4. 协议(不兼容旧格式)
本仓库目前使用的新协议格式如下:
4.1 请求(Request)
所有请求统一为:
{
"id": "任意字符串或数字(用于关联响应)",
"action": "...",
"payload": { }
}4.2 响应(Response)
{
"id": "与请求相同",
"ok": true,
"result": { }
}失败时:
{
"id": "与请求相同",
"ok": false,
"error": {
"message": "错误信息",
"code": "BAD_REQUEST | NOT_FOUND | INTERNAL"
}
}4.3 事件(Event)
Characteristic 变更事件:
{
"event": "characteristic.changed",
"data": {
"uuid": "...",
"service": {"type": "Switch", "subtype": "optional"},
"characteristic": "On",
"value": true,
"source": "ws | homekit"
}
}5. Actions(接口列表)
5.1 accessory.list
列出当前平台管理的配件。
请求:
{ "id": 1, "action": "accessory.list", "payload": {} }返回 result.accessories:
{
"accessories": [
{
"uuid": "...",
"name": "...",
"stableId": "...",
"services": [
{"type": "Switch", "name": "Main Switch", "subtype": "optional"}
]
}
]
}5.2 accessory.upsert
创建或更新一个配件(按 stableId 去重)。
请求:
{
"id": 2,
"action": "accessory.upsert",
"payload": {
"accessory": {
"stableId": "demo-001",
"name": "Demo Device",
"services": [
{
"type": "Switch",
"name": "Main Switch",
"characteristics": [
{"type": "On", "initialValue": false}
]
}
]
}
}
}说明:
stableId:用于生成 HomeKit UUID(必须稳定不变)services[].type:HAP 内的 Service 名称(例如Switch,Lightbulb,Thermostat,HeaterCooler,TemperatureSensor)services[].subtype:可选;用于同一种 Service 多实例区分characteristics[].type:HAP 内的 Characteristic 名称(例如On,TargetTemperature)initialValue:可选;首次创建时写入默认值(后续 upsert 不会覆盖已缓存值)characteristics[].props:可选;用于覆盖/补充 Homebridge 的CharacteristicProps(例如minValue,maxValue,minStep,unit,validValues等)- 也支持把这些字段直接平铺在
characteristics[]对象上(等价于props) - 服务端会把你传入的 props 与特征默认 props 合并后调用
setProps(best-effort)
- 也支持把这些字段直接平铺在
示例(控制 TargetTemperature 的范围与步进):
{
"type": "TargetTemperature",
"initialValue": 23.0,
"props": {"minValue": 10, "maxValue": 38, "minStep": 0.5}
}响应:
{ "uuid": "...", "name": "..." }5.3 accessory.remove
移除一个配件。
{
"id": 3,
"action": "accessory.remove",
"payload": {"uuid": "..."}
}5.4 accessory.removeAll
移除该平台创建的全部配件。
{ "id": 4, "action": "accessory.removeAll", "payload": {} }5.5 capabilities.get
列出服务端支持的 HAP Service / Characteristic 名称(用于客户端发现)。
{ "id": 5, "action": "capabilities.get", "payload": {} }5.6 characteristic.get
读取某个特征值。
payload.target 支持两种写法(二选一):
{ "uuid": "..." }:直接指定 accessory UUID{ "stableId": "..." }:使用accessory.upsert时的stableId(服务端会在内存中找到对应 accessory 并解析为 uuid)
另外,target.service 支持两种写法:
- 字符串:
"Switch" - 对象:
{ "type": "Switch", "subtype": "optional" }
{
"id": 6,
"action": "characteristic.get",
"payload": {
"target": {
"uuid": "...",
"service": {"type": "Switch"},
"characteristic": "On"
}
}
}5.7 characteristic.set
写入某个特征值(会调用 updateValue 并广播 characteristic.changed)。
{
"id": 7,
"action": "characteristic.set",
"payload": {
"target": {
"uuid": "...",
"service": {"type": "Switch"},
"characteristic": "On"
},
"value": true
}
}6. 常用配件定义示例
6.1 开关 + 温度传感器
{
"id": "ex-1",
"action": "accessory.upsert",
"payload": {
"accessory": {
"stableId": "demo-switch-temp",
"name": "Switch + Temp",
"services": [
{
"type": "Switch",
"name": "Main Switch",
"characteristics": [{"type": "On", "initialValue": false}]
},
{
"type": "TemperatureSensor",
"name": "Temp",
"characteristics": [
{
"type": "CurrentTemperature",
"initialValue": 20.0,
"props": {"minValue": -40, "maxValue": 100, "minStep": 0.1}
}
]
}
]
}
}
}6.2 恒温器(Thermostat)
数值枚举参考(常见):
TargetHeatingCoolingState: 0=OFF, 1=HEAT, 2=COOL, 3=AUTOCurrentHeatingCoolingState: 0=OFF, 1=HEAT, 2=COOLTemperatureDisplayUnits: 0=Celsius, 1=Fahrenheit
{
"id": "ex-2",
"action": "accessory.upsert",
"payload": {
"accessory": {
"stableId": "demo-thermostat",
"name": "Thermostat",
"services": [
{
"type": "Thermostat",
"name": "Thermostat",
"characteristics": [
{"type": "CurrentTemperature", "initialValue": 22.0},
{"type": "TargetTemperature", "initialValue": 23.0, "minValue": 10, "maxValue": 38, "minStep": 0.5},
{"type": "TargetHeatingCoolingState", "initialValue": 3},
{"type": "CurrentHeatingCoolingState", "initialValue": 0},
{"type": "TemperatureDisplayUnits", "initialValue": 0}
]
}
]
}
}
}7. 测试
仓库内置了一个简单的集成测试脚本,会覆盖:
Switch/TemperatureSensorThermostat
运行:
WS_TOKEN=change-me npm run ws:test -- --url ws://127.0.0.1:1888 --timeout 5000脚本路径:scripts/ws-test.js
8. 常见问题(FAQ)
8.1 Homebridge 能识别插件,但没日志
通常原因是 Homebridge 配置里没有添加该平台(platforms 数组缺少对应项)。
8.2 Unknown service / Unknown characteristic
你传入的 service.type / characteristic 名称必须是 HAP 内置的名字(区分大小写)。
8.3 为什么 accessory.list 里有“遗留配件”
旧版本/旧协议可能会让 Homebridge 缓存一些“没有 definition 的配件”。本插件现在 不再兼容 这类缓存对象:启动时会自动将其 unregister。
如果 Home App 里仍看到残留显示,通常需要在 Home App 里移除对应配件,或重启 Homebridge 让缓存同步。
