Changelog¶
All notable changes to this documentation project.
2026-08-07¶
Changed (config-driven regeneration)¶
- Reference tables are now generated from the pulled API config packages — Added
generate_reference.py+ a curatedboard_ids.json, which emit ground-truth fragments todocs/_generated/(speed limit, module map, feature flags,s_cmdmap, firmware order, family/protocol table, full command list). Pages pull them in viapymdownx.snippets(--8<-- "_generated/…"), so the config-derived tables can no longer drift from the packages. Reverse-engineered prose (encryption, authentication, transport, frame formats) stays hand-written. Generators run locally before committing (same model asgenerate_device_pages.py). The only datum not carried in the packages — the numeric board IDs — lives inboard_ids.json.
Fixed¶
- Speed-limit units were wrong —
setLimitSpeed/rLimitSpeed(DIS0x93) is in whole km/h, not 0.1 km/h. The config writes the value directly: 25 =19 00, 45 =2D 00, 60 =3C 00. This reverses the 2026-04-04 change to 0.1 km/h (250/450/600) — the config'ssetLimitSpeed_25/45/60s_data values, the app's speed-safety-lock radio (== 25/45/60), and a live E125S read (3C 00= 60) all confirm ×1. The ×10 scaling applies only to the read-only rated caprRatedSpeed/rMaxSpeed(DIS0x48, 450 = 45.0). - Board power-state addressing — On the E-series the motor controller is
0x02(not0x20), the batteries0x06/0x07(not0x22/0x23), and the ECU0x09; there is no board at0x25. Corrected from a live0x00–0xFFregister sweep; the old table used a different family's address convention. - E125S family attribution — The E125S is the Segway eScooter E family (
serverId 81, HW66), a separate config from the E150S / E250S (serverId 14102, HW4102). It uses Encryption2 / gen2 (live-confirmed AES handshake) even though its static scan-configencryptfield is absent; the generated families table now flags this. - Trip mileage —
rSingleMileage(DIS0xB9) is 2 bytes × 0.01 km (was documented as 4 bytes × 0.001 km). rMainPowerpower-state bit — Powered-on is bit 3 (0x08) of ECU0x03; bit 2 (0x04) is "main battery present" (set even in standby). Observed off =0x01F7, on =0x05FF/0x01FF.- Board-Addressing page URL collision —
devices.mdand the auto-generateddevices/index.mdboth resolved to/devices/, so the device index silently shadowed the Board-Addressing page (its content survived only in the search index). Renameddevices.md→board-addressing.mdand updated all inbound links.
Added¶
- Speed & Limiters page — Documents the two independent caps (read-only rated
0x48vs writable user lock0x93, effective top = min), every speed/gear register present in the config, and live E125S findings: no MCU gear subsystem (target0x02answers only its part number), and a dormant500(50.0 km/h) value in the ECU config block at register0xE3. - Feature-flag bit meanings from the app's own UI configs —
rFunBool/rCTLBool2/rWarn/rBoolbit → label are now derived from the shipped UI configs (string-resolved to English), replacing hand-typed tables that could drift. - Complete
s_cmdmapping — Every special-command byte → the commands that use it, generated from the config, alongside the curated purpose table.
2026-04-18¶
Clarified (provenance)¶
- How the ident reaches both sides — New "Provenance" section on the Credential QR page explains: the 16-byte vehicle-action ident is a factory-programmed per-device secret burned into scooter flash at manufacturing, mirrored in Segway's cloud keyed by serial number. The app fetches it once via
POST /vehicle/vehicle/vehicle-basic-infowith{uid, wnumber}and caches it for offline use. There is no BLE command that sets the ident on the scooter — the scooter already has it — which is why scoot-side verification works offline and why wrong-ident frames fail silently. Documents why the value is not derivable from public inputs (serial, ECU PN, BLE device name).
Added¶
- Python BLE Client chapter — Nav was promoted from "Implementation" to a top-level "Python BLE Client" section.
client.mdrewritten with: current CLI surface (including--identandopen-acc/close-acc/open-trunksubcommands), worked-example walkthrough, per-MAC session-file schema, Gen2/Gen3 constant tables, and "extending the client" recipe. Cross-linked tocredentials-qr.md. - Vehicle-action builders in the reference client —
nb_protocol.pynow exposesbuild_open_acc/build_close_acc/build_open_trunkwith a 16-byte ident payload;build_frameand all convenience builders take agen="gen2"|"gen3"argument (default Gen2 for the E-series moped target). Fixed a latent bug where the old client hardcoded Gen3 sync bytes (0x5A 0xB5) despite claiming E125S (Gen2) compatibility. - Credential QR setup page — Documents the
segway://credentials?sn=…&pwd=…&ident=…URI format used to transfer session password and vehicle-action ident between installations. Ships atools/make_creds_qr.pyCLI with--password,--ident,--sn,--ascii, and--outflags. - Cross-link from Authentication — Added a closing "Authorization beyond the handshake" section so readers who finished the 3-phase handshake know why writes may still silently fail without
$ident.
Clarified¶
$identis a 16-byte secret, not the ECU PN — Rewrote the Vehicle actions section of the command reference. Documented: (1) wire format is 16 raw bytes derived from a 32-char hex string, (2) mismatched payloads are silently dropped by the firmware (MAC still verifies, no error response — the worst possible failure mode for an app developer to diagnose), (3) storage location is iOS UserDefaults{serialNumber}_ident/ Android SharedPreferences, (4) the value is cloud-issued at first pairing and cached locally for offline use.- Not related to "airlock" — Explicit disclaimer that the
nb_airlock_*UserDefaults keys belong to the separate proximity-unlock feature (iBeacon). They coincidentally hold the same byte value in the reference app but are not the source of truth forcmd=0x64payloads.
2026-04-05¶
Added¶
fw_dataconstant documentation — Documented the 16-bytefw_dataconstant (97 CF B8 02...) fromlibnbcrypto.sothat is substituted for null key2 in Gen2 non-SN mode. Explains why Gen2 and Gen3 produce different ciphertext for the same plaintext.- iOS bonded device behaviour — New transport section covering stale CCCD state, notification draining, echo detection, and retry recovery. Practical workarounds for each issue.
- Vehicle action commands with
$ident— Rewrote security commands section. Documents Gen2 vs Gen3 target board differences (VCU 0x09 vs BLE 0x04), action registers (open ACC, close ACC, open trunk), and the$identauthorization token payload. - Stored password recovery — Step-by-step guide to extracting stored BLE passwords from iOS backups (
{SN}_decryptkey in UserDefaults plist), includingsqlite3andplutilcommands. - System device discovery — Documented iOS-specific
systemDevices()API for finding bonded peripherals that don't appear in scans.
Fixed¶
- Index page — Updated Python BLE client description from "untested with real hardware" to "verified against Segway E125S".
2026-04-04 (evening)¶
Verified¶
- Live hardware test — BLE client tested successfully against a real Segway E125S. Handshake (PRE_COMM + stored-password AUTH), register reads, and session persistence all confirmed working.
Fixed¶
- MTU fragmentation — App must split outgoing frames exceeding
MTU - 3bytes (20 bytes at default MTU 23). AUTH frames (27 bytes) were silently truncated without fragmentation, causing the device to never respond. Added explicit documentation and implementation. - Authentication
0x5A 0xB5references — Fixed remaining5A B5references in handshake examples (should be5A A5for BLE). - Speed limit data values — Corrected speed limit write examples (values are in 0.1 km/h units: 250=25 km/h, not 0x19=25).
- Odometer units — Documented as 0.001 km (1 metre precision), not raw km.
Added¶
- Board availability by power state — Table showing which boards respond when vehicle is off (DIS, BLE, VCU: always on; MCU, BMS, ECU: asleep). Commands to sleeping boards time out silently.
- Reconnect counter documentation — First AUTH frame in reconnect mode uses counter=2, same as normal flow.
--passwordCLI flag — Supply stored password from iOS backup to skip SET_PWD phase during reconnection.- Register value units — Range (0.1 km), speeds (0.1 km/h), odometer (0.001 km) now explicitly documented.
2026-04-04¶
Fixed¶
- Critical: BLE header correction — All BLE protocols (Protocol 2, Encryption2, Encryption3) use
0x5A 0xA5. The0x5A 0xB5header is exclusively used by WiFi v2 transport (WifiEncryptionProtocol2). Previous documentation incorrectly stated Encryption2 uses0x5AB5. Confirmed by decompilation ofBleEncryption2Protocol.java(FRAME_BEGIN = -91, i.e.0xA5) andWifiEncryptionProtocol2.java(FRAME_BEGIN = -75, i.e.0xB5).
Added¶
- Per-device protocol map — All 71 devices now show their BLE protocol class (Proto1, Proto2, Enc2) on the Board Addressing page, derived from
backup_config.nbscan configuration. - Protocol column in device tables — The Device Command Reference tables now include a Protocol column, auto-generated from
generate_device_pages.py. - Protocol class hierarchy — Full class hierarchy documented (BleProtocol1 → BleProtocol2 → BleEncryption2Protocol → BleEncryption3Protocol2), including WiFi variants.
- Encryption3 / V3Auth — Added documentation for the newest protocol variant (
BleEncryption3Protocol2), which uses a different handshake flow. - Protocol version selection logic — Documented
DynamicDevice.createBleProtocol()selection rules and BLE advertisement manufacturer data (0x4E42/0x4E43). - Gear profile commands — MCU board registers for reading/writing gear profiles (top speed, acceleration, TCS, nitro, energy recovery, speed safety lock).
- Vehicle action commands —
power-on,power-off,open-seatCLI commands with--identflag for E-series mopeds (cmd 0x64, target VCU 0x09). - Sound preset control — DIS register 0x75 (rWarn) bit 8 for sound effect toggling, volume control, alarm settings.
- Gen2/Gen3 protocol support — BLE client now supports both Gen2 (E-series mopeds) and Gen3 (newer kick scooters) protocol variants via
--genflag. - Changelog — This page.
Changed¶
- WiFi v2 documentation clarified — WiFi v2 section now explicitly states it is the only protocol using
0xB5. - Device count updated — 71 devices documented (was 66), including newer models from updated scan config.
2026-03-28¶
Added¶
- Initial release — Full protocol documentation published.
- 66 device command tables — Auto-generated from decrypted device configuration packages.
- Python BLE client — Reference implementation of Encryption2 protocol.
- Encryption algorithm — Complete AES-128 CTR + CBC-MAC documentation with Python reference code.
- Authentication handshake — 3-phase PRE_COMM / SET_PWD / AUTH sequence.
- BLE transport — Service UUIDs, characteristics, MTU handling.
- Board addressing — Module IDs and routing for all device families.
- Command reference — Register-based read/write commands for speed, battery, lights, security.
- Firmware update protocol — IAP (In-Application Programming) documentation.