diy solar

diy solar

JK BMS CAN bus comms now possible for inverters that support Goodwe and Pylontech batteries

Normally it's the ID 0x379 which is used by LuxPower to display the battery capacity.
This ID will be sent only if you choose can_protocol 2 or 4.

can_protocol 2 = can_protocol 1 + IDs 0x70, 0x371 and 0x379
Let me push an OTA quickly and update you

Edit: Works perfectly now.

IMG_20240128_203111329.jpg
Thanks 👍
 
Last edited:
Hi Guys,

Another step forward in this cool project, thanks to the support from @Sleeper85

Now, the simple and compact solution with M5stack Atom and CAN base works WIRELESSLY.

I have successfully compiled on the Atom S3 the Bluetooth version of the JK-CAN adapter via ESPhome, and it works fine with my Deye inverter.

In practice, I can remove the JST cable connector to the JK BMS serial (GPS) port.

This provides another degree of freedom in the hardware implementation, reducing cabling, connectors, adapters... The solution is truly plug and play and hassle-free.

As you can see by the picture you need to Power the ESP32 S3 via a USB C cable, connect the CAN cable (TX and RX), and it's done.

br
Davide

1706471345792.png
 
Hi Guys,

Another step forward in this cool project, thanks to the support from @Sleeper85

Now, the simple and compact solution with M5stack Atom and CAN base works WIRELESSLY.

I have successfully compiled on the Atom S3 the Bluetooth version of the JK-CAN adapter via ESPhome, and it works fine with my Deye inverter.

In practice, I can remove the JST cable connector to the JK BMS serial (GPS) port.

This provides another degree of freedom in the hardware implementation, reducing cabling, connectors, adapters... The solution is truly plug and play and hassle-free.

As you can see by the picture you need to Power the ESP32 S3 via a USB C cable, connect the CAN cable (TX and RX), and it's done.

br
Davide

View attachment 191896
@arzaman Wow, the soldering and the cable to the JK port was easy enough with my M5 kit. This is awesome. Where specifically in the code do you connect to the JK via bluetooth? Also do you leave esp-idf as the type vs aruindo?
 
@arzaman Wow, the soldering and the cable to the JK port was easy enough with my M5 kit. This is awesome. Where specifically in the code do you connect to the JK via bluetooth? Also do you leave esp-idf as the type vs aruindo?

I'm still busy with @arzaman to define the right board and framework values to use. Then I'll put it all in the README.
 
There is a major infuriating bug :

What I managed to understand is this;

If the battery is sufficiently discharged , and while charging (say, 25 Amps @ 54 V) a load comes on that drops the amperes and thus voltage down in the float range (53.6 V), and the ESP somehow reboots in between,
The charging logic gets stuck at float. Which means charging is now happening at (12 Amps @ 53.6 V) and solar is being wasted.
The way around for me was to force bulk or disable float, both flags don't survive ESP reboots.

@shvm @eumobong

I just modified the charging logic, taking inspiration from what @eumobong did.
This allows a Bulk charge after starting or rebooting the ESP32 and a Float charge only after the end of the Absorption phase.

I'll test it in depth tomorrow and if it's OK I'll release it with version 1.16.4.

C++:
                      // +--------------------------------------+
                      // | Charging Logic                       |
                      // +--------------------------------------+

                      // Warning : information from JK BMS is not available immediately after boot
                      
                      // Alarm : if JK-BMS alarm !
                      if (id(errors_bitmask).state > 1) {
                           id(charge_status) = "Alarm";
                      }
                      // No Alarm => Wait
                      else if ((id(errors_bitmask).state < 2) & (id(charge_status) == "Alarm")) {
                           id(charge_status) = "Wait";
                      }
                      // Charge ON : BMS and ESP32 charging switch is ON
                      else if ((id(charging_switch).state) & (id(switch_charging).state)) {

                        // Force Bulk : 'Charging manually (top bal)' switch is ON
                        if (id(switch_chg_bulk).state) {
                             id(charge_status) = "Force Bulk";
                        }
                        // No Force Bulk => Wait
                        else if ((!id(switch_chg_bulk).state) & (id(charge_status) == "Force Bulk")) {
                             id(charge_status) = "Wait";
                        }
                        // Bulk : Bat. V. <= Rebulk V. ( Absorption V. - Rebulk Offset V. )                             ( Rebulk V. = 55.2-2.5 = 52.7V by default )
                        else if (id(total_voltage).state <= (id(bulk_voltage).state - id(rebulk_offset).state)) {
                             id(charge_status) = "Bulk";
                             if (id(absorption_script).is_running()) id(absorption_script).stop();
                        }
                        // Absorption : Bat. V >= ( Absorption V. - Absorption Offset V. )                              ( Absorption V. = 55.2-0.05 = 55.15V by default )
                        else if ((id(charge_status) == "Bulk") & (id(total_voltage).state >= (id(bulk_voltage).state - id(absorption_offset).state))) {
                             id(charge_status) = "Absorption";
                             if (!id(absorption_script).is_running()) id(absorption_script).execute();                  // 10 % from top start absorption timer
                        }
                        // Bulk : Bat. V. > Rebulk V. + Wait or ESP32 startup
                        else if ((id(charge_status) == "Wait")) {
                             id(charge_status) = "Bulk";
                             if (id(absorption_script).is_running()) id(absorption_script).stop();
                        }
                        // Float : Bat. V. > Rebulk V. + Float switch ON and End Of Charge                              ( Float : after Absorption )
                        else if ((id(switch_chg_float).state) & (id(charge_status) == "EOC")) {
                             id(charge_status) = "Float";
                        }
                        // No Float => Wait
                        else if ((!id(switch_chg_float).state) & (id(charge_status) == "Float")) {
                             id(charge_status) = "Wait";
                        }

                      }
                      // Charge OFF
                      else id(charge_status) = "Wait";
 
@arzaman Wow, the soldering and the cable to the JK port was easy enough with my M5 kit. This is awesome. Where specifically in the code do you connect to the JK via bluetooth? Also do you leave esp-idf as the type vs aruindo?

All I can say today is that @arzaman tested it with the arduino framework only.

During my testing of the Bluetooth version with the ESP32 DevKit v1 board I noticed that the Bluetooth connection was unstable with the arduino framework and I corrected this problem using the esp-idf framework. Additionally, syssi which is the author of the JK Bluetooth code also uses esp-idf by default.

So I would like those with Atom Lite or S3 to test the Bluetooth version with the esp-idf framework.

YAML of BLE version
 
All I can say today is that @arzaman tested it with the arduino framework only.

During my testing of the Bluetooth version with the ESP32 DevKit v1 board I noticed that the Bluetooth connection was unstable with the arduino framework and I corrected this problem using the esp-idf framework. Additionally, syssi which is the author of the JK Bluetooth code also uses esp-idf by default.

So I would like those with Atom Lite or S3 to test the Bluetooth version with the esp-idf framework.

YAML of BLE version
Is there any specific config for connecting to the JK with Bluetooth? What if there are multiple JKs in the same area?
 
Is there any specific config for connecting to the JK with Bluetooth? What if there are multiple JKs in the same area?

You just need to choose the BLE protocol according to the version of your JK-BMS and specify its MAC address (use a smartphone application to find it).
The ESP32 only connects to the BMS that has this MAC address.

YAML:
# +--------------------------------------+
# | Bluetooth Settings                   |
# +--------------------------------------+
# Please use "JK02_24S" if you own a old JK-BMS < hardware version 11.0 (hardware version >= 6.0 and < 11.0)
# Please use "JK02_32S" if you own a new JK-BMS >= hardware version 11.0 (f.e. JK-B2A8S20P hw 11.XW, sw 11.26)
# Please use "JK04" if you have some old JK-BMS <= hardware version 3.0 (f.e. JK-B2A16S hw 3.0, sw. 3.3.0)
  protocol_version: JK02_32S
  mac_address: C8:47:8C:10:7E:AA
 
Impossible to find a Bluetooth MAC on an iPhone. Waiting for neighbor to come home, think he has a PC and/or android.

Android for the win: That being said, esphome run failed if I use type esp-idf using the BLE yaml. Only way this works is with type arduino on the M5Atom. Will see if logs present show any weirdness but all data is going to HA successfully.
 
Last edited:
Impossible to find a Bluetooth MAC on an iPhone. Waiting for neighbor to come home, think he has a PC and/or android.

Android for the win: That being said, esphome run failed if I use type esp-idf using the BLE yaml. Only way this works is with type arduino on the M5Atom. Will see if logs present show any weirdness but all data is going to HA successfully.
Just flash BLE scanner on your ESP using
https://github.com/syssi/esphome-jk-bms/blob/main/esp32-ble-scanner.yaml this should spit the Mac on the logs, note it. Afterward flash/OTA the main code
 
Impossible to find a Bluetooth MAC on an iPhone. Waiting for neighbor to come home, think he has a PC and/or android.

Android for the win: That being said, esphome run failed if I use type esp-idf using the BLE yaml. Only way this works is with type arduino on the M5Atom. Will see if logs present show any weirdness but all data is going to HA successfully.

What you need to watch out for is the ESP32 uptime which you can see in HA.

My test version has been up for several days with esp-idf. (ESP32 DevKit v1)

If I'm confirmed that it is stable for Atom with arduino, I will put it in the readme.

Thanks for your test 😉
 
All I can say today is that @arzaman tested it with the arduino framework only.

During my testing of the Bluetooth version with the ESP32 DevKit v1 board I noticed that the Bluetooth connection was unstable with the arduino framework and I corrected this problem using the esp-idf framework. Additionally, syssi which is the author of the JK Bluetooth code also uses esp-idf by default.

So I would like those with Atom Lite or S3 to test the Bluetooth version with the esp-idf framework.

YAML of BLE version

Exactly test in progress !!

up to now everthing quite stable with my Atom S3 Lite and Arduino framework

this is the board definition I used

esp32:
board: esp32-s3-devkitc-1
framework:
type: arduino
version: 2.0.14
platform_version: 6.5.0
variant: esp32s3

BT connection stable since last eveneing

1706514320885.png

Br
Davide
 
Very interesting!
Yet another alternative for a BMS that doesn't natively communicate with the inverter.
I'm available for some testing with the JK-BMS and Deye inverter. It's not clear to me which version of 'JK BMS (CAN)*' your application supports – the old one (JK02 protocol over the RS485/"GPS" port) or the new one (that indeed support inverter communications directly) ?

br
Davide
At the moment it supports the new one that implements a Pylon-clone CAN protocol.
I've just updated the application so its really easy to install, update, configure and maintain.

I'd really appreciate if you could test the JK BMS implementation as I only implemented it from the protocol specification but don't have the BMS myself. Please contact me for support on the https://github.com/ai-republic/bms-to-inverter discussion page or raise a ticket.
 
No, it integrates with the Victron ecosystem and can for example set the charge parameters on the MPPT.
I was just reviewing some of my questions and your answer got me thinking. The Victron smart solar MPPT parameters can be changed via the Victron connect app & Bluetooth. What extra parameters would I be able to set?
 
You can set the charge voltage and current limit (CVL/CCL/DCL) dynamically so if e.g. temperature gets too hot you can lower the charge current.

Regarding temperature and charging current, are there recommended charging values depending on temperature?

I know that at 0°C we no longer charge but what about high temperatures?
 
Regarding temperature and charging current, are there recommended charging values depending on temperature?

I know that at 0°C we no longer charge but what about high temperatures?

Anything over 30C is something to look out for. Anything over 40C will destroy your battery quickly. There is not hard cut-ff (same as for low temperatures by the way, it's not 0C exact - it's a gradient). 25C is the sweet spot, so if your temp is rising, lower the charge current to mitigate this.
 
Anything over 30C is something to look out for. Anything over 40C will destroy your battery quickly. There is not hard cut-ff (same as for low temperatures by the way, it's not 0C exact - it's a gradient). 25C is the sweet spot, so if your temp is rising, lower the charge current to mitigate this.

In your opinion, what would be the maximum number of amps recommended at 30°C and 40°C for 280Ah cells?

The limitation is both charging and discharging when it's hot, right?
 
In your opinion, what would be the maximum number of amps recommended at 30°C and 40°C for 280Ah cells?

The limitation is both charging and discharging when it's hot, right?
I don't think implementing this is necessary for low C-rates DIY solar applications, but here are C-rate recommendations from EVE and CALB.

charging rate temp.png
EVE charging
discharging rate temp eve.png
EVE discharging
charge rate temp calb.png

CALB charging
 
@eumobong

Why do you stop charging above 45°C ?

According to the table provided by @shvm , there seems to be no problem charging above 45°C.

C++:
if (max(id(temperature_sensor_1).state, id(temperature_sensor_2).state) > 45) { //if battery temp is higher than 45 deg C stop charging
  can_mesg[0] = uint16_t((id(charging_voltage).state - ${float_offset}) * 10) & 0xff;
  can_mesg[1] = uint16_t((id(charging_voltage).state - ${float_offset}) * 10) >> 8 & 0xff;
  can_mesg[2] = 0x00;
  can_mesg[3] = 0x00;
}
 

diy solar

diy solar
Back
Top