起因
我现在主要用的设备是苹果的,用了一些智能家居设备,都使用苹果的home控制。现在我用的小米直流变频风扇1X,只能在米家上使用。像使用siri能控制但不好用,home也不能用。
实现思路
通过万能的搜索,可以知道有homeassistant、homebridge这两个开源智能家居系统。去年我尝试使用homeassistant,看它的文档没搞明白我需要怎么做才能添加自定义组件。当然,我只是想用苹果home控制小米的设备,不想搞这么冗余的项目。 so,我就自己搞一个吧。 要实现苹果home控制小米的设备,需要搞定两部分
- 模拟出一个苹果的homekit设备
- 通过code可以控制小米的设备。
实现功能
控制小米设备
小米的智能家居设备,有一套miio的控制协议。通过这个规范,就可以方便的与设备通信。在github上我找到了现成的开源库python-miio,并支持1X风扇。
通过python-miio控制小米设备,需要有小米设备的ip、token。ip直接从路由器获得,获取token,我是用的charles抓了米家的包。
看python-miio项目的说明,直接实例一个风扇的对象,就可以通过api控制风扇。
小米1X风扇,对应的model类型是dmaker.fan.p5,我看源码上,Fan实例时有model参数,我就直接设置为了dmaker.fan.p5,以为它是自动根据这个类型使用FanP5的实例。结果一直提示user ack timeout,于是我就换了各种方法,cli命令。怎么都不行。最后是在cli命令上,看到有FanP5的类型,试了下,ok。才发现是我用错了。
展示下控制小米风扇的代码
from miio.fan import FanP5, OperationMode, MoveDirection
def test(): fan = FanP5(ip="192.168.1.1", token="bdae31092379167c30228549fd53137d") print(fan.info()) print(fan.status()) fan.on() # 设置模式 自然风OperationMode.Nature 直吹风OperationMode.Normal print(fan.set_mode(OperationMode.Nature))
# 设置风速 0-100 print(fan.set_speed(50)) # 设置摆头角度[30, 60, 90, 120, 140] print(fan.set_angle(60)) # 设置打开摇头 print(fan.set_oscillate(False)) # 设置指示灯 print(fan.set_led(False)) # 设置提示音 print(fan.set_buzzer(False)) # 设置童锁 print(fan.set_child_lock(False)) # 定时关闭 分钟 # print(fan.delay_off(99)) # 向左、向右移动 -5、+5 print(fan.set_rotate(MoveDirection.Left)) print(fan.status())test()模拟苹果homekit设备
同样也是在github找实现了HomeKit Accessory Protocol (HAP)的开源项目,我选用了HAP-python.
苹果的homekit预定义了各种设备,设备称作service,设备的功能称作characteristics。 设备信息、具体的功能,可以进HAP-python的项目资源查看。 我用的设备定义是Fanv2,有开关、调速、扇页旋转方向、摇头、童锁。 小米风扇1X的功能比苹果定义的风扇多,由于苹果的限制,我只能让苹果home控制风扇的主要功能。
使用HAP-python,需要继承Accessory,然后为各个功能设置使用的方法就可以。
class MiFan(Accessory): """代理小米风扇,实现homekit风扇设备"""
category = CATEGORY_FAN
def __init__(self, param, *args, **kwargs): super().__init__(*args, **kwargs) #初始化小米设备 self.fan = FanP5( ip=param.host, token=param.token )
mi_fan = self.add_preload_service('Fanv2', chars=['Name', 'Active', 'RotationSpeed', 'SwingMode', 'LockPhysicalControls', 'RotationDirection']) info = self.fan.info() logger.info(info) self.set_info_service( manufacturer='Xiaomi', model=info.model, firmware_revision=info.firmware_version, serial_number='1' )
mi_fan.configure_char('Name', value='Mi Fan') # 设备开关 mi_fan.configure_char('Active', setter_callback=self.set_power, getter_callback=self.get_power) # 风扇速度 mi_fan.configure_char('RotationSpeed', setter_callback=self.set_speed, getter_callback=self.get_speed) # homekit定义是旋转方向,这个配置成直吹风\自然风 mi_fan.configure_char('RotationDirection', setter_callback=self.set_mode, getter_callback=self.get_mode) # 是否摇头 mi_fan.configure_char('SwingMode', setter_callback=self.set_oscillate, getter_callback=self.get_oscillate) # 童锁 mi_fan.configure_char('LockPhysicalControls', setter_callback=self.set_child_lock, getter_callback=self.get_child_lock)
def set_mode(self, value): if value == 1: self.fan.set_mode(OperationMode.Nature) else: self.fan.set_mode(OperationMode.Normal)
def get_mode(self): return int(self.fan.status().mode == OperationMode.Nature)
def set_speed(self, value): self.fan.set_speed(value)
def get_speed(self): return self.fan.status().speed
def set_oscillate(self, value): self.fan.set_oscillate(bool(value))
def get_oscillate(self): return int(self.fan.status().oscillate)
def get_power(self): return int(self.fan.status().is_on)
def set_power(self, value: int): if value == 1: self.fan.on() else: self.fan.off()
def set_child_lock(self, value): self.fan.set_child_lock(bool(value))
def get_child_lock(self): return int(self.fan.status().child_lock)搞定实现后,加上启动类可以用了
def main(args): import logging import signal from pyhap.accessory_driver import AccessoryDriver
logging.basicConfig(level=logging.INFO)
driver = AccessoryDriver(port=51826) accessory = MiFan(args, driver, 'Fanv2') driver.add_accessory(accessory=accessory)
signal.signal(signal.SIGTERM, driver.signal_handler) driver.start()运行程序,会在终端上打印出homekit的二维码和数字码,用手机添加就ok。
同时会生成一个accessory.state文件。当你再次启动程序,会使用这个文件信息直接启动设备,不会在提示添加到home。需要重新添加设备时,删除accessory.state
效果
主控制界面,可以开关风扇、调节速度。扇叶旋转方向被我设置成了小米风扇的直吹风、自然风模式。

摇头和童锁功能是正常的。

结尾
我用python-miio和HAP-python两个库搞定了苹果home控制小米的风扇,主要功能都可以用。 用到的代码,我放到了github上https://github.com/jianyun8023/homekit-diy。