Document BullTron BLE commands
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
# BullTron BLE Command Catalog
|
||||
|
||||
Status: decompiled from BullTron Android app `1.1.33`. Entries are based on code paths, not live BLE captures.
|
||||
|
||||
## Services
|
||||
|
||||
| Service UUID | Purpose | Evidence |
|
||||
| --- | --- | --- |
|
||||
| `0000fff0-0000-1000-8000-00805f9b34fb` | Main BMS service | `BluetoothRegulate` constants and service discovery |
|
||||
| `02f00000-0000-0000-0000-00000000fe00` | Version, secret key, OTA | `BluetoothRegulate` constants and setup writes |
|
||||
| `0000ff00-0000-1000-8000-00805f9b34fb` | WiFi provisioning/config path | WaitConfig constants, not normal BMS telemetry |
|
||||
|
||||
## Characteristics
|
||||
|
||||
| Characteristic UUID | Direction | Purpose |
|
||||
| --- | --- | --- |
|
||||
| `0000fff1-0000-1000-8000-00805f9b34fb` | notify/read | Main BMS response/telemetry frames |
|
||||
| `0000fff2-0000-1000-8000-00805f9b34fb` | write, notify callback registered | Main BMS command frames |
|
||||
| `0000fff3-0000-1000-8000-00805f9b34fb` | write/read | AT-style BLE module/name/band commands |
|
||||
| `02f00000-0000-0000-0000-00000000ff04` | write/read/notify | Version query, `AT+VER=?\r\n` |
|
||||
| `02f00000-0000-0000-0000-00000000ff05` | write/read | Secret key handshake, ASCII `HiLink` |
|
||||
| `02f00000-0000-0000-0000-00000000ff02` | notify/read | OTA response |
|
||||
| `02f00000-0000-0000-0000-00000000ff01` | write | OTA data |
|
||||
|
||||
## Frame Format
|
||||
|
||||
The main BMS protocol is Modbus-like over BLE.
|
||||
|
||||
Read holding/register block:
|
||||
|
||||
```text
|
||||
D203 <start:16-bit> <count:16-bit> <crc16>
|
||||
```
|
||||
|
||||
Single-register write:
|
||||
|
||||
```text
|
||||
D206 <register:16-bit> <value:16-bit> <crc16>
|
||||
```
|
||||
|
||||
Multi-register write:
|
||||
|
||||
```text
|
||||
D210 <start:16-bit> <count:16-bit> <payload:count*2 bytes> <crc16>
|
||||
```
|
||||
|
||||
Password write:
|
||||
|
||||
```text
|
||||
D210 00C9 0003 <utf8 password bytes> <crc16>
|
||||
```
|
||||
|
||||
Time sync write:
|
||||
|
||||
```text
|
||||
D210 00D4 0003 <YY MM DD HH MM SS> <crc16>
|
||||
```
|
||||
|
||||
OTA chunk:
|
||||
|
||||
```text
|
||||
8110 <location> <length> <data> <crc16>
|
||||
```
|
||||
|
||||
The CRC is Modbus CRC16 with polynomial `0xA001`, initial value `0xFFFF`, and the app returns the final word byte-swapped as four uppercase hex digits.
|
||||
|
||||
## Response Format
|
||||
|
||||
For `D203` responses:
|
||||
|
||||
```text
|
||||
D203 <byte_count:8-bit> <payload words> <crc16>
|
||||
```
|
||||
|
||||
`byte_count` is the payload byte length. The live-data response uses `0x7C`, which is 124 bytes / 62 words.
|
||||
|
||||
For `D206` and `D210` responses, the app treats the acknowledgement as a fixed 8-byte / 16-hex-character frame.
|
||||
|
||||
## Commands Observed In App
|
||||
|
||||
| Name | Characteristic | Operation | Payload | Response/Notification | Meaning |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| Secret key | `02f...ff05` | write ASCII | `HiLink` | readback/notify `0100` means OK | Enables version/band setup path |
|
||||
| Query version | `02f...ff04` | write ASCII | `AT+VER=?\r\n` | version notify/read | BLE/app/MCU version query |
|
||||
| Query/change band | `fff3` | write ASCII | `AT+BAND=...` / query variant | AT response | BLE module band/region setup |
|
||||
| Change BLE name | `fff3` | write ASCII | `AT+NAME=<name>` | AT response | Rename BLE module |
|
||||
| Product info | `fff3` | write ASCII | `AT+PRODUCTINFO...` | AT response | Product info/config |
|
||||
| Read live data | `fff2` | write hex frame | `D2030000003E<crc>` | `fff1` notify with byte count `7C` | Reads main 62-word telemetry block |
|
||||
| Read last cell voltages | `fff2` | write hex frame | `D203003E0010<crc>` | `fff1` notify with byte count `20` | Reads last/extra cell voltage block |
|
||||
| Read password | `fff2` | write hex frame | `D20300C90003<crc>` | `fff1` notify with byte count `06` | Reads 3-word password field |
|
||||
| Read residue/calefaction flag | `fff2` | write hex frame | `D20300640001<crc>` | `fff1` notify with byte count `02` | Stores `residueTime`; `0001` also marks heating true |
|
||||
| Sync time | `fff2` | write hex frame | `D21000D40003<YYMMDDHHMMSS><crc>` | `D210` ack | Writes phone time to BMS |
|
||||
| Write password | `fff2` | write hex frame | `D21000C90003<password_hex><crc>` | `D210` ack | Sets password/control code |
|
||||
| Single register write | `fff2` | write hex frame | `D206<register><value><crc>` | `D206` ack | Generic settings/control write |
|
||||
| Multi-register write | `fff2` | write hex frame | `D210<start><count><payload><crc>` | `D210` ack | Generic settings/config write |
|
||||
|
||||
## Live Telemetry Register Map
|
||||
|
||||
Read command:
|
||||
|
||||
```text
|
||||
D203 0000 003E CRC
|
||||
```
|
||||
|
||||
Response dispatch:
|
||||
|
||||
```text
|
||||
D203 7C <62 words> CRC
|
||||
```
|
||||
|
||||
Words are parsed as unsigned 16-bit big-endian hex words before scaling.
|
||||
|
||||
| Register | Index | Scale / Transform | Unit | Field |
|
||||
| ---: | ---: | --- | --- | --- |
|
||||
| `0x0000`-`0x001F` | 0-31 | `raw * 0.001` | V | cell voltages |
|
||||
| `0x0020`-`0x0027` | 32-39 | `raw - 40` | deg C | battery temperature sensors |
|
||||
| `0x0028` | 40 | `raw * 0.1` | V | pack voltage |
|
||||
| `0x0029` | 41 | `(raw - 30000) * 0.1` | A | current; negative/positive sign follows firmware convention |
|
||||
| `0x002A` | 42 | `raw / 10` | % | battery percent / SOC |
|
||||
| `0x002B` | 43 | `raw * 0.001` | V | highest cell voltage |
|
||||
| `0x002C` | 44 | `raw * 0.001` | V | lowest cell voltage |
|
||||
| `0x002F` | 47 | raw enum | state | `1 = charging`, `2 = discharging` in live-time UI |
|
||||
| `0x0030` | 48 | `raw * 0.1` | Ah | remaining capacity |
|
||||
| `0x0032` | 50 | raw count, capped at 8 | count | temperature sensor count |
|
||||
| `0x0033` | 51 | raw | cycles | cycle count |
|
||||
| `0x0035` | 53 | `1 = on` | boolean | charge MOS |
|
||||
| `0x0036` | 54 | `1 = on` | boolean | discharge MOS |
|
||||
| `0x0038` | 56 | `raw * 0.001` | V | cell voltage delta |
|
||||
| `0x003A`-`0x003D` | 58-61 | 16-bit bitmaps | bits | alarm/status words |
|
||||
|
||||
The app applies an extra current correction for two recognized voltage profile pairs from settings registers:
|
||||
|
||||
| Setting values | Correction |
|
||||
| --- | --- |
|
||||
| settings word `0x000C` formats as `3.71` and word `0x000E` formats as `2.71` | multiply current by `3.472` |
|
||||
| settings word `0x000C` formats as `3.72` and word `0x000E` formats as `2.72` | multiply current by `3.37` |
|
||||
|
||||
## Time-To-Empty / Time-To-Full
|
||||
|
||||
The UI computes time from live registers instead of just displaying a raw BLE value:
|
||||
|
||||
```text
|
||||
current_A = abs(decoded register 0x0029)
|
||||
soc_percent = register 0x002A / 10
|
||||
remaining_capacity_Ah = register 0x0030 * 0.1
|
||||
rated_capacity_Ah = parsed settings capacity
|
||||
|
||||
if register 0x002F == 1:
|
||||
label = TimeToFull
|
||||
minutes = rated_capacity_Ah * (100 - soc_percent) / current_A * 60
|
||||
|
||||
if register 0x002F == 2:
|
||||
label = TimetoEmpty
|
||||
minutes = rated_capacity_Ah * soc_percent / current_A * 60
|
||||
```
|
||||
|
||||
If current is zero or the state is neither `1` nor `2`, the UI shows `-- h --m`.
|
||||
|
||||
## Dispatch By Read Byte Count
|
||||
|
||||
`DataAnalysisHelper.analysisPressValueByCan()` dispatches `D203` replies by byte count:
|
||||
|
||||
| Byte count | Meaning in app |
|
||||
| --- | --- |
|
||||
| `7C` | main run/live info |
|
||||
| `20` | last battery/cell voltage block |
|
||||
| `52` | settings info |
|
||||
| `40` | version data |
|
||||
| `06` | password data |
|
||||
| `12` | balancing state |
|
||||
| `0A` | new alarm info |
|
||||
| `4A` | device parameter info |
|
||||
| `04` | communication/protocol or production date |
|
||||
| `FE` | history info |
|
||||
| `18` | serial number |
|
||||
| `02` | residue time / heating flag |
|
||||
| `FC` | Ali/BMS data `0x00`-`0x7D` |
|
||||
| `E0` | Ali/BMS data `0x80`-`0xEF` |
|
||||
| `38` | BLE registers `0x63`-`0x7E` |
|
||||
| `22` | BLE registers `0xDF`-`0xEF` |
|
||||
|
||||
## Caveats
|
||||
|
||||
- This catalog is code-derived. A live BLE capture is still useful to confirm sign conventions, current correction edge cases, and whether a specific BullTron battery firmware requires link-layer encryption.
|
||||
- The app bundles WiFi/Ali IoT flows too; those are separate from the local BLE telemetry path documented here.
|
||||
Reference in New Issue
Block a user