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:

  1. Open the Bluetooth adapter.
  2. Start BLE discovery filtered to service 0000ff00-0000-1000-8000-00805f9b34fb.
  3. Connect to the selected peripheral.
  4. Discover services and characteristics.
  5. Subscribe to notifications on ff01.
  6. Write JBD read frames to ff02.
  7. Buffer notify chunks, split complete DD ... 77 frames, validate checksum, and parse the response payload into UI state.

Minimal BLE Workflow

  1. Connect to the device over BLE GATT.

  2. Discover services.

  3. Subscribe to notifications on ff01 under service ff00.

  4. Write the base-data read frame to ff02:

    DDA50300FFFD77
    
  5. Write the cell-voltage read frame to ff02:

    DDA50400FFFC77
    
  6. 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.
S
Description
Berger Android app BLE protocol reverse engineering: services, characteristics, command frames, CRC helper, and telemetry register map for SOC, current, voltage, capacity, and time-to-empty
Readme 36 KiB
Languages
Python 100%