Never Mind… The issue was that the TYPE should always be lower case.
As using the internal Bluetooth from your server can cause issues with range and such I put together another solution.
It is very robust
Stuff needed:
ESP32 module
Lcd2004 display(optional)
Spare time
Instead of letting the server connect we use a ESP32 Arduino instead. These have Bluetooth and WiFi. So it can grab the battery data from the BMS for us over BLE and then send them over to homeassistant over WiFi.
The functionality is the same as the batmon addon, except it doesn’t use MQTT and works straight with ESPhome(.yaml at end of post)
To add something extra to it I added an LCD that shows your current battery data:
substitutions:
name: 12s5pbattery
device_description: "Monitor and control a Xiaoxiang Battery Management System (JBD-BMS) via BLE"
external_components_source: github://syssi/esphome-jbd-bms@main
mac_address: xx:xx:xx:xx:xx:xx
esphome:
name: ${name}
comment: ${device_description}
project:
name: "syssi.esphome-jbd-bms"
version: 1.4.0
esp32:
board: esp32dev
framework:
type: esp-idf
external_components:
- source: ${external_components_source}
refresh: 0s
wifi:
ssid: "xxxxxxxx"
password: "xxxxxxx"
manual_ip:
static_ip: 192.168.1.188
gateway: 192.168.1.1
subnet: 255.255.255.0
api:
encryption:
key: "xxxxxxxxxxxxxxxxxxxx="
ota:
password: "xxxxxxxxxxxxxxxxx"
logger:
level: DEBUG
i2c:
sda: GPIO16
scl: GPIO17
display:
- platform: lcd_pcf8574
dimensions: 16x2
address: 0x27
lambda: |-
switch (id(page)){
case 1:
it.printf("Total:""%.3fV", id(total_voltage).state);
it.printf(0, 1, "Avg:""%.3fV", id(avgcell).state);
break;
case 2:
it.printf("Charging:""%d", id(charge).state);
it.printf(0, 1, "Delta:""%.3fV", id(deltacell).state);
break;
case 3:
it.printf("Current:""%.3fA", id(current).state);
it.printf(0, 1, "Temp:""%.1fC", id(temp2).state);
break;
}
globals:
- id: page
type: int
initial_value: "1"
interval:
- interval: 4s
then:
- lambda: |-
id(page) = (id(page) + 1);
if (id(page) > 3) {
id(page) = 1;
}
esp32_ble_tracker:
on_ble_advertise:
then:
- lambda: |-
if (x.get_name().rfind("xiaoxiang", 0) == 0) {
ESP_LOGI("ble_adv", "New JBD-BMS found");
ESP_LOGI("ble_adv", " Name: %s", x.get_name().c_str());
ESP_LOGI("ble_adv", " MAC address: %s", x.address_str().c_str());
ESP_LOGD("ble_adv", " Advertised service UUIDs:");
for (auto uuid : x.get_service_uuids()) {
ESP_LOGD("ble_adv", " - %s", uuid.to_string().c_str());
}
}
ble_client:
- id: client0
mac_address: ${mac_address}
jbd_bms_ble:
- id: bms0
ble_client_id: client0
update_interval: 30s
binary_sensor:
- platform: jbd_bms_ble
jbd_bms_ble_id: bms0
balancing:
name: "${name} balancing"
charging:
name: "${name} charging"
discharging:
name: "${name} discharging"
online_status:
name: "${name} online status"
sensor:
- platform: jbd_bms_ble
jbd_bms_ble_id: bms0
battery_strings:
name: "${name} battery strings"
current:
name: "${name} current"
id: current
power:
name: "${name} power"
charging_power:
name: "${name} charging power"
discharging_power:
name: "${name} discharging power"
state_of_charge:
name: "${name} state of charge"
nominal_capacity:
name: "${name} nominal capacity"
charging_cycles:
name: "${name} charging cycles"
capacity_remaining:
name: "${name} capacity remaining"
battery_cycle_capacity:
name: "${name} battery cycle capacity"
total_voltage:
name: "${name} total voltage"
id: total_voltage
average_cell_voltage:
name: "${name} average cell voltage"
id: avgcell
delta_cell_voltage:
name: "${name} delta cell voltage"
id: deltacell
min_cell_voltage:
name: "${name} min cell voltage"
max_cell_voltage:
name: "${name} max cell voltage"
min_voltage_cell:
name: "${name} min voltage cell"
max_voltage_cell:
name: "${name} max voltage cell"
temperature_1:
name: "${name} temperature 1"
id: temp1
temperature_2:
name: "${name} temperature 2"
id: temp2
temperature_3:
name: "${name} temperature 3"
cell_voltage_1:
name: "${name} cell voltage 1"
cell_voltage_2:
name: "${name} cell voltage 2"
cell_voltage_3:
name: "${name} cell voltage 3"
cell_voltage_4:
name: "${name} cell voltage 4"
cell_voltage_5:
name: "${name} cell voltage 5"
cell_voltage_6:
name: "${name} cell voltage 6"
cell_voltage_7:
name: "${name} cell voltage 7"
cell_voltage_8:
name: "${name} cell voltage 8"
cell_voltage_9:
name: "${name} cell voltage 9"
cell_voltage_10:
name: "${name} cell voltage 10"
cell_voltage_11:
name: "${name} cell voltage 11"
cell_voltage_12:
name: "${name} cell voltage 12"
operation_status_bitmask:
name: "${name} operation status bitmask"
errors_bitmask:
name: "${name} errors bitmask"
balancer_status_bitmask:
name: "${name} balancer status bitmask"
software_version:
name: "${name} software version"
text_sensor:
- platform: jbd_bms_ble
jbd_bms_ble_id: bms0
errors:
name: "${name} errors"
operation_status:
name: "${name} operation status"
device_model:
name: "${name} device model"
switch:
- platform: ble_client
ble_client_id: client0
name: "${name} enable bluetooth connection"
- platform: jbd_bms_ble
jbd_bms_ble_id: bms0
charging:
name: "${name} charging"
id: charge
discharging:
name: "${name} discharging"
Could be interesting for @rusins or @luastoned
Is there a way to save all the data and put it into a spread sheet? I’ve been thinking of doing this and probably will, but it would be sweet to save everything. I know it’s not needed but I have a data addiction and like to keep as much as I can.
Yes, you can export the data from home assistant, or even use the Grafana addon.
Home assistant already makes a graph from every data point though.
Using this system now to closely monitor my drowned battery… yesterday I crashed while riding a wet road and my board ended up in a creek.
Drying it out now while closely monitoring with hassio
After crash pic, while I was dying from pain. Just used my last adrenaline to fish up my board from the creek and open the battery box for draining
I was just about to do this exact same thing with esphome, so thanks for saving me the work! I have it running on a dev board. It sits out in my garage and when I bring a board within range, I get the nice BMS stats, and I use it to either trigger charge stops at voltage storage level, or charge up to like 80% the night before I do a ride, then have HA kick the charger back on in time for the ride.
Do you have any recommendations for a “production” esp32-based board or fully built-out hardware module? I’m looking for something off-the-shelf. Otherwise I’ll do my usual style (translation: ugly board enclosure and complete DIY aesthetic).
So two things:
-
The Waveshare esp32-s3-relay-6ch is definitely a nice unit. I picked up two (one for prod, one for testing) and they are pretty solid. I haven’t tested the relays yet, but I have a couple other projects that I could definitely use this with. I mean this is literally begging to be used as a garage light switch/garage door opener/bms monitor all in one
-
The esp32 implementation running on this thing seems to be pretty solid (hint for anyone stumbling across this, board model esp32-s3-devkitc-1 with framework arduino seems to work fine). The issue I’m running into seems to be that that the ESP can’t connect to any of my boards with manufacturer ID DGJBD. It connects fine to the one with manufacturer ID SZLLT. Those all seem to be JBD BMSs. I did make sure nothing was trying to connect to the DGJBD units at the same time and that they’re visible both in general BLE scans and connectable via Overkill Solar. None of them are set to require PINs.
The error is just a straightforward unable to connect message:
[23:36:19][C][esp32_ble:391]: ESP32 BLE:
[23:36:19][C][esp32_ble:393]: MAC address: 30:30:F9:79:DD:9D
[23:36:19][C][esp32_ble:394]: IO Capability: none
[23:36:19][C][esp32_ble_tracker:653]: BLE Tracker:
[23:36:19][C][esp32_ble_tracker:654]: Scan Duration: 300 s
[23:36:19][C][esp32_ble_tracker:655]: Scan Interval: 320.0 ms
[23:36:19][C][esp32_ble_tracker:656]: Scan Window: 30.0 ms
[23:36:19][C][esp32_ble_tracker:657]: Scan Type: ACTIVE
[23:36:19][C][esp32_ble_tracker:658]: Continuous Scanning: True
[23:36:19][C][ble_client:027]: BLE Client:
[23:36:19][C][mdns:117]: Hostname: batmon_dev0
[23:36:19][C][esphome.ota:073]: Over-The-Air updates:
[23:36:19][C][esphome.ota:074]: Address: batmon_dev0.local:3232
[23:36:19][C][esphome.ota:075]: Version: 2
[23:36:19][C][safe_mode:018]: Safe Mode:
[23:36:19][C][safe_mode:020]: Boot considered successful after 60 seconds
[23:36:19][C][safe_mode:021]: Invoke after 10 boot attempts
[23:36:19][C][safe_mode:023]: Remain in safe mode for 300 seconds
[23:36:19][C][api:139]: API Server:
[23:36:19][C][api:140]: Address: batmon_dev0.local:6053
[23:36:19][C][api:144]: Using noise encryption: NO
[23:36:20][W][jbd_bms_ble:156]: [83:3D:05:37:C2:A5] Not connected
[23:36:39][W][jbd_bms_ble:156]: [19:73:06:37:C2:A5] Not connected
[23:36:47][W][jbd_bms_ble:156]: [F0:6F:13:37:C2:A5] Not connected
[23:36:50][W][jbd_bms_ble:156]: [83:3D:05:37:C2:A5] Not connected
[23:36:53][D][esp32_ble_tracker:270]: Starting scan...
[23:37:09][W][jbd_bms_ble:156]: [19:73:06:37:C2:A5] Not connected
[23:37:17][W][jbd_bms_ble:156]: [F0:6F:13:37:C2:A5] Not connected
[23:37:20][W][jbd_bms_ble:156]: [83:3D:05:37:C2:A5] Not connected
The other one connects without issue:
36:48][C][esp32_ble:391]: ESP32 BLE:
[23:36:48][C][esp32_ble:393]: MAC address: 24:58:7C:EC:62:59
[23:36:48][C][esp32_ble:394]: IO Capability: none
[23:36:48][C][esp32_ble_tracker:653]: BLE Tracker:
[23:36:48][C][esp32_ble_tracker:654]: Scan Duration: 300 s
[23:36:48][C][esp32_ble_tracker:655]: Scan Interval: 320.0 ms
[23:36:48][C][esp32_ble_tracker:656]: Scan Window: 30.0 ms
[23:36:48][C][esp32_ble_tracker:657]: Scan Type: ACTIVE
[23:36:48][C][esp32_ble_tracker:658]: Continuous Scanning: True
[23:37:11][D][esp32_ble_client:110]: [0] [70:3E:97:FF:17:E6] ESP_GATTC_WRITE_CHAR_EVT
[23:37:12][D][esp32_ble_client:110]: [0] [70:3E:97:FF:17:E6] ESP_GATTC_NOTIFY_EVT
[23:37:12][D][esp32_ble_client:110]: [0] [70:3E:97:FF:17:E6] ESP_GATTC_NOTIFY_EVT
[23:37:12][I][jbd_bms_ble:242]: Hardware info frame (25 bytes) received
(etc etc)
Any suggestions?
Hi @lidocaineusi I just put this together like a script kiddie. Can’t really give you support on why it doesnt work with the other type BMS.
I suggest you open a ticket at the GitHub repo.
Happy I was able to help !
Sat down this weekend to debug, and it turns out the bluetooth MAC addresses I was using were backwards. That’s what I get for relying on Overkill Solar to pull the addresses, which on the JBD BMSs, it actually reverses. I have NO idea why. Guess this is what I get for not checking on it myself. Discovered that when I was doing a proper BT scan outside Overkill Solar. First shot shows Overkill. Second shot shows the scan.
After that, added all the boards with compatible Smart BMSs to HA and got the Grafana graphs going:
Will need to clean that up and probably coalesce a bunch of those into single graphs with selectable variables per board.
On the to do list:
-
ble_client in esphome is limited to three clients total. Not sure if that’s a software or hardware limitation (probably hardware) but I need to verify. Three per ESP chip is ok but not great. Also curious if this limitation exists on the non-esp32 mqtt version running on something like a Raspberry Pi.
-
The charging and balancing sensors need some debugging; they’re either not updating datapoints very often or they’re doing it incorrectly, or I’m running into an ESP bluetooth query timeout. Either way, they’re acting wonky and not showing state correctly.
But all in all, this is damn cool and WAY nicer than having to babysit a phone BMS app.
Hey where’d you get the Davega numbers? I’d also like the rough SOC percentages for an 18s pack. Reason being I was asked to implement a “reach X percentage charge at Y time” automation for both 12s and 18s packs. Right now I have that about halfway there, in that I can set a board to charge to storage voltage levels OR full, with an optional delay start at a specified date/time:
With those Davega numbers I can do the calc for a 12s, but no idea what the 18s voltage/percentage mappings are.
I also have mobile notifications going for charge starts, charge stops (storage or full), and temperature alerts:
I got the voltage levels from a thread on the forum by @ janpom . But they’re expressed as a percentage of cell voltage, so it should work for both 12s and 18s as long as you have a cell voltage value
Ah that makes sense. Brain was not working.
hy sir, I need help can u pleas guide me regarding this project i want to interface JK-BMS with ESP-32
Sure but this thread is already a guide.
Did anyone perhaps made a yaml for multiple bmss connected to 1 esp?