JK-BMS + Grafana in one evening.


New Member
Apr 8, 2023
Apologies for temporarily removing this for a period. I found a few mistakes, too many, decided to pull it and redo.

Aim: DATA! The JK-BMS provides numerical data output for all the various voltages, currents etc. This data is easiest accessed via BLE. (Bluetooth). The aim is to get the data out of the BMS and into Grafana where we can review battery performance in realtime or historically.

The JK-BMS provides multiple interfaces from UART, CAN, RS485 and BLE. I only had a quick attempt at RS485 before finding it led nowhere fast. I found others had success with bluetooth. This is the approach I ended up sticking with as it yielded the best results in the least amount of time.

Items needed:
* An ESP32 (dev board, Node32, WemosMini32, no GPIOs are required)
* Access to an MQTT broker
* Access to an InfluxDB instance
* Access to a grafana instance
* Ability to run some python code, or NodeRed if you wish

The "Access to" items I will briefly cover options.

Connecting the ESP32 to the BMS to get data.

The following github project contains a pre-made ESPHome component for the ESP32. ESPHome, in the sense of how we are going to use it here, is just an ESP32 programming and platform utility. We will only use it to program the ESP32.


Other than ignoring the UART wiring portion, if like me you intent to use only BLE. You are advised to follow the documentation above to get that working. I will tell you what I had to fiddle with to get it working on mine.

I choose the docker-compose route to install ESPHome. Using the following docker-compose.yaml
version: '3'
    container_name: esphome
    image: ghcr.io/esphome/esphome
      - ./config:/config
      - /etc/localtime:/etc/localtime:ro
      - /dev/serial/by-id/usb-Silicon_Labs_CP2104_USB_to_UART_Bridge_Controller_02xx04D-if00-port0:/dev/ttyUSB0
    restart: always
    privileged: true
    network_mode: host

The volume mapping for the usb-Silicon_Labs USB_to_UART is the ESP32 board. There are other options to facilitate the docker seeing the USB adapter. I choose to volume map it.

You don't need to use docker-compose, I advise it, but you can just install ESPHome any other way as well.

I then cloned that github repo. I took the "esp32-ble-example.yaml" example config, copied it into the ESPHome "config" folder and edited the top portion only:
  name: small-battery
  device_description: "JK-BMS 8S Main Pack"
  external_components_source: github://syssi/esphome-jk-bms@main
  mac_address: 20:22:xx:11:09:xx
  # Defaults to "JK02"
  # Please use "JK02_32S" if you own a JK-B2A8S20P >= hardware version 11+ (f.e. JK-B2A8S20P hw 11.XW, sw 11.26)
  # Please use "JK04" if you have some old JK-BMS <= hardware version 3 (f.e. JK-B2A16S hw 3.0, sw. 3.3.0)
  protocol_version: JK02_32S

Name, describe it, change the MAC Address (get from app). Select which proto version your BMS supports.

Optional, but additionally I enabled direct MQTT support by adding a secrets.yaml int he config folder as:
wifi_ssid: mylan
wifi_password: EasyGuessedPassword

mqtt_username: user
mqtt_password: pass

Then uncommented the mqtt: section the main config:
   broker: !secret mqtt_host
   username: !secret mqtt_username
   password: !secret mqtt_password
   id: mqtt_client

If you multiple instances remember to change the "id:".

Flashing to the ESP32, assuming you have got a recognised ttyUSB or other UART device hooked up to it, I ran this:
 docker-compose exec esphome esphome small_battery.yaml run

Teething troubles aside it ran and produced text logging output including BMS data.

Checking the MQTT broker I found topics looking like this:


Number contains the configuration settings.
Switch is the third page on the app for turning stuff ON/OFF.
Sensor is where all the stats live.

At this point you should be able to unplug the ESP32 and move it closer to the BMS, somewhere between the BMS and the WIfi AP is good with good reception on both. You can also point HomeAssistant at it. If that is all you need, you are more or less dane.

Getting data to Grafana... Part 1, InfluxDB.

There are "off the shelf" MQTT to Influx "bridge" projects. Unfortunately I have not browsed these in quite a while having my own in house libraries for same. I will share the git repo link for the code I use, which is unfortunately in two parts. I strongly encourage you to seek a more mainstream project or maintain your own code for this, mine is a bit "janky" in this area with too much copy and paste laziness.

I transform the raw MQTT to a different format (JSON) and publish it to another MQTT. This step is not required, but without putting it here the next part will make no sense!

Then I load those transformed messages into Influx using the HTTP client API. Here:

In english:
Subscribe to the parent topic, say "small-battery/sensor/#
On receiving a message extract the "metric" from the topic, eg: small-battery_state_of_charge (optionally removing the prefix).
Form a JSON structure to conform with the InfluxDB HTTP REST API protocol.
POST that to the REST API using the influx client lib.
In short something like this:
 json_body = [
            "measurement": measurement,
            "tags": {
                "key": device,
                "type": type
            "time": dt,
            "fields": {
                "value": state

def write_json(json_body):
    client.write_points(json_body)#, retention_policy="one_year")

You could also do this from NodeRed or similar application if you desire, whatever works.

Assuming you got the data into influx-db, the rest of the effort is in setting up your grafana dash boards.

Here are a few snapshots of mine:
The Main JK_BMS dash (with a Cameo appearance of the MPPT stats and some ambient temp sensors).
(Yes, I am still trying to get a top balance finished :) We trying with the multiplus charger last night after the sun let me down yesterday).

The realtime dashboard, "kiosk" style, single screen of the whole house.

My docker-compose where I get all of this to run together as one platform:
Last edited:
So, turned out to be sunny today and I got to test a whole bunch of stuff at the same time.

This link is to a snapshot of the tests.

1. Does the end-2-end graphing solution work? PASS
2. Does the BMS work? PARTIAL PASS
3. Will it fully top charge the cells to 3.65V? PASS
4. Does the balancer work? PASS
5. Is the MPPT charge controller in balance with the BMS/Balancer? PASS

Feel free to interact. It would seem the main plot line was cell number 4 being the guy at the back. The MPPT did a stellar job, helped by the balancer will taper the current right back to only 1 Amp and waited paitently. I was worried the "Boost" phase would end before I got that near perfect flat cell voltage line, but luckily it stayed in boost. (Then sun went away and the rain started).
Cool. Looking to do the same. Any particular esp32 you bought?
I use these:

With a bare ESP32-VROOM-32D Espressif modules which "clip" in.

I have a "parent" PCB which has an ESP32, STM32F411 and a 2.8"TFT screen which I use for various projects.

It depends on project, this one could use the screen so it might go that way. If it doesn't then I'd just go for a generic ESP32 board, maybe a WeMosMini32, maybe a basic ESP32Dev board or a Lola. I prefer the ones which comes without the pin headers soldered on.

In the specific case of the JK-BMS BLE to MQTT there are no additional connections. I may actually just solder a 3.3V reg onto some wires, wrap it in headshrink and fill it with hot glue.
Thanks! can you share details on how you went from MQTT to influxes and the configuration for grafana?
A caveat / annoying bug.
The BMS only supports a single BLE connection. So if you have this MQTT bridge feeding on it every 5 seconds, it can become very difficult to use the app. The only "work around" I have right now is a switch on the ESP32 to temporarily disable it while I tweak BMS settings on the app.
Last edited:
Sorry I needed to take it down temporarily, there were mistakes in it. I'll restore it this week without the errors.
A note on Grafana graph config.

I'm torn on the multi-unit graphs. I am also torn on the split axis.

By default grafana puts the main axis legend down the left. However the most recent data and the area your drawn to is on the right.

So when you try, like I have and mix units, such as "balancer Amps with cell delta V" you get Amps on the right and volts on the left. I constantly end up reading the wrong axis.

I am thinking in future I shall abandon most, maybe not all multi-unit graphs and move all axis to the right hand side.

I am slowly trying to work out Grafana's "Alerting" system which is relatively new. If I get any easy wins on useful notification mechanisms based on battery errors say I'll post it.
I got ESPHome to work on an ESP32S3 device now and MQTT. Is there a grafana config I can refer to and why not directly from grafana using MQTT plugin to get the data?
The only grafana config I have is the JSON model export. Grafana is usually the easy part and how you build you graphs is part of the customisation and fun! I haven't gone as far as to create an exportable dashboard or anything.

I haven't used the MQTT plug in. It looks like it only allows you to see realtime data, rather than historical over time. Could be handy for somethings.

These are examples of basic bridging techniques. Telegraf is popular as it also produces metrics about the host it's running on, like CPU, Memory, Disk, Network etc.

Of course, almost all parts of this setup are optional and have alternatives. There are influxdb alternatives like promethius.

Once the data is in a grafana datasource (like influx) it should be pretty intuitive. You just select the datasource, the "measurement" and pick which "items" you want. Group by "Key" and then it's just playing with the visualisation/graph cosmetrics.

Here is my cell voltage graph query as an example:
Man, i'm having a heck of a time configuring telegraph to pull the MQTT topic for the jk_bms ESPHome and put it into influx. Complains about formatting and values, strings, etc. Do you have the telegraf for reference?
There are a few String formatted items in the topics, which aren't suitable for influx.

The formatted total runtime for example.

As I mentioned I used python, I'm not sure how much this helps you, but it's how I assigned the units. Those at the end with "none" just get dropped on the next hop and don't go to Influx.

if "voltage" in sensor_topic:
        json_out.data["units"] = "V"
        value = float(message.payload)
    elif "current" in sensor_topic:
        json_out.data["units"] = "A"
        value = float(message.payload)
    elif "power" in sensor_topic:
        json_out.data["units"] = "W"
        value = float(message.payload)
    elif "temperature" in sensor_topic:
        json_out.data["units"] = "C"
        value = float(message.payload)
    elif "state_of_charge" in sensor_topic:
        json_out.data["units"] = "%"
        value = float(message.payload)
    elif "capacity" in sensor_topic:
        json_out.data["units"] = "Ah"
        value = float(message.payload)
    elif "total_runtime" in sensor_topic and "formatted" not in sensor_topic:
        json_out.data["units"] = "S"
        value = float(message.payload)
    elif "resistance" in sensor_topic:
        json_out.data["units"] = "mR"
        value = float(message.payload)
        json_out.data["units"] = "none"
        value = message.payload.decode("UTF-8")
What cable do you guys use to connect to JK BMS. I hake no idea what I'm looking for. I have usb. I just need plug for BMS GPS port
What cable do you guys use to connect to JK BMS. I hake no idea what I'm looking for. I have usb. I just need plug for BMS GPS port
Must be 4pins 1.25mm pitch (JST 1.25mm). I could not find pre-made cable, ended up buying this
The GPS port I believe is a 4 pin MicroJST.

Be warned it's extremely fragile. The GPS port does not provide USB, it provides either CAN or RS845. it's not a standard protocol but a custom botch over ModBusTCP.

This is why i liked that BT worked. that leaves teh GPS port free for teh battery power button as well!

Also note the VCC on that port is battery voltage. If you connect a 12V device or a 5V device it will require a buck converter. The same can be said for the JK-BMS screens. It's one reason they are "correct" when they state you need to buy the correct cable, from them, for the exact version of BMS/Screen etc. Not an easy task! The screen cables (which I believe are CAN adaptors) have a buck converter in them.
Must be 4pins 1.25mm pitch (JST 1.25mm). I could not find pre-made cable, ended up buying this
I used only the GND, TX and RX pins. they are 3.3v TTL.
Here is my sample test communication packet which is very similar to what they show in their 'BMS-RS485Communication protocol.pdf' document:


  • JK BMS test.txt
    2.3 KB · Views: 11
Hi Venquessa, have you been able to manage the balancer switch operation?
I am trying to understand how can I switch it on and off without using the JK app.
Any help will be greatly appreciated, thank you in advance.