Last active
March 17, 2025 11:55
-
-
Save hwinkelmann/00bd08f4e99dc2e67936da276a66601b to your computer and use it in GitHub Desktop.
Read data from a LIONTRON battery
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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