npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

homebridge-websocket-platform

v1.1.1

Published

Homebridge platform plugin to create/update HomeKit accessories dynamically via WebSocket.

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-platform
  • name: 任意显示名称
  • listen: WebSocket 监听地址;推荐 host:port(例如 127.0.0.1:1888),也支持仅填端口(例如 1888
  • token: 必填;客户端必须提供该 token(见下文)
  • maxBufferedAmount: 可选;当某个客户端发送太慢(WebSocket bufferedAmount 超过该字节数)时,服务端会丢弃对该客户端的 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=AUTO
  • CurrentHeatingCoolingState: 0=OFF, 1=HEAT, 2=COOL
  • TemperatureDisplayUnits: 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 / TemperatureSensor
  • Thermostat

运行:

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 让缓存同步。