python-miio
更新于 2026-10-31 10:27:09 · 创建于 2026-10-31 10:27:06
这是什么
python-miio 是米家生态里最底层、也最绕不开的一块基础设施:一个用来跟小米设备通信的 Python 库 + 命令行工具 miiocli。
它同时吃两套协议:
- miIO——老设备的二进制协议(扫地机、老款净化器、插座、风扇……)
- MIoT——2019 年之后新设备用的那套(基于 siid/piid 的服务-属性模型,即 miot-spec)
两者关系一句话:老设备靠一个个手写的设备类(roborockvacuum、fan、chuangmiplug…)支持,新设备靠 genericmiot 按 miot-spec 自动适配——后者只要能读到设备的 spec,理论上所有 MIoT 设备通吃。
再说一句它为什么重要:Home Assistant 官方的 xiaomi_miio 集成(扫地机、灯、风扇、插座、红外遥控、PM2.5 传感器、网关报警、WiFi 中继)底层跑的就是这个库。你在 HA 里点"启动清扫"、"调到 60% 亮度",最终落到设备上的指令是 miiocli 背后那套代码发出去的。
安装(这里有个大坑,先说)
pip install python-miio
装完之后你会发现一个问题:PyPI 上最新的正式版还是 0.5.12,发布于 2022-07-18。而仓库的 master 分支一直在动,最新提交是 2026-07-25(genericmiot: add metadata command and cgllc-spec namespace)。
所以分两种情况:
| 你的设备 | 该怎么装 |
|---|---|
| 老 miIO 设备(扫地机、老净化器、插座…) | pip install python-miio 的 0.5.12 就够用 |
新 MIoT 设备(要靠 genericmiot) |
必须装预发布版或 git 版,见下 |
# 预发布版(0.6.0.dev0)
pip install --pre python-miio
# 或者直接 master
pip install git+https://github.com/rytilahti/python-miio.git
README 里明确写了:项目正在进行一次大规模重构(issue #1114),在 0.6.0 正式发布之前,想控制现代 MIoT 设备就得用 git 版或 --pre。这个坑不提前说,很多人装完 0.5.12 发现 miiocli genericmiot 根本不存在。
第一步:拿到 token
miiocli 的一切操作都要 --ip 和 --token 两个参数。库自己带了一条龙服务(底层调 micloud):
miiocli cloud
Username: example@example.com
Password:
输出长这样:
== name of the device (Device offline ) ==
Model: example.device.v1
Token: b1946ac92492d2347c6235b4d2611184
IP: 192.168.xx.xx (mac: ab:cd:ef:12:34:56)
DID: 123456789
Locale: cn
设备名后面那个 (Device offline ) 是云端记录的在线状态,跟你现在能不能连上没关系——它只是小米云最后一次看到它的状态。
登录小米云容易翻车(验证码额度、区域、AdGuard 拦截之类),所以还有一条更稳的路:用 Xiaomi Cloud Tokens Extractor 这种专门工具把 token 批量导出来,再喂给 miiocli。两者不冲突,作者在 README 里也把它列在相关项目里。
摸清设备底细:info
拿到 IP + token 之后,先不管支不支持,这条命令对任何 miIO/MIoT 设备都有效:
miiocli device --ip 192.168.1.50 --token <token> info
Model: rockrobo.vacuum.v1
Hardware version: MW300
Firmware version: 1.2.4_16
Supported using: RoborockVacuum
Command: miiocli roborockvacuum --ip 127.0.0.1 --token 00000000000000000000000000000000
Supported by genericmiot: True
信息量很大,三行要重点看:
Model—— 真实型号字符串,比 App 里那个营销名称靠谱得多Command—— 直接告诉你该用哪个子命令,不用自己猜(老设备走这条)Supported by genericmiot: True—— 说明这台设备也能用通用的 MIoT 接口控制,多一个选择
控制新设备:genericmiot
genericmiot 的聪明之处在于,它不硬编码功能,而是去下载这台设备的 miot-spec 文件(首次使用自动下载并缓存),然后按 spec 里定义的 service / property / action 动态生成命令。
四个常用子命令:status / set / actions / call。
看状态
miiocli genericmiot --ip 192.168.1.60 --token <token> status
Service Light (light)
Switch Status (light:on, access: RW): False (<class 'bool'>, )
Brightness (light:brightness, access: RW): 60 % (<class 'int'>, min: 1, max: 100, step: 1)
Power Off Delay Time (light:off-delay-time, access: RW): 1:47:00 (<class 'int'>, min: 0, max: 120, step: 1)
注意它顺手把可写属性(access: RW)的取值范围也打出来了——min: 1, max: 100, step: 1。这就是写脚本时最需要的元数据,不用去翻 spec 网站。
改设置
miiocli genericmiot --ip 192.168.1.60 --token <token> set light:brightness 0
[{'did': 'light:brightness', 'siid': 2, 'piid': 3, 'code': 0}]
code: 0 就是成功。参数用的是 service:property 这种点分标识,跟 status 里括号内的名字一模一样。
列动作 + 执行
miiocli genericmiot --ip 192.168.1.60 --token <token> actions
Light (light)
light:toggle Toggle
light:brightness-down Brightness Down
light:brightness-up Brightness Up
miiocli genericmiot --ip 192.168.1.60 --token <token> call light:toggle
{'code': 0, 'out': []}
属性是"设成某个值",动作是"触发某个行为"——灯开关这种语义上属于动作,改亮度属于设属性。
控制老设备:专用子命令
老设备的命令按品类拆开,每个模块的功能不一样:
miiocli roborockvacuum --help
Usage: miiocli roborockvacuum [OPTIONS] COMMAND [ARGS]...
Commands:
add_timer Add a timer.
...
有两个实用技巧:
1. 每次调用都会自动探测型号,靠的是向设备发一次 info 查询。但如果设备没连上云端,这一步可能直接报错。
2. 手动指定型号可以跳过探测:
miiocli roborockvacuum --model roborock.vacuum.s5 --ip <ip> --token <token> start
设备云连接关掉(或者你刚把它从米家 App 里删了)的时候,这条能救命。
排错:把日志打开
miiocli -d ... # debug
miiocli -dd ... # 更啰嗦
协议层的问题(token 错、型号探测失败、值超范围被拒)基本都得靠这个看。更详细的排错清单在 文档的 Troubleshooting 页。
另外 CLI 支持 -o json / -o json_pretty,用来写脚本比解析默认输出舒服得多:
miiocli -o json genericmiot --ip <ip> --token <token> status
当库用:三行代码接管设备
CLI 之外,它本质上是个 Python 库。最省事的入口是 DeviceFactory——它会先 info 探测型号,再自动构造对应的设备类:
from miio import DeviceFactory
dev = DeviceFactory.create("192.168.1.50", "<token>")
print(dev.status())
想做一个"不挑设备型号"的通用面板,就看这三个内省方法:
sensors()—— 有哪些传感器settings()—— 有哪些可改的设置actions()—— 有哪些可执行动作
它们返回的是设备描述符对象(descriptors),里面带着类型、取值范围、单位这些元数据,足够你自动生成 UI 或者写通用脚本。这是 HA 那种"一套代码支持上百款设备"的做法。
注意:不是所有老设备都写了 descriptors,缺的可以补 PR——作者说补起来不复杂。
没设备也能开发:自带模拟器
miiocli 内置了 miIO 和 MIoT 两套模拟器。你要给这个生态写工具、或者想给项目提 PR 但手上没那台设备,直接在模拟器上跑就行,不用真机。
支持范围
- 所有 MIoT 设备:通过
genericmiot,只要有 miot-spec 就支持 - 老 miIO 设备:一大票专用模块,覆盖扫地机(小米 V1/S4/S5/S6/S7、石头、追觅、云米)、空调伴侣、净化器(含 air dog)、加湿器、电风扇(V2/V3/SA1/ZA/P 系一大串)、插座、插排、摄像机、Yeelight 系列、Philips 灯具、红外遥控、净水器、电饭煲、PM2.5 检测仪、加湿器、电暖器、扫地拖一体机、宠物饮水机、走步机、咖啡机、智能马桶盖、16 路继电器模块……
基本是"米家有的它都想支持",README 里那张清单长到要滑好几屏。
谁在用它
Home Assistant 官方集成(这是最大用户):
| HA 平台 | 管什么 |
|---|---|
vacuum.xiaomi_miio |
小米扫地机 / 石头 |
light.xiaomi_miio |
Philips 灯具 |
fan.xiaomi_miio |
净化器、加湿器、电风扇 |
switch.xiaomi_miio |
插座、插排 |
remote.xiaomi_miio |
万能红外遥控 |
sensor.xiaomi_miio |
PM2.5 检测仪 |
alarm_control_panel.xiaomi_miio |
网关报警 |
device_tracker.xiaomi_miio |
WiFi 中继 |
第三方 HA 组件也一堆建在它上面:hass-xiaomi-miot(al-one,MIoT 全家桶)、xiaomi_miot_raw(ha0y)、xiaomi_airconditioningcompanion、xiaomi_fan、xiaomi_cooker 等。
生态周边:dustcloud(逆向/root 小米设备)、Valetudo(免云固件)、micloud(云接口库)、micloudfaker(假云服务器,用来在断外网时修插排状态查询)。
几个需要知道的问题
- 正式版停在 2022 年。
0.5.12之后四年没有正式发布,MIoT 相关能力全在 master 和0.6.0.dev0上。装库的时候先想清楚要哪个版本,不然会怀疑人生。 - 316 个 open issue。社区项目、维护者精力有限,新设备支持基本靠用户提 PR——想加设备的话,那个模拟器就是给你准备的工具。
- 必须同网段直连。
miiocli走的是局域网,跨 VLAN / 跨子网要自己放通;出门在外想控制,需要靠 HA + 反代/组网那一套(比如 Tailscale)。 - IP 变了就断。token 不变但 IP 会变,在路由器上给设备做静态 DHCP 绑定是标配动作,否则脚本隔几天就失效。
- 协议的"值"很严格。改设置时超出
min/max会被设备直接拒掉,status里打出来的范围就是准的。 - GPL-3.0。当命令行工具用无所谓,但如果把库嵌入自己的产品,GPL 的传染性要提前评估——想做闭源商业产品的话这一步别跳过。
一句话总结
米家设备的"驱动层":miiocli 给命令行玩家,miio 库给开发者,genericmiot 让新设备免写代码就能控制——HA 里所有小米集成的能力边界,基本就是这个库的能力边界。老设备装 0.5.12,新设备记得上 --pre。