Add Berger LFP BLE command notes and client
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
# Berger LFP BLE Flow
|
||||
|
||||
This is the app flow used to obtain battery information such as discharge
|
||||
current, SOC, voltage, temperatures, cell voltages, MOS state, and estimated
|
||||
charge/discharge time.
|
||||
|
||||
## Evidence
|
||||
|
||||
- App package: `com.jbd.berger`
|
||||
- Version: `1.0.3`
|
||||
- Main bundle: `assets/apps/__UNI__F61076D/www/app-service.js`
|
||||
- Source-map style log labels embedded in bundle:
|
||||
- `utils/BLE.ts`
|
||||
- `App.vue`
|
||||
- dashboard/control/parameter pages
|
||||
|
||||
## Connection Sequence
|
||||
|
||||
1. `uni.openBluetoothAdapter()`
|
||||
2. `uni.startBluetoothDevicesDiscovery()` with service filter `ff00`
|
||||
3. `uni.onBluetoothDeviceFound()` records devices and RSSI
|
||||
4. `uni.createBLEConnection()` with 10 second timeout
|
||||
5. `uni.getBLEDeviceServices()`
|
||||
6. `uni.getBLEDeviceCharacteristics()`
|
||||
7. `uni.notifyBLECharacteristicValueChange()` on `ff01`
|
||||
8. `uni.onBLECharacteristicValueChange()` buffers incoming bytes
|
||||
9. `uni.writeBLECharacteristicValue()` sends command chunks to `ff02` with
|
||||
`writeType: "writeNoResponse"`
|
||||
|
||||
The app chunks outgoing buffers into 20-byte pieces before writing.
|
||||
|
||||
## Services And Characteristics
|
||||
|
||||
- Service: `0000ff00-0000-1000-8000-00805f9b34fb`
|
||||
- Notify/read: `0000ff01-0000-1000-8000-00805f9b34fb`
|
||||
- Write: `0000ff02-0000-1000-8000-00805f9b34fb`
|
||||
|
||||
## Pairing / Bonding
|
||||
|
||||
- Needs Android bond before normal telemetry: likely no.
|
||||
- Evidence: the app uses uni-app BLE APIs for connection, service discovery,
|
||||
notifications, and writes. I did not find a normal-path bond request in the
|
||||
app bundle.
|
||||
- Caveat: a peripheral firmware could still enforce encryption independently,
|
||||
but the app flow itself does not show pairing as a telemetry prerequisite.
|
||||
|
||||
## Getting Live Values
|
||||
|
||||
The app sends:
|
||||
|
||||
```text
|
||||
DD A5 03 00 FF FD 77
|
||||
```
|
||||
|
||||
The response uses:
|
||||
|
||||
```text
|
||||
DD 03 <status> <length> <payload> <checksum> 77
|
||||
```
|
||||
|
||||
Important payload fields for command `0x03`:
|
||||
|
||||
| Payload bytes | Formula | Unit | Field |
|
||||
| ---: | --- | --- | --- |
|
||||
| `0..1` | big-endian / 100 | V | pack voltage |
|
||||
| `2..3` | signed big-endian / 100 | A | current |
|
||||
| `4..5` | big-endian / 100 | Ah | remaining capacity |
|
||||
| `6..7` | big-endian / 100 | Ah | nominal capacity |
|
||||
| `8..9` | raw | cycles | cycle count |
|
||||
| `10..11` | JBD bitfield | date | production date |
|
||||
| `12..13` | nonzero bitmap | boolean | balancing |
|
||||
| `16..17` | nonzero bitmap | boolean | protection |
|
||||
| `18` | decimal digits | version | software version |
|
||||
| `19` | raw | % | SOC |
|
||||
| `20` | `1 = charge`, `2 = discharge`, `3 = both` | boolean | MOS state |
|
||||
| `22` | raw count | count | temperature sensor count |
|
||||
| `23..` | `(raw - 2731) / 10` | deg C | temperatures |
|
||||
|
||||
Production date bitfield:
|
||||
|
||||
```text
|
||||
day = value & 0x1F
|
||||
month = (value >> 5) & 0x0F
|
||||
year = 2000 + (value >> 9)
|
||||
```
|
||||
|
||||
Estimated time is computed locally:
|
||||
|
||||
```text
|
||||
if current_A > 0:
|
||||
time_to_full = (nominal_Ah - remaining_Ah) / current_A
|
||||
if current_A < 0:
|
||||
time_to_empty = remaining_Ah / abs(current_A)
|
||||
```
|
||||
|
||||
## Cell Voltages
|
||||
|
||||
The app sends:
|
||||
|
||||
```text
|
||||
DD A5 04 00 FF FC 77
|
||||
```
|
||||
|
||||
The response command `0x04` payload is a sequence of big-endian 16-bit cell
|
||||
voltages scaled by `0.001 V`.
|
||||
Reference in New Issue
Block a user