Board Addressing & Devices¶
Each Segway-Ninebot vehicle consists of multiple boards (modules), each with its own address. Commands are routed to specific boards using the TARGET_ID field in the frame.
Board types¶
| Board | String ID | Hex | Description |
|---|---|---|---|
| DIS | dis |
varies | Display / Dashboard controller |
| CTRL | ctrl |
varies | Main controller |
| BLE | ble |
varies | Bluetooth module |
| BMS | bms |
varies | Battery Management System (primary) |
| BMS2 | bms2 |
varies | Battery Management System (secondary) |
| BMS3 | bms3 |
varies | Battery Management System (tertiary) |
| BMS4 | bms4 |
varies | Battery Management System (quaternary) |
| MCU | mcu |
varies | Microcontroller unit |
| ECU | ecu |
varies | Electronic Control Unit |
| SUB_CTRL | sub_ctrl |
varies | Secondary controller |
| DRIVER | driver |
varies | Motor driver |
| AHRS | ahrs |
varies | Attitude & Heading Reference System |
| UPC | upc |
varies | Uninterruptible Power Controller |
| ANCHOR | anchor |
varies | Anchor/dock module |
| DBOARD | dboard |
varies | Dashboard board |
| MOTOR1 | motor1 |
varies | Motor 1 |
| MOTOR2 | motor2 |
varies | Motor 2 |
| TAG | tag |
varies | Tag/tracking module |
| PTZ | ptz |
varies | Pan-Tilt-Zoom (camera) |
| BFG | bfg |
varies | BLE Firmware Gateway |
Protocol identifier¶
The BT_ID field (byte position 3 in Encryption2 frames) is always 0x3E (62). This identifies the Bluetooth protocol layer — it is not a board address. Frames with BT_ID != 0x3E are silently discarded.
Board ID routing¶
Each board has two IDs:
- sendId: Used as
TARGET_IDwhen sending commands to this board - receiveId: Expected in response frames from this board
These IDs are defined in the device configuration and vary by device model.
Example: Segway eScooter E (E125S) module map¶
Modules referenced by the Segway eScooter E config (serverId 81, HW 66 — the
E125S). The E150S / E250S (serverId 14102, HW 4102) are a separate config
family. The module list is generated from the config package; the numeric target
bytes come from the app's BoardConfig (see board_ids.json):
Modules referenced by this family's config, joined to the numeric BLE target byte (from board_ids.json — the numeric IDs are the one thing not carried in the config package).
| Module | Target | In config | Live-confirmed | Note |
|---|---|---|---|---|
abs |
0x1B |
✓ | ||
abs-f |
0x1B |
✓ | ||
abs-r |
0x1C |
✓ | ||
ble |
0x04 |
✓ | ✓ | handshake target |
bms-ble1 |
0x0D |
✓ | ||
bms-ble2 |
0x0E |
✓ | ||
bms-ble3 |
0x0F |
✓ | ||
bms1 |
0x07 |
✓ | ✓ | ~232 registers |
bms2 |
0x06 |
✓ | ✓ | ~231 registers |
bms3 |
0x05 |
✓ | absent on 2-battery units | |
chg |
0x20 |
✓ | ✓ | 16 registers respond at 0x20 |
dis |
0x01 |
✓ | ✓ | answers every index (256) |
dvr-f |
0x31 |
✓ | ||
ecu |
0x09 |
✓ | ✓ | power state + vehicle actions + config block |
fl-apl |
0x22 |
✓ | ||
gl-apl |
0x34 |
✓ | ||
hep |
0x11 |
✓ | ||
htg |
0x35 |
✓ | ||
light |
0x15 |
✓ | ||
mcu |
0x02 |
✓ | ✓ | E125S: part number only, no gear registers |
tft |
0x23 |
✓ |
Board availability by power state¶
Not all boards are accessible when the vehicle is powered off. Only boards with independent power (BLE module, dashboard) respond to register reads when the ignition is off. Commands sent to sleeping boards time out silently with no response.
Confirmed on E125S (live BLE full-register sweep):
| Board | Target | Off | On | Notes |
|---|---|---|---|---|
| DIS (Dashboard) | 0x01 | yes | yes | Always powered — answers every index; aggregates other boards |
| BLE | 0x04 | yes | yes | Battery-powered radio module |
| ECU / VCU | 0x09 | yes | yes | Power state via rMainPower (0x03); config block at 0xDF |
| MCU | 0x02 | no | yes* | *Even powered on, answers only its part number (0x00/0x10) — this family has no MCU gear registers |
| BMS1 | 0x07 | no | yes | ~232 registers when awake |
| BMS2 | 0x06 | no | yes | ~231 registers when awake |
| BMS3 | 0x05 | no | no | Absent on 2-battery units |
| CHG | 0x20 | no | charging | 16 registers respond |
Addresses come from the config, not the old 0x20/0x22/0x25 scheme
On the E-series the motor controller is 0x02, the batteries 0x06/0x07, and the ECU 0x09 — matching this family's config (and live-confirmed). There is no board at 0x25. Earlier drafts used a different family's 0x20/0x22/0x23/0x25 convention.
Reading power state (rMainPower, ECU 0x03)
Bit 3 (0x08) = powered on. Observed 0x01F7 (503) = off; 0x05FF (1535) or 0x01FF (511) = on — bit 3 is the reliable cross-unit indicator. Bit 2 (0x04) = main battery present (set even in standby, so not an on/off signal).
Dashboard as proxy
When the vehicle is off, read battery level (DIS:0xB5), range (DIS:0x25), and odometer (DIS:0xB7) from the DIS board (0x01) rather than directly from BMS. DIS aggregates data from sleeping boards and keeps cached values available.
Supported device families¶
Every device family in the manifest, with its protocol/encryption values, is generated from the pulled config packages + app scan config — so it never drifts:
All 66 device families from manifest.json, joined to the scan-config protocol values (backup_config). ble_protocol and encrypt are the static config values; - = field absent (runtime default applies).
Kick scooters¶
| Family | serverId | HW id | Commands | ble_protocol | encrypt | Live-confirmed |
|---|---|---|---|---|---|---|
| Ninebot KickScooter Air | 58 | 35 | 55 | 2 | - | |
| Ninebot KickScooter E | 55 | 39 | 106 | 2 | - | |
| Ninebot KickScooter ES | 52 | 33 | 84 | 2 | 0 | |
| Ninebot KickScooter Max | 54 | 36 | 68 | 2 | 0 | |
| Ninebot Kickscooter C2 Pro | 535 | 124 | 70 | 2 | - | |
| Ninebot Kickscooter D18 | 525 | 116 | 46 | - | 2 | |
| Ninebot Kickscooter D28 | 526 | 114 | 47 | - | 2 | |
| Ninebot Kickscooter D38 | 527 | 115 | 46 | - | 2 | |
| Ninebot Kickscooter E2/E2 Plus | 536 | 125 | 69 | 2 | - | |
| Ninebot Kickscooter F | 521 | 44 | 63 | 2 | - | |
| Ninebot Kickscooter F | 534 | 123 | 55 | 2 | - | |
| Ninebot Kickscooter F2 | 538 | 127 | 104 | 2 | - | |
| Ninebot Kickscooter F2 Plus | 539 | 128 | 104 | 2 | - | |
| Ninebot Kickscooter F2 Pro | 540 | 129 | 104 | 2 | - | |
| Ninebot Kickscooter F65 | 530 | 45 | 59 | - | 2 | |
| Ninebot Kickscooter G65 | 531 | 120 | 63 | - | 2 | |
| Ninebot Kickscooter MAX G2 | 537 | 131 | 121 | - | 2 | |
| Ninebot Kickscooter UiFi 1 | 532 | 121 | 74 | - | 2 | |
| Ninebot Kickscooter UiFi 1 Pro | 533 | 122 | 74 | - | 2 | |
| Ninebot eKickScooter E2 Pro | 541 | 141 | 107 | 2 | - | |
| Segway ST2 Pro | 544 | 136 | 83 | - | 2 | |
| Segway GT1 | 523 | 112 | 86 | - | 2 | |
| Segway GT2 | 524 | 113 | 83 | - | 2 | |
| Segway P100S | 529 | 119 | 91 | - | 2 | |
| Segway P65 | 528 | 118 | 91 | - | 2 | |
| Segway SuperScooter GT3 | 10257 | 257 | 192 | 2 | 2 | |
| Segway ZT3 Pro | 10256 | 256 | 191 | 2 | 2 | |
| Segway eKickscooter Ninebot MAX G3/MAX G3 Plus | 10258 | 258 | 192 | 2 | 2 | |
| eKickScooter E3 Series | 10261 | 261 | 145 | 2 | - | |
| eKickScooter F3 | 10259 | 259 | 192 | 2 | 2 |
Mopeds & motorcycles¶
| Family | serverId | HW id | Commands | ble_protocol | encrypt | Live-confirmed |
|---|---|---|---|---|---|---|
| SEGWAY E150S / SEGWAY E250S | 14102 | 4102 | 512 | 2 | 2 | |
| Segway eMoped B | 110 | 73 | 511 | 2 | - | |
| Segway eMoped B | 111 | 86 | 511 | 2 | - | |
| Segway eMoped C | 105 | 67 | 511 | 2 | - | |
| Segway eScooter E | 81 | 66 | 512 | 2 | - | Enc2/gen2 |
| Segway eScooter N | 820 | 89 | 512 | 2 | - |
Self-balancing¶
| Family | serverId | HW id | Commands | ble_protocol | encrypt | Live-confirmed |
|---|---|---|---|---|---|---|
| Ninebot S 2 | 33 | 30 | 98 | 1 | - | |
| Ninebot S L | 39 | 28 | 96 | 2 | - | |
| Ninebot S Nano | 37 | 25 | 83 | 2 | - | |
| Ninebot S Nano | 38 | 27 | 82 | 2 | - | |
| Ninebot S-Max | 35 | 24 | 85 | 1 | - | |
| Ninebot S-Max | 351 | 26 | 92 | 1 | - | |
| Ninebot S-Plus | 6 | 20 | 98 | 2 | - | |
| Ninebot-S | 3 | 3 | 84 | 1 | - | |
| Segway miniLITE | 32 | 22 | 73 | 2 | - |
GoKarts¶
| Family | serverId | HW id | Commands | ble_protocol | encrypt | Live-confirmed |
|---|---|---|---|---|---|---|
| Ninebot Gokart | 7 | 48 | 88 | 2 | - | |
| Ninebot Gokart Pro | 72 | 49 | 93 | 2 | - | |
| Ninebot Gokart Pro Automobili Lamborghini Edition | 73 | 50 | 100 | 2 | - | |
| Segway Gokart Kit 2 | 77 | 57 | 102 | 2 | - | |
| Segway Gokart Pro 2 | 76 | 56 | 116 | 2 | - | |
| Segway Gokart Pro Bumblebee Limited Edition | 74 | 54 | 94 | 2 | - | |
| Segway Gokart Pro Optimus Prime Limited Edition | 75 | 55 | 95 | 2 | - |
Unicycles¶
| Family | serverId | HW id | Commands | ble_protocol | encrypt | Live-confirmed |
|---|---|---|---|---|---|---|
| Ninebot One | 2 | 2 | 52 | 1 | - | |
| Ninebot One A1 | 4 | 19 | 72 | 1 | - | |
| Ninebot One Z | 42 | 18 | 69 | 2 | - |
E-bikes¶
| Family | serverId | HW id | Commands | ble_protocol | encrypt | Live-confirmed |
|---|---|---|---|---|---|---|
| Segway E-bike Muxi | 27153 | 17153 | 166 | 2 | 2 | |
| Segway E-bike Myon | 26384 | 16384 | 165 | 2 | 2 | |
| Segway Xyber | 27152 | 17152 | 166 | 2 | 2 | |
| Xafari | 26640 | 16640 | 159 | 2 | 2 |
Speakers¶
| Family | serverId | HW id | Commands | ble_protocol | encrypt | Live-confirmed |
|---|---|---|---|---|---|---|
| Ninebot Engine Speaker | 1110 | 242 | 5 | 2 | 0 | |
| Segway-Ninebot Engine Speaker 2 | 1111 | 244 | 5 | 2 | 0 | |
| 九号引擎音箱II | 27410 | 17410 | 5 | 2 | 0 |
Power stations¶
| Family | serverId | HW id | Commands | ble_protocol | encrypt | Live-confirmed |
|---|---|---|---|---|---|---|
| Lumina-500 | 20752 | 10752 | 104 | 2 | 2 | |
| Segway Portable Power Station Cube | 1112 | 208 | 104 | 2 | 2 |
Armor kits¶
| Family | serverId | HW id | Commands | ble_protocol | encrypt | Live-confirmed |
|---|---|---|---|---|---|---|
| Ninebot Mecha Kit | 107 | 51 | 104 | 2 | - | |
| Ninebot Mecha Kit | 1071 | 52 | 104 | 2 | - |
Encryption is negotiated at runtime
The encrypt column is the static scan-config default. A device can advertise a higher encryption version, which the app honours at connect time. Segway eScooter E (HW 66 / serverId 81 — the E125S family) carries no static encrypt value yet completes a full Encryption2/gen2 AES handshake on real hardware. Do not infer the wire encryption from this column alone. Note also that E125S (HW 66) and E150S/E250S (HW 4102 / serverId 14102) are separate config families.
Protocol selection¶
Each device's configuration specifies two values that determine the BLE protocol class:
ble_protocol— frame format:1= Protocol 1 (0x55AA),2= Protocol 2 (0x5AA5)encrypt— encryption version:0= XOR/none,2= Encryption2 (AES-CCM),3= Encryption3 (V3Auth)
The app's DynamicDevice.createBleProtocol() selects the protocol class:
ble_protocol + encrypt → Protocol class
protocol=2, encrypt=2 → BleEncryption2Protocol2 (most devices)
protocol=2, encrypt=3 → BleEncryption3Protocol2 (newest devices)
protocol=2, encrypt=0 → BleProtocol2 (XOR only)
protocol=1, encrypt=2 → BleEncryption2Protocol1
protocol=1, encrypt=0 → BleProtocol1 (no encryption)
All BLE protocols use 0x5A 0xA5
Every BLE protocol variant (Protocol 2, Encryption2, Encryption3) uses the same 0x5A 0xA5 header. The 0x5A 0xB5 header is exclusively used by WiFi v2 transport (WifiEncryptionProtocol2), which supports 2-byte length fields for payloads up to 65,535 bytes.
The encrypt value from the config is a default — the actual encryption version can also be determined at runtime from BLE advertisement manufacturer data (manufacturer ID 0x4E42 or 0x4E43).
Protocol class hierarchy¶
BleProtocol1 — 0x55AA, optional XOR
BleProtocol2 — 0x5AA5, optional XOR
BleEncryption2Protocol — 0x5AA5, AES-128 CTR + CBC-MAC (abstract)
├── BleEncryption2Protocol1 — Protocol 1 framing + AES
├── BleEncryption2Protocol2 — Protocol 2 framing + AES (most common)
└── BleEncryption3Protocol2 — Protocol 2 framing + V3Auth
WifiEncryptionProtocol — 0x5AA5, WiFi transport
WifiEncryptionProtocol2 — 0x5AB5, WiFi v2 (extended length)
Encryption3 / V3Auth
No devices in the current scan config have encrypt=3 set statically. Encryption3 support is determined at runtime from the device's BLE advertisement data (encryptProtocolVersion == 3). Devices that support V3Auth use BleEncryption3Protocol2 with a different handshake flow (conectV3() instead of connectGetSN()).