Files
bulltron-ble-commands/README.md
T

33 lines
2.0 KiB
Markdown

# BullTron BLE Commands
Reverse-engineering notes for the BullTron Android app BLE protocol.
## Target App
- App label: BullTron
- Package: `com.inuker.bluetooth.bulltron`
- Version analyzed: `1.1.33` / `1133001`
- XAPK source: APKPure direct download
- XAPK SHA-256: `35388e6c2b9afeeb4bafd97df09fcb1e33427802dd98f74a2a4648099dda71ff`
- Base APK SHA-256: `f1d486b410c1fa2fae78837fcc27a63aa16c6cb1b45f096a17c9968908add363`
- Signer CN: `smart_daly`
- Signer cert SHA-256: `996caf450ecdb34d0ba45d2b2c6a2df56243338c7be3b7b497168af4e3d00ae4`
The XAPK was unpacked and the base APK code was verified against the separately mirrored PGYER APK: all three DEX files have identical SHA-256 hashes. The APK was decompiled with apktool and JADX. JADX reported some failed methods, so a few UI mappings were cross-checked against smali.
## Main Finding
Normal telemetry does not use the standard BLE Battery Service. The app connects as a BLE GATT client, subscribes to a custom BullTron/Daly-style service, writes Modbus-like frames to a write characteristic, then parses notify frames from a read/notify characteristic.
Android pairing/bonding is not explicitly required in the app's normal BMS flow. The core path uses `connect`, MTU request, service discovery, notifications, and writes. Generic library code contains bonding helpers, but the BullTron telemetry path does not call `createBond()`.
## Documents
- `docs/ble-flow.md` - connection/setup/query flow, pairing answer, and value derivation
- `docs/command-catalog.md` - services, characteristics, command frames, and telemetry register map
- `tools/extract-ble-symbols.py` - helper for scanning JADX/apktool output for BLE UUIDs and GATT calls
## Status
The local repo contains the reverse-engineering results. Pushing to `git@git.mannheim.ccc.de:C3MA/bulltron-ble-commands.git` is currently blocked because C3MA Gitea does not allow organization push-to-create for this repo. Create an empty `C3MA/bulltron-ble-commands` repository or provide a token with repo creation rights, then push `main`.