起因
我现在主要用的设备是苹果的,用了一些智能家居设备,都使用苹果的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。