bub-xiaoai is a Bub channel plugin for Xiaomi XiaoAi speakers.
It is based on the Xiaomi device integration approach from yihong0618/xiaogpt, but the scope here is narrower:
- listen for messages from a XiaoAi speaker
- forward them into Bub as a channel
- expose
xiaoai.speakso the assistant can speak replies back through the speaker - keep the interaction in continuous conversation mode by default
This project does not provide a standalone CLI runner for XiaoAi. It is meant to be loaded by Bub as a plugin.
- Message polling from XiaoAi via Xiaomi Mina APIs
- QR authentication and MIoT actions through
mijiaAPI - TTS playback through the XiaoAi speaker
- Automatic wake-up after a reply to keep conversation going
- Temporary static file HTTP server started with the listener lifecycle
- Bub tool
xiaoai.speak - Bundled skill
xiaoaiundersrc/skills/xiaoaito instruct the LLM to callxiaoai.speak
At runtime the plugin creates a single XiaoAiMessageListener, registers a Bub channel named xiaoai, and exposes a tool:
- Channel:
xiaoai - Tool:
xiaoai.speak(text: str)
Incoming XiaoAi queries are turned into Bub ChannelMessage objects. The assistant should answer by calling xiaoai.speak, which performs TTS on the device.
When the listener starts, it also creates a temporary directory and serves it through a local HTTP server for the same lifecycle window. The directory is available through listener.static_server.temp_dir, and the base URL is available through listener.static_server.origin.
The channel currently runs in continuous conversation mode by default:
- ordinary spoken queries are forwarded without a keyword prefix
- the raw wake word
小爱同学is ignored and not sent to the LLM - after a reply finishes, the plugin attempts to wake XiaoAi again so the next utterance can be captured
- Python
>=3.13
uv pip install git+https://github.com/bubbuild/bub-xiaoai.gitSettings are loaded from environment variables through XiaoAiSettings with prefix BUB_MI_.
Supported variables:
BUB_MI_HARDWAREBUB_MI_MI_DIDBUB_MI_COOKIEBUB_MI_TOKEN_HOMEBUB_MI_POLL_INTERVALBUB_MI_REQUEST_TIMEOUTBUB_MI_CHAT_ID
Defaults are defined in src/bub_xiaoai/mi.py.
Two authentication modes are supported:
- Mi Home QR code
- Xiaomi cookie
If BUB_MI_COOKIE is set, the plugin skips account login and uses the cookie directly.
Otherwise, the plugin uses the mijiaAPI authentication flow. On first startup,
scan the QR code shown in the terminal with the Mi Home app. Authentication data
is reused and refreshed on later startups. In Bub runtime the default auth path is:
<bub-home>/mi_token.json
This is wired in src/bub_xiaoai/plugin.py.
export BUB_MI_HARDWARE=LX06
export BUB_MI_MI_DID='your-device-did'Or with cookie login:
export BUB_MI_HARDWARE=LX06
export BUB_MI_COOKIE='deviceId=...; serviceToken=...; userId=...'
export BUB_MI_MI_DID='your-device-did'Once the plugin is loaded by Bub:
- speech coming from XiaoAi arrives on channel
xiaoai - the LLM can answer by calling
xiaoai.speak
The provided skill at src/skills/xiaoai/SKILL.md tells the model to use xiaoai.speak for user-facing spoken replies.
- User talks to XiaoAi.
XiaoAiChannelpolls Xiaomi conversation records.- A new record is converted into a Bub message.
- The assistant handles the message.
- The assistant calls
xiaoai.speak. - The plugin speaks the response on the speaker.
- After TTS finishes, the plugin tries to wake XiaoAi again.
Relevant implementation files:
- Authentication, device discovery, and MIoT actions use
mijiaAPI. - The small Mina client is maintained locally because
mijiaAPIdoes not expose XiaoAi playback and UBus endpoints. - The XiaoAi integration approach is adapted from
xiaogpt, especially conversation polling and Mina playback commands. - The code is intentionally scoped to Bub integration instead of reproducing all of
xiaogpt. - There is no prompt management, model orchestration, or standalone command runner here.
- Xiaomi QR login can fail due to Xiaomi risk control. Cookie login remains available as a fallback.
- Automatic wake-up depends on MiIO commands and a usable
mi_did. - The channel currently ignores the isolated wake word
小爱同学. - Only the latest XiaoAi conversation records are polled; this is not a full history sync.
Run a quick syntax check:
python3 -m compileall srcRun a minimal import check in the project environment:
uv run python - <<'PY'
from bub_xiaoai import XiaoAiMessageListener, XiaoAiSettings
print(XiaoAiMessageListener, XiaoAiSettings)
PYVerify Xiaomi authentication without starting the Bub runtime:
uv run python scripts/test_xiaoai_auth.py
uv run python scripts/test_xiaoai_auth.py --auth-path /path/to/auth.jsonOn first use, scan the QR code with the Mi Home app. The script verifies both Mi Home access and the micoapi credentials required by XiaoAi Mina endpoints.
- Core Xiaomi speaker integration ideas in this project come from
yihong0618/xiaogptby @yihong0618, including device discovery, conversation polling, MiIO wake-up control, and the overall continuous-conversation interaction model. - Built for the Bub plugin/runtime model