• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

使用 Homebridge 米家设备接入 Homekit

武飞扬头像
xjmeng
帮助1

缘起

起初为了解决晚上不开空调太热,开了又太冷的问题,入手了一个空调伴侣。由于家里大多是苹果设备,又恰好有 Homepod mini,就选择了 Aqara 的一款支持 Homekit 直接接入的产品。做了个自动化,温度升到一定程度就制冷几分钟,从此再也没有被热醒。

后续每次搬家都会因地制宜购买一些合适的智能设备,如今家里两台空调、一台热水器和几乎所有的灯都接入了 Homekit,所有设备均可通过 Siri 控制,并且支持配置相应自动化,实现夜间有人经过自动亮灯、开门自动打开客厅灯等功能,对于长期租房生活的人而言,不得不说是一种提升居家幸福感的方式。

学新通

Homekit 为何物

这里简单介绍一下 HomeKit,它是 Apple 官方推出的智能家居解决方案,双向开放。意思是客户端与智能家居设备之间的通信协议是公开的,你既可以编写代码自行模拟出一个 Homekit 设备,也可以自行实现客户端控制家庭内的设备。

为了便于 Siri 控制,HomeKit 将一个智能设备抽象为三个等级:Accessory、Service、Characteristic。

Accessory 可以理解为是一个硬件实体,例如一盏灯、上面的一个空调伴侣,都是一个 Accessory。

Service 是智能设备拥有的功能,例如开关、灯泡、风扇。一个 Accessory 是可以包含多个 Service 的,比如我的屏幕挂灯,除了前面的主灯之外还有一个氛围灯,那在 HomeKit 中就可以映射为两个 Lightbulb Service。

每个 Service 会包含一组特定的属性,叫做 Characteristic。例如 Lightbulb Service 中,有一个 On 属性,表示灯的开关状态,有一个 Brightness 可选属性,表示灯的亮度。更多 Service 和其对应的 Characeristic 可以参考 Homebridge 开发者文档

探索跨平台接入

最初设想的很美好,每次都购入支持 Homekit 的产品,这样就可以把所有设备聚合在一个平台。但是随着需求越来越多样,要么是支持 Homekit 的产品价格都略贵,要么满足场景的产品都没有支持 Homekit。于是便把目光转向了另一大智能家居平台——米家。

手里的第一台米家设备是一个显示器挂灯,由于不想舍弃原有的 Homekit 平台,还是继续想喊 Siri 来开关设备,于是就想了一个迂回办法:把开关灯做成快捷指令,这样只要说出指令名,就可以语音操控。但实际用了一段时间发现,快捷指令体验较原生还是差了不少。一是指令名不能说错,哪怕差一个字也会原地暴露 Siri 愚蠢本性。二是仅能做一些简单的开关灯操作,像调亮度调颜色这类需要一点语义的指令还是无法支持。

学新通

使用 Homebridge 桥接智能设备

为了能让 Siri 代理米家设备,还不牺牲产品功能,我开始调研将米家设备接入 HomeKit 的方法。目前主流方案有两个:Homebridge 和 HomeAssistant。Homebridge 较为轻量且本身就是为 Homekit 服务,将它作为切入点是个不错的选择,但尝试了几个插件之后发现,要么无法调颜色,要么背景灯和前景灯和在了一起无法单独控制。一筹莫展之际,翻看了一下 Homebridge 的代码,发现竟然是 Javascript 实现,前端开发者狂喜,马上开始研究如何自行实现一个插件。

正如名字中的 "bridge",Homebridge 起到了桥梁的作用,通过编写插件,它可以在局域网内模拟出一个 Homekit 设备,你只需要在插件中定义出这些设备的功能,家庭应用里就会自动出现这个设备。当你通过 Homekit 造作一个智能设备时,Homebridge 便会收到通知,执行插件中定义好的逻辑,进而完成实际的设备操作。

学新通

Homebridge 关系图。插图使用 excalidraw.com/ 绘制

不难发现,将一个其它平台的设备接入 Homekit 主要有两个步骤:一是选择合适的一组 Service 和 Characteristic 并在 Homebridge 插件中定义,二是找到在代码中本地控制智能设备的方法。我们分别来看如何实现这两个步骤。

编写 Homebridge 插件

Homebridge 提供了一个插件模板可以供开发者快速构建起一个插件,clone 项目后,像正常前端项目一样执行 npm install 安装依赖后就可以启动了。启动后在终端会显示 Homekit 的配对码,使用家庭 app 即可将 Homebridge 添加成为一个桥接设备。

模板项目里面包含一个灯泡和一个运动传感器用于展示,添加桥接设备后,正常就可以在家庭应用中看到这两个模拟设备了。定义一个设备的核心代码位于 platformAccessory.ts文件:

this.service = this.accessory.getService(this.platform.Service.Lightbulb) || this.accessory.addService(this.platform.Service.Lightbulb);

this.service.getCharacteristic(this.platform.Characteristic.On)
      .onSet(this.setOn.bind(this))                
      .onGet(this.getOn.bind(this));               

accessory 可以在 Homebridge API 中创建,你只需要定义好 accessory 对应的 Service、Characteristic,配置好属性 onGet 和 onSet 的回调,即可完成虚拟设备的创建。

对于屏幕挂灯来说,定义一个背景灯、一个主灯就类似这样:

setupLightService() {
    const serviceName = 'light';
    const service = this.accessory.getService(serviceName) || this.accessory.addService(this.Service.Lightbulb, serviceName, 'Light');
    service
      .getCharacteristic(this.Characteristic.On)
      .onSet((value) => this.controller.setLightPower(value ? 'on' : 'off'))
      .onGet(this.createPropGetter('main_power', (p) => p === 'on'));

    service
      .getCharacteristic(this.Characteristic.Brightness)
      .onSet((value) => this.controller.setLightBright(value as number))
      .onGet(this.createPropGetter('bright'));

    service
      .getCharacteristic(this.Characteristic.ColorTemperature)
      .onSet((v) => this.controller.setLightColorTemperature(this.homeKitCtToYeeLight(v as number)))
      .onGet(this.createPropGetter('ct', (v) => this.YeeLightCtToHomeKit(parseInt(v as string))));
  }

  setupBgService() {
    const serviceName = 'background';
    const service = this.accessory.getService(serviceName) || this.accessory.addService(this.Service.Lightbulb, serviceName, 'BG');
    service
      .getCharacteristic(this.Characteristic.On)
      .onSet((value) => this.controller.setBgPower(value ? 'on' : 'off'))
      .onGet(this.createPropGetter('bg_power', (p) => p === 'on'));

    service
      .getCharacteristic(this.Characteristic.Brightness)
      .onSet((value) => this.controller.setBgBright(value as number))
      .onGet(this.createPropGetter('bg_bright'));

    service
      .getCharacteristic(this.Characteristic.Hue)
      .onGet(() => this.controller.getBgHue())
      .onSet((v) => this.controller.setBgHue(v as number));
    service
      .getCharacteristic(this.Characteristic.Saturation)
      .onGet(() => this.controller.getBgSaturation())
      .onSet((v) => this.controller.setBgSaturation(v as number));
  }

  connect(): void {
    this.setupInformation('Yeelight Technology');
    this.setupLightService();
    this.setupBgService();
  }

本地控制米家设备

米家设备绑定成功后,设备会启动一个 UDP Server 用于与外界通信,我们就可以直接向这个 UDP 服务发送请求来控制设备。客户端与 UDP 服务的通信协议为米家自研的二进制协议,具体可以参考:Xiaomi Mi Home Binary Protocol

二进制解包以后是 JSON 格式的数据,具体的数据内容经测试大概有两种格式,一种是通过 miot-spec 定义的米家标准属性,可以通过 miot-spec.com 查询。另一种是较为古老的自非标准格式,可以通过抓包等方式获取到。“标准”是针对 JSON 中的 params 字段而言的,两种格式的发包均包含 id method params几个字段。

而不同设备对这两种格式的支持情况不同,需要进行实际测试,格式不支持时会返回错误码,或干脆静默无返回。

// miot-spec 格式发包
{"id":1844,"method":"get_properties","params":[{"diid":111111,"siid":2,"piid":1}]}
// miot-spec 格式回包
{"id":1844,"result":[{"did":"","siid":2,"piid":1,"code":0,"value":false}],"exe_time":20}

// 非标准格式发包
{"id":8534,"method":"get_prop","params":["tar_temp"]}
// 非标准格式回包
{"id":8534,"result":[27],"exe_time":10}

完整项目

我把目前已购买的米家设备均接入了 Homekit,插件代码:homebridge-miio-local-platform,目前支持到了以下几种设备型号。如果你也感兴趣,可以在 Homebridge UI 中搜索安装 MiIO Local Platform插件,填入设备 id 、token 和 name 即可运行。未被支持到的设备型号则不会在家庭 app 中出现。关于小米设备的 id 和 token 可以参考其它文章,我这里使用的是 Xiaomi-cloud-tokens-extractor,通过登录至小米账号直接获取,比较方便。

学新通

注意事项

自带 WiFi 模块的米家设备可以直接接入,而仅支持蓝牙连接的设备则需要一个网关。如果不想购买网关可以尝试使用 ESP32 模拟网关功能,但带机量有限,目前自定义网关的操作还在探索中╮(╯▽╰)╭。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgeabii
系列文章
更多 icon
同类精品
更多 icon
继续加载