bin+lib ubmsc

A client for Battery Management Systems (BMS)

2 releases

0.1.1 Sep 12, 2024
0.1.0 Sep 11, 2024

#33 in Visualization

Download history 158/week @ 2024-09-05 303/week @ 2024-09-12 31/week @ 2024-09-19 33/week @ 2024-09-26 10/week @ 2024-10-03

535 downloads per month

MIT license

105KB
2K SLoC

BMS BLE tool

github crate docs MIT CI

This is a tool for interacting with some customer-grade Battery Management Systems (BMS).

Inplemented features

  • Discovering compatible BLE devices
  • Identifying devices by address or name
  • Querying device info
  • Fetching cells data
  • Command-line interface
  • Prometheus exporter
  • Prometheus push gateway client

Supported models and firmware versions

Vendor Model HW Version SW Version
JiKong BMS BD4A8S4P 15A 15.26

I'm happy to add support for other models in the future. Please open PR or create issue.

Crate usage examples

Get device info and cells data by device name:

use btleplug::{api::Manager as _, platform::Manager};
use ubmsc::Client;

#[tokio::main(flavor = "current_thread")]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let manager = Manager::new().await?;

    let adapter = manager
        .adapters()
        .await?
        .into_iter()
        .next()
        .ok_or("No adapters found")?;

    let client = Client::new(&adapter, &"UPS_BMS".into(), &Default::default());

    let info = client.device_info().await?;
    println!("{info:?}");

    let data = client.cell_data().await?;
    println!("{data:?}");

    client.close().await?;

    Ok(())
}

Find available BMS devices and print device info:

use btleplug::{api::Manager as _, platform::Manager};
use ubmsc::Client;

#[tokio::main(flavor = "current_thread")]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let manager = Manager::new().await?;

    let adapter = manager
        .adapters()
        .await?
        .into_iter()
        .next()
        .ok_or("No adapters found")?;

    for device in Client::find(&adapter, &Default::default()).await? {
        let client = Client::new(&adapter, &"UPS_BMS".into(), &Default::default());

        let name = client.device_name().await?;
        let info = client.device_info().await?;
        println!("{name}");
        println!("{info:?}");

        client.close().await?;
    }

    Ok(())
}

Command-line usage examples

Show help:

$ ubmsc --help`
Usage: ubmsc [-v] [-l <filter>] [-j] [-t <seconds>] [-r <seconds>] [-d <address...>]
             [-f <format>] [-i] [-c] [-e] [-p] [-u <url>] [-s <seconds>]

Battery Management Systems (BMS) interface.

When passed both -e and -p options push client will be run in continuous mode with specified interval.

Options:
  -v, --version                    Show version and exit.
  -l, --log <filter>               Logging filter (example: jk_bms=debug)
  -j, --journal                    Enable log to journald (log to stderr by default)
  -t, --scan-timeout <seconds>     Bluetooth scanning timeout in seconds (30 by default)
  -r, --request-timeout <seconds>  Bluetooth request timeout in seconds (5 by default)
  -d, --devices <address>          Device addresses or names (will try to scan if nothing passed)
  -f, --format <format>            Data format: rust(r) (by default) rust-pretty(R) json(j)
                                   json-pretty(J) yaml(y) toml(t) toml-pretty(T) metrics(m)
  -i, --device-info                Show device info
  -c, --cell-data                  Show cell data
  -e, --exporter                   Run prometheus exporter
  -p, --push                       Run prometheus push gateway client
  -u, --url <url>                  Prometheus exporter URL to listen/connect
  -s, --scrape-interval <seconds>  Metrics scraping interval (60s by default)
  -h, --help                       Show this help message and exit.

Get device info by device name and output in JSON format:

$ ubmsc -f J -i -d UPS_BMS
{
  "device_info": [
    {
      "device_model": "JK_BD4A8S4P",
      "hardware_version": "15A",
      "software_version": "15.26",
      "up_time": 1709100,
      "poweron_times": 1,
      "device_name": "UPS_BMS",
      "device_passcode": "1234",
      "manufacturing_date": "240818",
      "serial_number": "40531310629",
      "passcode": "000",
      "userdata": "JK-BMS",
      "setup_passcode": "123456789",
      "userdata2": "JK-BMS"
    }
  ]
}

Scan BLE to find devices and print device info and cells data in TOML format:

$ ubmsc -f t -i -c
[[device_info]]
device_model = "JK_BD4A8S4P"
hardware_version = "15A"
software_version = "15.26"
up_time = 1707500
poweron_times = 1
device_name = "UPS_BMS"
device_passcode = "1234"
manufacturing_date = "240818"
serial_number = "40531310629"
passcode = "000"
userdata = "JK-BMS"
setup_passcode = "123456789"
userdata2 = "JK-BMS"
[[cell_data]]
cell_voltage = [2.384000062942505, 2.384000062942505, 2.383000135421753, 2.384000062942505, 2.384000062942505, 2.384000062942505]
average_cell_voltage = 2.384000062942505
delta_cell_voltage = 0.0010000000474974513
balance_current = 1.0240000486373901
cell_resistance = [0.1380000114440918, 0.13700000941753387, 0.14000000059604645, 0.1380000114440918, 0.13900001347064972, 0.13900001347064972]
battery_voltage = 14.304000854492188
battery_power = 2.2310001850128174
battery_current = 0.15600000321865082
battery_temperature = [23.200000762939453, 23.600000381469727]
mosfet_temperature = 25.399999618530273
remain_percent = 100
remain_capacity = 12.000000953674316
nominal_capacity = 12.000000953674316
cycle_count = 1
cycle_capacity = 18.464000701904297
up_time = 1707600

Show BMS cell data in Prometheus metrics format:

$ ubmsc -f metrics -c -d UPS_BMS
# HELP average_cell_voltage Average voltage of cells, V
# TYPE average_cell_voltage gauge
average_cell_voltage{device="UPS_BMS"} 2.385000228881836
# HELP balance_current Cells balance current, A
# TYPE balance_current gauge
balance_current{device="UPS_BMS"} 0
# HELP battery_current Current of battery, A
# TYPE battery_current gauge
battery_current{device="UPS_BMS"} 0.07800000160932541
# HELP battery_power Power of battery, W
# TYPE battery_power gauge
battery_power{device="UPS_BMS"} 1.1160000562667847
# HELP battery_temperature Temperatures of battery, ℃
# TYPE battery_temperature gauge
battery_temperature{cell="0",device="UPS_BMS"} 22.80000114440918
battery_temperature{cell="1",device="UPS_BMS"} 23.200000762939453
# HELP battery_voltage Voltage of battery, V
# TYPE battery_voltage gauge
battery_voltage{device="UPS_BMS"} 14.308000564575195
# HELP cell_resistance Resistances of cells, Ω
# TYPE cell_resistance gauge
cell_resistance{cell="0",device="UPS_BMS"} 0.1380000114440918
cell_resistance{cell="1",device="UPS_BMS"} 0.13700000941753387
cell_resistance{cell="2",device="UPS_BMS"} 0.14000000059604645
cell_resistance{cell="3",device="UPS_BMS"} 0.1380000114440918
cell_resistance{cell="4",device="UPS_BMS"} 0.13900001347064972
cell_resistance{cell="5",device="UPS_BMS"} 0.13900001347064972
# HELP cell_voltage Voltages of cells, V
# TYPE cell_voltage gauge
cell_voltage{cell="0",device="UPS_BMS"} 2.386000156402588
cell_voltage{cell="1",device="UPS_BMS"} 2.384000062942505
cell_voltage{cell="2",device="UPS_BMS"} 2.384000062942505
cell_voltage{cell="3",device="UPS_BMS"} 2.384000062942505
cell_voltage{cell="4",device="UPS_BMS"} 2.384000062942505
cell_voltage{cell="5",device="UPS_BMS"} 2.384000062942505
# HELP cycle_capacity Cycle capacity, A·h
# TYPE cycle_capacity counter
cycle_capacity{device="UPS_BMS"} 19.117000579833984
# HELP cycle_count Number of battery cicles
# TYPE cycle_count counter
cycle_count{device="UPS_BMS"} 1
# HELP delta_cell_voltage Delta voltage of cells, V
# TYPE delta_cell_voltage gauge
delta_cell_voltage{device="UPS_BMS"} 0
# HELP mosfet_temperature Temperature of mosfet, ℃
# TYPE mosfet_temperature gauge
mosfet_temperature{device="UPS_BMS"} 24.899999618530273
# HELP poweron_times Number of poweron cicles
# TYPE poweron_times counter
poweron_times{device="UPS_BMS"} 1
# HELP remain_capacity Remain capacity of battery, A·h
# TYPE remain_capacity gauge
remain_capacity{device="UPS_BMS"} 12.000000953674316
# HELP remain_percent Remain capacity of battery, %
# TYPE remain_percent gauge
remain_percent{device="UPS_BMS"} 100
# HELP up_time Time since last poweron, S
# TYPE up_time counter
up_time{device="UPS_BMS"} 1770773

Run prometheus exporter for specified devices (with logging to journald):

$ ubmsc -e -u http://127.0.0.1:9898/metrics -l ubmsc=debug -j -d UPS_BMS -d SOLAR_BMS

Run prometheus pushgateway client continuously to export to VictoriaMetrics:

$ ubmsc -e -p -u http://127.0.0.1:8428/api/v1/import/prometheus -l ubmsc=info -j -d UPS_BMS -d SOLAR_BMS

Alternative solutions

  • MPP-Solar Python module and command-line tools to work with BMS. Has support several models of different vendors. Doesn't work with JK-BMS with latest firmwares (>11.x).
  • esphome-jk-bms Component for ESPHome to interact with JK-BMS. Not tested.

Dependencies

~8–39MB
~599K SLoC