# Battery PoC — direct-connect charge state Reads the aggregate battery percentage straight from the aGate over its own SoftAP. No cloud, no MQTT, no Bluetooth. Recovered from the Dart AOT layer; see `RE_DART_FINDINGS.md` §§3–5, 8, 10. ## Requirements - Host whose Wi-Fi adapter is associated to the device AP (`AP_` / ``, `wifi.derive_hotspot_credentials`). - L2 reachability to `10.100.1.1`. In a container this means a bridged `macvlan`/`ipvlan` address on `10.100.1.0/24` or `network_mode: host` (see repo-root `.devcontainer/docker-compose.yml`). A default Docker bridge (`172.17.0.0/16`) is NATed to a non-`10.100.1.x` source and gets `ECONNREFUSED`. - Python `requests` for the HTTP helpers in `device_local.py`. ## What it does 1. Probes TCP ports `9000, 18000` in order (`9000` was open on the tested unit; `0x4650 = 18000` is the app constant but was closed there). 2. Sends `DEVICE_APOWER_INFO (0x19)`, then `BMS (0x1D)`, `EMS (0x1E)`: compact-JSON `CommunicationObject` → `encrypt_object` (key `hex(sum(sn) & 0xFF)`) → int16LE length framing. 3. Decrypts the reply and extracts `currentBatterySoc` → `soc` → `avg(socArray)`. ## Usage ```bash # show derived hotspot creds only python -m franklinwh_agate_client.battery --sn <20-char-SN> --show-hotspot # print just the percentage python -m franklinwh_agate_client.battery --sn <20-char-SN> # full reply envelope python -m franklinwh_agate_client.battery --sn <20-char-SN> --raw ``` Options: `--host` (default `10.100.1.1`), `--ports 9000,18000`, `--key-radix {16,32}` (default 16; 32 is the alternate candidate in the disassembly), `--timeout`. Programmatic: ```python from franklinwh_agate_client import get_battery out = get_battery("...", host="10.100.1.1") print(out["value"], out["source"]) # e.g. 78.0 currentBatterySoc ``` ## Limits - No live round-trip has succeeded yet from an isolated container netns (all probes `ECONNREFUSED`); first success needs a `10.100.1.x` source. - `key_radix`, BLE field order, and `X-Device-*` binding remain open (`RE_DART_FINDINGS.md` Open items).