Skip to content

Instantly share code, notes, and snippets.

@hwinkelmann
Last active March 17, 2025 11:55
Show Gist options
  • Select an option

  • Save hwinkelmann/00bd08f4e99dc2e67936da276a66601b to your computer and use it in GitHub Desktop.

Select an option

Save hwinkelmann/00bd08f4e99dc2e67936da276a66601b to your computer and use it in GitHub Desktop.
Read data from a LIONTRON battery
// This is a POC that reads data from a Jiabaida BMS, as it is integrated
// in the Liontron battery that I have.
// It's basically the same information as it is displayed in the buggy app that
// comes with it.
const {createBluetooth} = require('node-ble')
const {bluetooth, destroy} = createBluetooth()
// BLE adress of the battery - this will be different from battery to battery
const DEVICE_ADRESS = "A4:C1:38:C5:96:C9";
// These UUIDs stay the same, they are hard-coded into the app
const SERVICE = "0000ff00-0000-1000-8000-00805f9b34fb";
const CHARACTERISTIC = "0000ff01-0000-1000-8000-00805f9b34fb";
const RW_CHARACTERISTIC = "0000ff02-0000-1000-8000-00805f9b34fb";
async function main() {
const { bluetooth, destroy } = createBluetooth()
const adapter = await bluetooth.defaultAdapter()
const device = await adapter.waitDevice(DEVICE_ADRESS)
console.log("found device", await device.getAddress(), await device.getName());
await device.connect();
console.log("connected");
const gattServer = await device.gatt()
const service = await gattServer.getPrimaryService(SERVICE);
const readCharacteristic = await service.getCharacteristic(CHARACTERISTIC);
const writeCharacteristic = await service.getCharacteristic(RW_CHARACTERISTIC);
await readCharacteristic.startNotifications()
readCharacteristic.on('valuechanged', buffer => {
if (buffer.length < 7)
return;
if (buffer[0] === 0xdd && buffer[1] === 0x03)
decodeBaseInfo(buffer);
});
// Periodically query data
setInterval(() => {
// dispatch a BMSBaseInfoCMDEntity
const buffer = Buffer.from([0xdd, 0xa5, 0x03, 0x00, 0xff, 0xfd, 0x77]);
rwChar.writeValue(buffer);
}, 1000);
}
function decodeBaseInfo(buffer) {
console.log("total voltage: " + shortToFloat(buffer[4], buffer[5], 100) + "V");
console.log("current: " + shortToFloat(buffer[6], buffer[7], 100) + "A");
console.log("remainingPower: " + shortToFloat(buffer[8], buffer[9], 100) + "Ah");
console.log("nominalPower: " + shortToFloat(buffer[10], buffer[11], 100) + "Ah");
console.log("cycles: " + shortToFloat(buffer[12], buffer[13], 1));
}
function shortToFloat(high, low, scale) {
const value = ((high & 255) << 8) + (low & 255);
const sign = (high >> 7) === 0 ? 1 : -1;
if ((high >> 7) === 0)
return value / scale;
return (value - 0x10000) / scale;
}
main().then(console.log).catch(() => {
device.disconnect();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment