Skip to main content

Passwordless QR login to the official Xiaomi cloud: extract per-device miIO tokens / BLE keys and control cloud IR remotes (TV / A-C / fan / DIY)

Project description

mihome-ctl

Passwordless QR login to the official Xiaomi cloud — extract every device's miIO token / local IP / BLE beacon-key, and control cloud IR remotes (TV / air-conditioner / fan / DIY on-off) through your home's parent blaster (e.g. a Xiao AI speaker). No local hardware, no Home Assistant required.

  • Talks only to official hosts: account.xiaomi.com + {region}.api.io.mi.com
  • Supports the tw / sg regions (python-miio / micloud have no tw locale)
  • Produces per-device token + local IP + BLE key
  • Passwordless (QR); secrets written with chmod 600

CI  ·  Docs: https://daviddwlee84.github.io/mihome-ctl/  ·  中文說明見文件站

A thin wrapper over the Xiaomi-cloud-tokens-extractor connector (MIT, vendored + trimmed into mihome_ctl/connector.py, see THIRD_PARTY_LICENSES/) plus a cloud-IR control layer.

Install

uv tool install mihome-ctl          # or: pipx install mihome-ctl
# From source:
uv sync && uv run mihome-ctl --help

Optional extras:

uv tool install 'mihome-ctl[verify]'   # verify: LAN token check (python-miio)
uv tool install 'mihome-ctl[mcp]'      # MCP server (for Claude / agents)

Claude integration — skill + MCP (one step)

After installing, wire up the agent skill and MCP server in one command:

mihome-ctl setup            # lists what it will do, asks [y/N], then installs the skill + registers the MCP
mihome-ctl setup -y         # skip the confirmation prompt (non-interactive)
mihome-ctl setup --project  # install into ./.claude instead of the user dir
mihome-ctl setup --npx      # install the skill via `npx skills add` (vercel-labs/skills) instead
mihome-ctl setup --dry-run  # preview what it would do, write nothing
mihome-ctl setup --uninstall  # remove the skill + unregister the MCP (also honors -y / --dry-run)

setup ships the skill inside the wheel, so the default path needs no Node — it copies SKILL.md locally and runs claude mcp add mihome-ctl -- mihome-ctl-mcp (or prints the config if the claude CLI isn't found). So the whole onboarding is:

uv tool install 'mihome-ctl[mcp]' && mihome-ctl setup
  • Agent Skill mihome-ir — lets Claude control the TV / A-C / fan by voice-style requests. Also installable directly: npx skills add daviddwlee84/mihome-ctl --skill mihome-ir.
  • MCP server mihome-ctl-mcp — exposes list_remotes / list_keys / ir_send / ir_ac as MCP tools (reuses the QR session cached by mihome-ctl ir).

Usage

mihome-ctl extract               # QR login, extract tokens (scans tw sg cn)
mihome-ctl extract --server tw sg   # specific regions (space-separated, not repeated flags)
mihome-ctl list                  # reprint last result offline
mihome-ctl verify --did <DID>    # LAN-verify one device (needs [verify])

mihome-ctl ir                    # list cloud miir.* remotes + parent blaster
mihome-ctl ir-send --remote <name> --key VOL+ [--repeat 3]
mihome-ctl ir-send --remote <name>            # omit --key to list a remote's keys
mihome-ctl ir-ac --temp 26 --mode cool        # absolute A/C control (state-based)
mihome-ctl ir-ac --off | --status
mihome-ctl ir-code --matchid xm_1_199         # IRDB matchid → per-key Pronto (see notes)

On first run a QR is drawn in the terminal (or open http://127.0.0.1:31415) — scan once with the Mi Home app; the session is cached in the state dir's mi-session.json, so subsequent runs skip the scan. Use --relogin to force a re-login.

State directory

Resolved in this order (secret filenames: mi-tokens.json / mi-session.json / mi-ir.json / devices.md):

  1. MIHOME_CTL_HOME environment variable
  2. the nearest ./.secrets/ walking up from the cwd (convenient when embedded as a submodule inside another repo)
  3. otherwise platformdirs user state dir

All secrets are written with mode 0600.

Architecture — one core, many front-ends

mihome_ctl.core is a UI-agnostic layer (connector, cloud API, IR codec, operations) that only does work and returns structured data. Everything on top is a thin presentation layer:

  • mihome_ctl.commands + __main__ — the Tyro CLI (commands above)
  • mihome_ctl.mcp_server — an MCP server (mihome-ctl-mcp, needs [mcp])
  • a future TUI would be one more presentation layer over the same core

ir-code and licensing (important)

ir-code decodes a Xiaomi IRDB matchid into Pronto: base64 → AES-128-ECB → gzip → microsecond timings → Pronto. The decoder is a clean-room implementation (from the public protocol, using pycryptodome), so this package contains no AGPL code, vendors nothing AGPL, and downloads no AGPL tool at runtime — it stays cleanly MIT.

Limitation (stated honestly): the public {region}-urc.io.mi.com/controller/code/1 endpoint currently requires a Mi Home app signature (anonymous requests return status:19), so fetching codes online by matchid is experimental. The decoder itself is verified by a round-trip test. To use an external IRDB tool (e.g. the AGPL-licensed ysard/mi_remote_database), install it yourself and opt in — this package deliberately does not depend on or bundle it (core/ircodec/base.py keeps an IRCodecBackend extension point for an external backend).

Development

uv sync --extra verify --extra mcp
uv run pytest -q
uv run ruff check . && uv run ruff format --check .

Releasing

Publishing is automated: cut a GitHub Release tagged vX.Y.Z (matching the pyproject.toml version) and .github/workflows/release.yml builds and uploads to PyPI via Trusted Publishing (OIDC — no stored token). One-time PyPI setup instructions are in the workflow header.

License

MIT (see LICENSE). The bundled Xiaomi connector derives from an upstream MIT project — see THIRD_PARTY_LICENSES/.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mihome_ctl-0.3.0.tar.gz (48.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mihome_ctl-0.3.0-py3-none-any.whl (41.4 kB view details)

Uploaded Python 3

File details

Details for the file mihome_ctl-0.3.0.tar.gz.

File metadata

  • Download URL: mihome_ctl-0.3.0.tar.gz
  • Upload date:
  • Size: 48.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for mihome_ctl-0.3.0.tar.gz
Algorithm Hash digest
SHA256 003a60fd3c9a7568441fb1fa085f21843a2ce27ecb744f4ad195781415e81411
MD5 578a49e01a5409f7bf2c180d7f9e2ed0
BLAKE2b-256 d3c0220c2f8b97464e34bf5e9c9074050ad87ce2d06f22b68061247bcdcf7c5b

See more details on using hashes here.

File details

Details for the file mihome_ctl-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: mihome_ctl-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 41.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for mihome_ctl-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d8b2f933f752187de0629fc483329c2813512ec08eebbc81dcab16be3c0ad93e
MD5 6dff028041dc45c92836661a4225d55b
BLAKE2b-256 b89bf8805b5ae95dde3dc32c7a41727701840b1bb34a86253fe7418b6fb2de6f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page