MiService

July 24, 2026 · View on GitHub

中文 | English

PyPI License

XiaoMi Cloud Service for mi.com — A Python library and CLI for Xiaomi Cloud services.

Supports Xiaomi account login (with OTP two-factor authentication), MiIO/MIoT device control, and MiNA XiaoAi Speaker TTS broadcast.

Features

  • Xiaomi account login and service token management (supports SMS/Email OTP two-factor authentication)
  • MiIO protocol device control (property read/write, action invocation)
  • MIoT Spec interface documentation queries (miot-spec.com, supports text/python formatted output (raw dict by default))
  • MiNA XiaoAi Speaker control: TTS broadcast, volume, playback control, status queries, AI response retrieval
  • Direct LAN device control (MiIOLocalService), no cloud account needed
  • CLI tool miservice for one-line device operations; also supports python -m miservice
  • Zero hard dependencies: falls back to built-in biohttp when aiohttp isn't installed; falls back to a built-in pure-Python AES when pycryptodome isn't installed

Installation

pip3 install miservice

# Optional: install aiohttp for better async HTTP performance
pip3 install aiohttp

# Optional: install pycryptodome for a faster AES implementation (used by MiIOLocalService; falls back to a built-in pure-Python implementation otherwise)
pip3 install pycryptodome

Requires Python 3.8+.

Library Structure

MiService: XiaoMi Cloud Service
  |
  |-- MiAccount: Account login and token management
  |     |-- Username/password login
  |     |-- OTP two-factor authentication (SMS/Email)
  |     |-- Service token persistence (~/.mi.token)
  |
  |-- MiIOService: MiIO service (sid=xiaomiio)
  |     |-- MiIO protocol requests (signing/encryption)
  |     |-- MIoT property get/set/action invocation
  |     |-- Device list queries
  |     |-- Home/room hierarchy queries
  |     |-- MIoT Spec interface documentation queries
  |     |-- MIoT data decryption
  |
  |-- MiNAService: MiAI service (sid=micoapi)
  |     |-- XiaoAi Speaker device list
  |     |-- TTS broadcast / volume control
  |     |-- Playback control (pause/stop/resume/URL play/single-track loop)
  |     |-- Playback status queries
  |     |-- Latest AI response retrieval
  |     |-- Auto-detection of device models (some models use play_music API)
  |
  |-- miio_command: MiIO command-style interface
  |
  |-- MiIOLocalService: Direct LAN device control (no cloud account needed)
  |     |-- Property get/set
  |     |-- Raw miIO method invocation
  |
  |-- aes: Built-in pure-Python AES-128-CBC (fallback used when pycryptodome isn't installed, backs miiolocal)
  |
  |-- local_command: Local device command-style interface

Environment Variables

VariableRequiredDescription
MI_USERYesXiaomi account username
MI_PASSYesXiaomi account password
MI_DIDNoDevice ID or device name (required when operating devices; also used by MiNA device-level commands to locate the target speaker)
MI_LOCALNo<IP>:<Token>; when set, commands go directly over the LAN instead of the cloud, no MI_USER/MI_PASS/MI_DID needed

CLI Usage

MiService 3.0.2 - XiaoMi Cloud Service

Usage: The following variables must be set:
           export MI_USER=<Username>
           export MI_PASS=<Password>
           export MI_DID=<Device ID|Name>

Get Props: miservice <siid[-piid]>[,...]
           miservice 1,1-2,1-3,1-4,2-1,2-2,3
Set Props: miservice <siid[-piid]=[#]value>[,...]
           miservice 2=60,2-1=#60,2-2=false,2-3="null",3=test
Do Action: miservice <siid[-piid]> <arg1|[]> [...]
           miservice 2 []
           miservice 5 Hello
           miservice 5-4 Hello 1

Call MIoT: miservice <cmd=prop/get|/prop/set|action> <params>
           miservice action '{"did":"267090026","siid":5,"aiid":1,"in":["Hello"]}'

Call MiIO: miservice /<uri> <data>
           miservice /home/device_list '{"getVirtualModel":false,"getHuamiDevices":1}'

Devs List: miservice list [name_keyword|full] [getVirtualModel=false|true] [getHuamiDevices=0|1]
           miservice list Light true 0
           miservice list full

Home List: miservice home [name_keyword|full]
           miservice home
           miservice home full
           miservice home 我的家

MIoT Spec: miservice spec [model_keyword|type_urn] [text|python]
           miservice spec
           miservice spec speaker
           miservice spec xiaomi.wifispeaker.lx04
           miservice spec xiaomi.wifispeaker.lx04 text
           miservice spec urn:miot-spec-v2:device:speaker:0000A015:xiaomi-lx04:1

MIoT Decode: miservice decode <ssecurity> <nonce> <data> [gzip]

MiNA Commands:
           miservice mina            # List MiNA devices
           miservice mina <text>     # TTS broadcast to all devices
           miservice mina pause      # Pause playback
           miservice mina stop       # Stop playback
           miservice mina play       # Resume playback
           miservice mina play <url> # Play audio from URL
           miservice mina loop <url> # Play URL on single-track loop
           miservice mina volume <n> # Set volume (0-100)
           miservice mina status     # Get playback status
           miservice mina ask        # Get latest AI response

Local Device (no cloud account, direct LAN control):
           export MI_LOCAL=<IP>:<Token>

Get Props: miservice <prop>[,...]
           miservice power,brightness
Set Props: miservice <prop=value>[,...]
           miservice power=on,brightness=80

Call Method: miservice /<method> [params_json]
             miservice /miIO.info
             miservice /set_power '["on"]'

You can also run python -m miservice with the same arguments as the miservice command.

Debug Logging

Control the log level with the -v flag (0–5):

miservice -v5 list        # DEBUG level
miservice -v2 list        # ERROR level
miservice -v3 list        # WARN level
miservice list            # Default WARNING level

Examples

1. Set Account

export MI_USER=<Username>
export MI_PASS=<Password>

2. Query Device List

miservice list

Displays the list of devices under your account, including name, model, DID, and token.

3. Set DID

export MI_DID=<Device ID|Name>

The DID comes from the device list query result, or you can use the device name directly.

4. Query Device Interface Documentation

miservice spec xiaomi.wifispeaker.lx04 text

Queries the MIoT interface capabilities of the device, categorized into property get, property set, and action invocation. Omitting text/python returns the raw spec dict as-is instead of a formatted view.

5. Query Volume Property

miservice 2-1

2 is the siid, 1 is the piid (if piid is 1, it can be omitted). These can be found in the spec interface description.

6. Set Volume Property

miservice 2=#60

The value type depends on the interface documentation:

  • # forces a text type; you can also use single quotes ' and double quotes " to force text type (single or paired quotes work)
  • Without a type hint, the value is auto-detected; possible results are JSON null, false, true, integer, float, or text

7. Action Invocation: TTS Broadcast and Execute Text

The following command makes the XiaoAi Speaker say "Hello":

miservice 5 Hello

Here 5 is the siid, and the aiid is omitted (defaults to 1).

The following command is equivalent to saying "XiaoAi, check the weather" to the speaker:

miservice 5-4 "Check the weather" 1

Here 1 means the device should respond verbally. To execute silently (no speaker response):

miservice 5-4 "Turn off the light" 0

If there are no arguments, pass [] as a placeholder.

8. XiaoAi Speaker Control (MiNA)

miservice mina provides TTS broadcast and playback control for XiaoAi Speakers. Without arguments, it lists MiNA devices:

miservice mina                      # List MiNA devices

Send TTS broadcast to all XiaoAi Speakers:

miservice mina "Hello World"

Device-level commands (pause/stop/resume/URL play/single-track loop/volume/status/AI response) require MI_DID to locate the target speaker (MI_DID corresponds to miotDID in the device list):

export MI_DID=<miotDID>
miservice mina pause                # Pause
miservice mina stop                 # Stop
miservice mina play                 # Resume playback
miservice mina play <url>           # Play specified URL (list loop)
miservice mina loop <url>           # Single-track loop URL
miservice mina volume 50            # Set volume 0-100
miservice mina status               # Query playback status
miservice mina ask                  # Get latest AI response

Note: With mina <text>, if the text happens to match a subcommand name (e.g., pause), it will be treated as a subcommand. To broadcast such text, use quotes or add a prefix, e.g., miservice mina "Pause for a moment".

9. Direct LAN Control (No Cloud Account)

Set MI_LOCAL=<device IP>:<device Token> and the CLI talks to the device directly over UDP instead of the cloud (Token can be obtained from miservice list via the cloud, or sniffed from the app):

export MI_LOCAL=192.168.1.10:0123456789abcdef0123456789abcdef

miservice power,brightness          # Read properties
miservice power=on,brightness=80    # Set properties
miservice /miIO.info                # Call a raw miIO method

Library Usage

import asyncio
from miservice import MiAccount, MiIOService, MiNAService

async def main():
    account = MiAccount(None, 'username', 'password', '~/.mi.token')

    # Query device list
    io_service = MiIOService(account)
    devices = await io_service.device_list()
    print(devices)

    # Get device property
    value = await io_service.miot_get_prop('device_id', (2, 1))
    print(value)

    # Set device property
    code = await io_service.miot_set_prop('device_id', (2, 1), 60)
    print(code)

    # XiaoAi Speaker TTS
    na_service = MiNAService(account)
    devices = await na_service.device_list()
    if devices:
        device_id = devices[0]['deviceID']
        await na_service.text_to_speech(device_id, 'Hello')

        # Playback control
        await na_service.player_set_volume(device_id, 50)   # Set volume
        await na_service.player_pause(device_id)            # Pause
        await na_service.player_play(device_id)             # Resume
        await na_service.play_by_url(device_id, 'http://.../music.mp3')  # Play URL (auto-detect model)
        await na_service.player_set_loop(device_id, 0)      # 0=single loop, 1=list loop

        # Playback status and AI response
        status = await na_service.player_get_status(device_id)
        messages = await na_service.get_latest_ask(device_id)

    # Direct LAN control (no cloud account needed, only device IP and Token)
    from miservice import MiIOLocalService
    local_service = MiIOLocalService('192.168.1.10', '0123456789abcdef0123456789abcdef')
    power = await local_service.get_prop('power')
    await local_service.set_prop('power', 'on')

asyncio.run(main())