3.7 KiB
Berger LFP BLE Commands
Reverse-engineering notes for the Berger LFP Android app BLE protocol.
This repository documents the custom JBD-style BLE GATT protocol used by the Berger LFP Android app to read battery telemetry such as SOC, current, voltage, remaining capacity, cell voltages, temperatures, MOS state, and estimated charge/discharge time.
Target App
- App label: Berger LFP
- Package:
com.jbd.berger - Version analyzed:
1.0.3/8 - XAPK source: APKPure direct download for Play package
com.jbd.berger - XAPK SHA-256:
962eb7d0c62a34e03bfbe034632fd227e0f352cd66fac9ac3d77166cec0abb5e - Base APK SHA-256:
aa2325cfe3777824657f0ade0c381cf4bc296f9630179e0d33ed4eb56d78c1bb - Signer CN:
Unknown - Signer cert SHA-256:
ec11c6d3260adecb382186a61207e61657834b3b025e3ca31bc6ef4d88f720f9
The XAPK was unpacked and the base APK was decompiled with apktool. The app is
a DCloud/uni-app package, so the useful BLE logic is in
assets/apps/__UNI__F61076D/www/app-service.js.
Main Finding
Berger LFP does not use the standard BLE Battery Service. It connects as a BLE
GATT client, scans for a custom service ff00, subscribes to notifications on
ff01, and writes JBD command frames to ff02.
Android pairing/bonding does not appear to be required by the app flow. The normal path is adapter init, scan, connect, service discovery, notification enable, and command writes.
Quick Start
Build the main live-data read frame:
python3 tools/berger_frame.py read 0x03
Expected output:
DDA50300FFFD77
Send that frame to characteristic 0000ff02-0000-1000-8000-00805f9b34fb
after subscribing to notifications on
0000ff01-0000-1000-8000-00805f9b34fb.
Local Desktop App
This repo includes a small Python GUI client that can scan for Berger/JBD-style BLE devices, connect, poll telemetry, and display decoded values locally.
Debian
sudo apt update
sudo apt install python3 python3-venv python3-pip python3-tk bluez
python3 -m venv .venv
. .venv/bin/activate
python3 -m pip install -r requirements.txt
python3 berger_gui.py
If scanning finds no devices, check that Bluetooth is powered and unblocked:
rfkill list bluetooth
bluetoothctl power on
bluetoothctl scan on
Windows 11
py -3 -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
python berger_gui.py
The GUI uses native WinRT Bluetooth through bleak on Windows.
App Workflow
The app's telemetry flow is:
- Open the Bluetooth adapter.
- Start BLE discovery filtered to service
0000ff00-0000-1000-8000-00805f9b34fb. - Connect to the selected peripheral.
- Discover services and characteristics.
- Subscribe to notifications on
ff01. - Write JBD read frames to
ff02. - Buffer notify chunks, split complete
DD ... 77frames, validate checksum, and parse the response payload into UI state.
Minimal BLE Workflow
-
Connect to the device over BLE GATT.
-
Discover services.
-
Subscribe to notifications on
ff01under serviceff00. -
Write the base-data read frame to
ff02:DDA50300FFFD77 -
Write the cell-voltage read frame to
ff02:DDA50400FFFC77 -
Parse notifications from
ff01.
Caveats
- This catalog is code-derived from the Android app bundle, not yet confirmed against a live HCI capture.
- The desktop app currently implements read-only telemetry. The Android app has charge/discharge MOS and factory/name/capacity write paths; those are documented, but deliberately not exposed as GUI buttons yet.
- Only one phone/client can normally hold the battery GATT connection at a time. Close the Android app before connecting from a PC.