No description
  • Python 84.3%
  • Roff 12.9%
  • Makefile 2.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Emmett1 a6a59e4e18 Add support for ZTE-style goform MiFi firmware
The new device (firmware MX1SW1.0_10F_FB_DANENG_SL_V01.01.02P42U28_06)
serves a ZTE-style web UI with a JSON API under /reqproc instead of
Marvell duster's xml_action.cgi, so login failed with
"unexpected login challenge".

Split the client into Duster and Zte backends behind the same set of
operations, auto-detected by probing /reqproc/proc_get (override with
--firmware / MIFI_FIRMWARE). raw accepts field lists and goform
key=value params on zte.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 23:53:57 +08:00
.gitignore first commit 2026-09-16 16:46:04 +08:00
Makefile first commit 2026-09-16 16:46:04 +08:00
mifi.1 Add support for ZTE-style goform MiFi firmware 2026-09-26 23:53:57 +08:00
mifi.py Add support for ZTE-style goform MiFi firmware 2026-09-26 23:53:57 +08:00
README.md Add support for ZTE-style goform MiFi firmware 2026-09-26 23:53:57 +08:00

mifi

A dependency-free command-line client to monitor and control a portable 4G MiFi router. Two firmware families are supported and auto-detected:

Firmware Web API Tested on
Marvell "duster" ("4G Wireless Router MIFI", HTTP-Digest realm Highwmg) XML-over-CGI at /xml_action.cgi U MOBILE LV01 (PXA1802, SDK067_CW_M03)
ZTE-style goform UI (server Demo-Webs, "4G Hostless Modem") JSON at /reqproc/proc_get / /reqproc/proc_post MX1SW1.0_10F_FB_DANENG_SL_V01.01.02P42U28_06

Other devices using either web UI should work too. Pure Python 3 standard library — no pip install, nothing to build.

Install

make install            # -> ~/.local/bin/mifi  (no root needed)
make uninstall

Installs to your home-local directory by default. For a system-wide install:

make install PREFIX=/usr/local     # may need sudo

If ~/.local/bin isn't on your PATH, the installer prints the line to add. You can also just run the script in place: ./mifi.py <command>.

Quick start

mifi status                     # signal, network, battery, data usage
mifi battery                    # battery gauge
mifi watch                      # live-refreshing dashboard
mifi sms list inbox             # read texts
mifi sms send +60123456789 "hi" # send a text

Configuration

Credentials default to admin / admin. Override per-invocation or via the environment:

Setting Flag Env var Default
Host/IP --host MIFI_HOST 192.168.0.1
Username --user MIFI_USER admin
Password --password MIFI_PASS admin
Firmware --firmware MIFI_FIRMWARE auto (duster or zte to force)
export MIFI_PASS='s3cret'
mifi status

Note: the credentials are the same ones you use to log into the router's web panel. The password is often printed on a sticker under the battery. ZTE-style devices have no username, so --user is ignored there. They also lock the web login after 5 wrong passwords; mifi reports how many attempts remain when a login fails.

Commands

Command What it does
status One-shot summary: network, radio/band, WAN IP, signal (RSSI/RSRP/RSRQ/SINR), battery, connected clients, unread SMS, and data usage.
battery Battery level as a gauge bar, plus charging state.
watch [--interval N] Clears the screen and re-renders status every N seconds (default 3), with a battery gauge in the header.
connect / disconnect Bring the cellular WAN up or down.
reboot [-y] Reboot the router (prompts unless -y).
sms list [inbox|sent|draft] [--page N] List stored messages. Bodies are UTF-16 decoded; unread are marked *.
sms send <number> <text> Send an SMS.
raw get <file> / raw set <file> [--stdin] duster: call any XML endpoint the web UI uses (wan, statistics, message, lan, …). Handy for exploring.
raw get <f1,f2,…> / raw set <goformId> [key=value …] zte: read any proc_get fields as JSON, or POST any goform command.

JSON output

Every read command (and the action commands) accept --json for scripting, with --compact for single-line output:

mifi status --json | jq '{net:.network, dbm:.rsrp, batt:.battery_pct}'
mifi battery --json                       # {"level_pct":97,"charging":true,...}
mifi sms list inbox --json | jq length
mifi watch --json --interval 10           # newline-delimited JSON, one per tick

Numbers come back as JSON numbers, booleans as booleans, and byte counters as raw integers (do your own formatting). Errors are emitted as {"error": "..."} on stdout with a non-zero exit code.

How it works

These devices don't speak standard HTTP auth: the server answers every request with 200 OK plus a WWW-Authenticate header and an UNAUTHORIZED body, until a request carries a valid custom digest header (with the quirk that the digest URI is always the literal /cgi/xml_action.cgi). mifi reproduces the firmware's two-step login.cgi handshake, then issues XML GET/POST calls to xml_action.cgi. See the module docstring in mifi.py for the gory detail.

ZTE-style devices are simpler: mifi POSTs goformId=LOGIN with the base64'd password to /reqproc/proc_post (keeping the session cookie), reads status as JSON from /reqproc/proc_get?cmd=a,b,c&multi_data=1, and issues actions such as CONNECT_NETWORK, REBOOT_DEVICE and SEND_SMS as goform POSTs.

Auto-detection probes /reqproc/proc_get once per run; if it answers with JSON the device is treated as ZTE-style, otherwise as duster.

The device tends to allow one session at a time, so if the web UI is logged in elsewhere the CLI may occasionally get bumped — just re-run.

Files

Path Purpose
mifi.py The client (also the installed mifi).
Makefile install / uninstall / check.
mifi.1 Man page (make install also installs it).

Caveats

  • Signal metrics (RSSI/RSRP/RSRQ/SINR) are the raw values the firmware reports; scaling varies by model.
  • Battery_voltage is the firmware's misnomer for the charge level (0–100), which is what battery shows.
  • ZTE-style firmware may report no battery percentage at all, only the coarse icon level (battery_pers); battery then shows that level instead.
  • On ZTE-style firmware, sms list reads the device's message store (as the web UI does), 20 messages per --page.
  • connect, disconnect, reboot, and sms send change live device state — use with care.

License

Provided as-is, no warranty. Do what you like with it.