mi-router — MiWiFi (Xiaomi) router inspector¶
Read-only CLI for poking at a Xiaomi / MiWiFi router's stock web API without
opening a browser. Sister tool to sms (which does the same job
for Huawei HiLink routers).
The CLI hits the LuCI/MiWiFi JSON API under /cgi-bin/luci/;stok=<token>/api/
after performing the router's standard SHA1 challenge handshake
(sha1(nonce + sha1(password + key))). No third-party SDK exists; the auth
flow is implemented inline.
Tested against Xiaomi AX9000 (hardware ID RA70), MiWiFi firmware 1.0.168
(CN region). Likely works on most MiWiFi 3.x firmwares — endpoints
deviating per model fall through gracefully (the script reports endpoint
not registered instead of crashing).
Install¶
Deployed automatically by chezmoi:
~/.dotfiles/bin/mi-router— the CLI (uv-script; first run resolves deps into uv's cache)~/.config/mi-router/config.toml.example— starter config
uv must be installed (it is, via the bootstrap script).
First-time setup¶
# Either: populate the config file
cp ~/.config/mi-router/config.toml.example ~/.config/mi-router/config.toml
chmod 600 ~/.config/mi-router/config.toml
$EDITOR ~/.config/mi-router/config.toml # set host + password
# Or: let mi-router prompt on first call and save for you
mi-router login-test
Resolution order (first non-empty wins):
--host/--username/--passwordCLI flags~/.config/mi-router/config.tomlMI_ROUTER_HOST/MI_ROUTER_USER/MI_ROUTER_PASSenv vars- Interactive
getpassprompt (TTY only; offers to save to config)
Defaults: host = 192.168.31.1, user = admin.
Commands¶
mi-router info # router identity, FW, LAN/WAN
mi-router wifi # all radios
mi-router wifi --show-passwords # …with cleartext PSKs
mi-router devices # online clients (default)
mi-router devices --no-online-only # include offline
mi-router mdns # discovery toggles + caveats
mi-router all # info + wifi + devices + mdns
mi-router endpoints # curated catalog of GET endpoints
mi-router endpoints --check # …live-probe each one
mi-router login-test # verify creds, no other output
mi-router raw xqnetwork/wifi_detail_all # any MiWiFi GET endpoint
Global flags: --host, --username, --password, --timeout. They work
either before or after the subcommand. endpoints (without --check) is
the only subcommand that does not require credentials — it prints a
static catalog without touching the router.
What mi-router mdns reports¶
The MiWiFi web UI exposes very few discovery-related toggles. The two it does:
miotrelay(畅快连) — multicast/IoT discovery relay across radios. Leave on if you care about mDNS-style cross-band discovery.miscan(AIoT Smart Antenna Auto-Scan) — auto-discovers unprovisioned Mi smart devices on 5G for the Mi Home onboarding flow.
What is not exposed by the stock UI on this firmware: AP/client isolation, IGMP snooping, multicast-to-unicast / multicast rate, generic mDNS reflector, per-SSID firewall rules. To inspect or change those you'd need SSH access (disabled by default on stock firmware) or to flash OpenWrt / a dev firmware.
For the full mDNS troubleshooting workflow — including the dns-sd and
tcpdump recipes — see playbooks/mdns-diagnostics.md.
Read-only by design¶
No POST-bearing endpoints are wired up. The raw subcommand is also
GET-only. This is deliberate: for the inspector use case, the cost of an
accidental toggle (kicking your IoT devices off the network, breaking
mesh, locking yourself out) outweighs the convenience. If you need to flip
something, do it in the web UI.
A side effect of the auth handshake worth knowing: each fresh login
invalidates the router's existing web session, which kicks an open
browser tab back to the login screen. Don't run mi-router repeatedly in
a tight loop while you're using the web UI in another tab.
Endpoints used / available¶
The hard-coded subcommands cover what most people want, but there are dozens
more GET endpoints worth knowing. Run mi-router endpoints for a live
table; this is the same catalog formatted for reading:
System / firmware (always-safe GET):
| Endpoint | Subcommand | Purpose |
|---|---|---|
xqsystem/login |
(auth) | SHA1 challenge login (POST, internal) |
xqsystem/fac_info |
info |
Firmware version, SSH/Telnet, factory SSIDs |
xqsystem/country_code |
Regulatory region | |
xqsystem/get_languages |
Available UI languages | |
xqsystem/check_rom_update |
Firmware-update check (no upgrade triggered) | |
xqsystem/upnp |
UPnP daemon state + active port mappings | |
misystem/router_name |
info |
Router display name + locale |
misystem/topo_graph |
info |
Hardware ID, mode, mesh topology |
misystem/newstatus |
Aggregated dashboard data (HW + counts) | |
misystem/status |
Per-device traffic stats (up/down speed) | |
misystem/sys_time |
Router clock + timezone | |
misystem/messages |
System notifications inbox | |
misystem/r_ip_conflict |
IP conflict detection state | |
misystem/web_access_info |
Remote web-access (WAN admin) status |
Network — LAN / WAN:
| Endpoint | Subcommand | Purpose |
|---|---|---|
xqnetwork/lan_info |
info |
LAN IP / mask / MAC / uptime |
xqnetwork/lan_dhcp |
LAN DHCP pool + lease config | |
xqnetwork/wan_info |
info |
WAN config + status + DNS |
xqnetwork/pppoe_status |
WAN protocol detail (DHCP/PPPoE/static) | |
xqnetwork/mode |
Router mode (0 = router) |
|
xqnetwork/macbind_info |
MAC ↔ IP bindings + device list | |
xqnetwork/portforward |
Port-forwarding rules | |
xqnetwork/get_lanaggregation_switch |
LAN aggregation (link bonding) state | |
xqnetdetect/nettb |
Network detect status |
Wi-Fi:
| Endpoint | Subcommand | Purpose |
|---|---|---|
xqnetwork/wifi_detail_all |
wifi |
Per-radio config (SSID, ch, BW, enc, AX) |
xqnetwork/wifi_macfilter_info |
MAC filter list + currently-connected wifi clients | |
xqnetwork/get_miotrelay_switch |
mdns |
"畅快连" multicast relay state |
xqnetwork/get_miscan_switch |
mdns |
AIoT 5G unprovisioned-device scan state |
xqnetwork/get_son_backhaul_mode |
Mesh backhaul mode | |
misns/wifi_share_info |
Mi shared-WiFi feature ⚠ may include cleartext SSID/PSK |
Devices & QoS:
| Endpoint | Subcommand | Purpose |
|---|---|---|
misystem/devicelist |
devices |
All known clients (online + offline) |
misystem/qos_info |
QoS state + per-client priorities |
Write endpoints (POST) — intentionally NOT supported¶
The raw subcommand only does GET. These all exist on the router but the
CLI won't reach them; flip them in the web UI if you need to:
xqsystem/{reboot, reset, shutdown, set_country_code, set_language, set_mac_filter, set_name_password}xqnetwork/{set_wifi, set_all_wifi, set_wifi_ax, set_wifi_macfilter, set_wifi_txbf, set_wifi_txpwr, set_lan_aggregation, set_lan_dhcp, set_lan_ip, set_management_ip, set_son_backhaul_mode}xqnetwork/{miotrelay_switch, miscan_switch, add_mesh_node, scan_mesh_node, edit_device, mac_bind, mac_unbind, manually_add}misystem/{set_router_name, set_band, web_access_opt}
Discovered-but-unstable endpoints¶
Some endpoints exist in the routing table but only return useful data with specific parameters or app state:
misystem/qos_{guest,xq}→code:1523(参数错误 / "missing parameter")misystem/qos_{limits,mode,offlimit}→code:1607(QoS must be on)xqnetwork/get_addnode_status→ 500 (only valid during mesh-add flow)xqdatacenter/request→ 500 (needs JSON body)misystem/active,xqnetdetect/netupspeed→ 502 (probably need params)
Troubleshooting¶
login failed: {'code': 401, ...}— wrong password. Re-prompt by deleting the cached value:$EDITOR ~/.config/mi-router/config.toml.could not parse login key/mac from router page— your firmware's login page differs from the regex assumptions. Openhttp://<router>/cgi-bin/luci/webin a browser, view source, look for thekey:andmac:JS literals, and patchKEY_RE/MAC_REin the script.endpoint not registered (404)— the endpoint doesn't exist on this firmware. The script returns a JSON_errorpayload instead of crashing so you can keep exploring.- Web UI keeps logging me out — see "Read-only by design" above; each
mi-routercall is a fresh login.
See also¶
sms— sister tool for Huawei HiLink routers.playbooks/mdns-diagnostics.md— when and how to usemi-router mdnsinside a wider Bonjour/mDNS investigation.