CLI tool
rytilahti/python-miio avatar
rytilahti/python-miio

python-miio: controlling Xiaomi devices over miIO and MIoT from Python

Python library & console tool for controlling Xiaomi smart appliances

4,309 stars600 forksPythonGPL-3.0

At a glance

What is it?
python-miio is a community library and miiocli console tool for Xiaomi appliances that speak miIO or MIoT. It is aimed at developers and tinkerers who want local control, not at people looking for a polished app.
Who is it for?
Adopt python-miio if you already know your device tokens and want scripted or local control of Xiaomi hardware, especially through the genericmiot integration for modern devices. Skip it if you want a graphical app, or if your device model is not in the supported list and no genericmiot spec exists for it.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 67 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap python-miio fills between Xiaomi hardware and local scripts

Xiaomi appliances talk over two protocols: the older miIO and the newer MIoT. The official app is the intended way to drive them, and it assumes a cloud account, a phone, and the vendor's own interface. python-miio takes a different position. It is a Python library plus a console tool, miiocli, that speaks both protocols directly to the device on your network, given its IP address and token. The README is explicit that this is "a voluntary, community-driven effort" with no affiliation to the companies whose devices it supports, which sets expectations about support channels and release cadence.

The audience is narrow on purpose. If you write Python, run a home automation stack, or want to schedule a vacuum or a fan from a cron job, this is the layer you would build on. If you want a phone app, it is not for you. The library also underpins integrations elsewhere: the repository lists Home Assistant among its topics and its projects using this library. That is the real signal about who this is for. Most people meet python-miio indirectly, through something else that imports it.

Two protocols, two code paths: miIO modules versus genericmiot

The architecture splits along protocol lines, and the split matters more than any single API call.

Older miIO devices are handled by per-model modules. The README names roborockvacuum and fan as examples. Each module exposes its own set of commands, so a vacuum gets add_timer and a fan gets fan-specific settings. Support here is hand-written per device family, which means coverage is uneven: a model is either implemented or it is not.

Modern MIoT devices go through the genericmiot integration instead. Rather than hand-coding each model, it downloads a device model specific "miot spec" file, caches it locally, and derives the available features from that description. The README describes the result: common commands status, set, actions and call work across devices that have a spec, without a dedicated module. Properties are addressed by namespaced identifiers such as light:brightness, and status output annotates each one with its access mode, type and range, for example access: RW, min: 1, max: 100, step: 1.

That design is the interesting part. It moves device support from code to data. The cost is a first-run download and a dependency on the spec being accurate for your model. The README notes the spec file is downloaded and cached locally on first use, so an offline machine or a model with no spec will not work through this path.

Installing python-miio and reading your first device

The stable release installs from PyPI. The README gives this as the primary path.

bash
pip install python-miio

If you intend to control a modern MIoT device, the README is blunt: you want the git version or a pre-release until 0.6.0 is released, because the MIoT support is part of an ongoing refactoring effort.

bash
pip install --pre python-miio

The package requires Python 3.11 or newer according to pyproject.toml, and installs three console scripts: miiocli, mirobo and miio-extract-tokens. The next step is obtaining tokens. The README's simplest route is the cloud command, which uses the micloud dependency to fetch them from your account.

bash
miiocli cloud

You will be prompted for a username and password, and the output lists each device with its model, token, IP, MAC, DID and locale. Treat that output as a secret: the token is the credential that lets anything on your network command the device.

With a token in hand, ask the device what it is. This works even for models the library does not support yet.

bash
miiocli device --ip <ip> --token <token> info

The output includes Model, Hardware version, Firmware version, and a Supported using field naming the module to use. It also prints a Command line you can copy, and a Supported by genericmiot flag. That last line is the decision point: if it reads True, you can drive the device with genericmiot rather than hunting for a dedicated module.

For a MIoT device, status is the first real command. It prints services and their properties with access modes and accepted ranges.

bash
miiocli genericmiot --ip <ip> --token <token> status

Writing a value uses the namespaced property name shown in that output. The README's example sets brightness to 0.

bash
miiocli genericmiot --ip <ip> --token <token> set light:brightness 0

The response is a list of result objects carrying did, siid, piid and code. A code of 0 indicates success in the README's examples. Actions work the same way: list them, then call one by name.

bash
miiocli genericmiot --ip <ip> --token <token> actions
miiocli genericmiot --ip <ip> --token <token> call light:toggle

Every command accepts --help, which is how you discover subcommands and options rather than guessing them.

Where python-miio gets in your way

The token requirement is the first wall. There is no pairing flow in the library itself. You either pull tokens from the cloud with miiocli cloud, or follow the discovery documentation for other extraction routes, which include an Android backup path behind the backup_extract extra. On recent Android versions that route is constrained by how backups work, and the README does not promise it will succeed on every setup.

The second wall is model coverage. Older devices depend on dedicated modules, so an unsupported model simply has no commands. The info command will tell you the truth here, and it is worth running before writing any code. If Supported by genericmiot is False and no module matches, you are out of luck with the stock library.

Third, MIoT support is not in a stable release. The README tells readers to use the git version or a pre-release until 0.6.0 ships, and the most recent release listed is 0.6.0.dev0 from 2024-03-13. The last push to the repository was on 2026-07-25, so work continues, but anyone pinning to a stable version from PyPI will not get genericmiot. That is a real deployment constraint, not a footnote.

Finally, this is a command-and-control library, not a state manager. It does not poll your devices in the background, keep history, or reconcile desired state. Each invocation is a request to a device on your LAN. If the device is offline, the call fails. If you want automation logic, you build it or you use a platform that imports this library.

python-miio compared with python-roborock

The related searches pair python-miio with python-roborock, and the difference is scope rather than quality. python-miio covers a broad set of Xiaomi appliances across two protocols: vacuums, fans, lights and whatever else has a module or a MIoT spec. That breadth is the point, and it is also why per-device depth varies.

python-roborock is a narrower library aimed at Roborock vacuums specifically. The trade is depth for breadth: a project focused on one vendor line can track that line's firmware changes and device quirks more closely than a general library can, at the cost of not controlling your Xiaomi fan or light. python-miio does include Roborock support, with a roborockvacuum module and a mirobo console script, so the two overlap on vacuums. Where they diverge is everything else.

If your fleet is entirely Roborock, a dedicated library is a reasonable default and python-miio is the fallback. If you have mixed Xiaomi hardware and want one dependency, python-miio is the one that spans the set. Neither choice removes the token requirement.

Licence, packaging and the cost of keeping up

python-miio is GPL-3.0-only, as declared in pyproject.toml and the LICENSE file. That is a copyleft licence, and it is worth understanding before you embed the library in a product. If you distribute software that links against or bundles python-miio, the GPL's terms attach to that distribution. Using it as a separate command-line tool that your own code invokes is a different situation from importing it into a closed-source application. This is a description of the licence, not legal advice; if the distinction matters for your product, get it reviewed.

The dependency list is moderate and mostly uncontroversial: click, cryptography, construct, zeroconf, attrs, platformdirs, tqdm, micloud, croniter, defusedxml, pydantic and PyYAML. The construct pin is capped below 3, and zeroconf below 1, so major-version jumps in those libraries will require upstream changes before you can upgrade. Python 3.11 is the floor, which rules out older distributions that still ship 3.9 or 3.10.

Upgrade cost is dominated by the MIoT refactoring. Until 0.6.0 is released, anyone using genericmiot is tracking a development branch, which means API surface can move. The CHANGELOG.md file at the repository root is where release notes live; the README does not document a rollback procedure for a bad upgrade, so pin your version and test against your actual devices before moving.

Editorial conclusion

Adopt python-miio if you already know your device tokens and want scripted or local control of Xiaomi hardware, especially through the genericmiot integration for modern devices. Skip it if you want a graphical app, or if your device model is not in the supported list and no genericmiot spec exists for it. Before committing, verify three things: that your model appears in the supported devices list, that miiocli device --ip <ip> --token <token> info reports a usable command, and whether you need pip install --pre python-miio because the MIoT work has not shipped in a stable 0.6.0 release yet.

Frequently asked questions

How do I integrate my Xiaomi Home with Home Assistant?

The repository lists home-assistant among its topics and Home Assistant among the projects using this library, so the integration path runs through a component that imports python-miio rather than through python-miio itself. The README documents the library and the miiocli console tool, not a Home Assistant setup procedure.

What is Mi Home used for?

The README frames the official app as the vendor's own interface to the same appliances python-miio controls over miIO and MIoT. python-miio is an independent, community-driven alternative that talks to the device directly using its IP address and token, and it is not affiliated with the companies whose devices it supports.

What smart home appliances does Xiaomi offer?

The README names Roborock vacuums and fans as examples of supported device families, and the genericmiot integration covers modern MIoT devices that have a spec file, including lights with properties such as light:brightness and light:on. The repository maintains a supported devices list for the full set.

Official sources

  1. License: GPL-3.0
  2. Project website
  3. README
  4. Releases
  5. rytilahti/python-miio on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/rytilahti-python-miio.svg)](https://hysenlabs.com/projects/rytilahti-python-miio)