Your router speaks
encrypted JSON-RPC.
The HH515L web UI does not send your password. It runs a four-stage handshake — RSA key exchange, PBKDF2-SHA512 against the router’s own salt, AES-256-CBC on every request body, HMAC-SHA256 on every payload. I read that out of the router’s own JavaScript and reimplemented it, so all 348 endpoints are one command away.
$ cpe login # prompts, never on argv $ cpe status
The password is never passed on the command line where ps would show it, never logged, and never written to disk — only the resulting session token is stored, at ~/.cpe/session.json with mode 0600. The router itself is on your LAN, and so is every request.
The catalog was extracted from the router’s own web UI bundle and verified against it: every name in src/endpoints.ts corresponds to a real post() call site in the firmware’s JavaScript, and none are missing.
Let your agent set it up
Every command speaks --json, so an agent can drive the router directly. Paste this and it installs the binary, logs in without putting your password on a command line, and shows you what it found.
Set me up with cpe — a terminal control plane for my TCL HH515L 5G router.
Run this first, then follow it exactly, top to bottom:
curl -fsSL https://cpe.lukaloehr.com/setup.txt
Ask me its first question before doing anything else. Never put my router
password on a command line, and never run a write endpoint without asking.Two steps
Ah, so you haven’t fallen for the vibe yet. Respect. I still read commands before I run them too.
Get the binary
Self-contained, no runtime needed — macOS arm64/x64, Linux x64/arm64 on Releases. Verify it against the published SHA256SUMS if you like. Or run from source with Bun; there are no runtime dependencies.
$ chmod +x cpe-darwin-arm64 $ mv cpe-darwin-arm64 ~/.local/bin/cpe $ sha256sum -c SHA256SUMS --ignore-missing
Log in once
One caveat worth knowing: the router locks the account after a few failed logins. cpe login performs exactly one Login call and never retries — if credentials are rejected it prints how many attempts remain rather than swallowing it.
$ cpe login $ cpe status $ cpe call GetConnectedDeviceList --json \ | jq '.ConnectedList[].DeviceName'
Every Set* and action endpoint requires --confirm, including through cpe call. Read-only endpoints never do. cpe reboot is refused; cpe reboot --confirm actually reboots.
loginAuthType: 7
The router does not accept a plain password. Four stages, all of it read out of the firmware’s own JavaScript and covered by tests built from vectors taken out of the same bundle.
Responses come back encrypted the same way and are decrypted with TmpKey. PKCS#7 padding is applied once, by the cipher.
Commands
Everyday
cpe loginAuthenticate — prompt, or $CPE_PASSWORDcpe statusRouter, network, signal, wifi, data usagecpe devicesConnected devices, interface and accesscpe smsList SMS threads (--unread for unread)cpe networkRegistration, signal list, settingscpe firewallLevel, filters, port triggering, UPnP, ALGcpe call <endpoint>Any of the 348, directlycpe endpointsBrowse and search the catalogEnvironment
CPE_PASSWORDSkips the interactive promptCPE_USERadminCPE_BASEhttp://192.168.1.1/jrd/webapiCPE_TIMEOUT_MS15000NO_COLOROff automatically when pipingFlags
--jsonCompact single-line, agent-friendly--confirmRequired for every write or action--searchSearch the endpoint catalog