diy solar

diy solar

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

Not on the model we were testing.
It didn’t exist.
No mention of it in the user manual.
No option on the front panel or via software.

On my Voltronic Axpert Max 7.2 (we already tested your RS485 version) manual for remote panel says:
SumatraPDF_2023-09-19_18-40-03.png

and this is from software protocol:
SumatraPDF_2023-09-19_18-43-33.png
And I confirm, I was able to set "Max Discharge Current" via remote panel or EspHome while battery mode set in "PYLON" testing you RS485 version.
 
But in original question (https://diysolarforum.com/threads/j...dwe-and-pylontech-batteries.48963/post-863878) OP is talking of Voltronic Max 7200, as mine.

See https://github.com/Uksa007/esphome-jk-bms-can/discussions/27#discussioncomment-6274479, this is me when we tested Max 7.2.

If you are talking about another inverter, then sorry. Could you remember which one?
Ciao Pongo, scusami..Anche io ho un Max 7200 (di SP24)...spiegami un attimo per favore, ma questo accessorio creato da uksa007 funziona? Il JK comunica con il Voltronic come qualsiasi altro BMS tipo Seplos e compare la percentuale? Io ho un JK con uscita RS485 per adesso collegato ad un Raspbarry e con Solar Assistant.
 
@uksa007

absorption_v: "55.2"
rebulk_offset: "3.0"

I did the tests below with a battery at +/- 53.1V
I set the offset to 3V to match the condition of the box marked "A".

Under these conditions when booting the ESP32 the charging status should be on Bulk but we remain stuck on Wait.

Why ?

First, during boot, JK-BMS information is not immediately available.

Even if the BMS allows charging, the condition !id(charging_switch).state) is true and the code framed with the number 1 is executed.
The 'charge_status' variable is changed to 'Disabled'.

Then the code framed with the number 2 is executed and 'charge_status' is changed to 'Wait'.

Then we will remain stuck in this 'Wait' state until the battery voltage is below 55.2 - 2.5 (offset) = 52.7V (3.29V / cell which can last a long time).

A battery charging with 30A or more can be well above 52.7V with an SoC less than 50%.

V1.13.3 original script

1695273346706.png

1695273274803.png



Modified script

To correct this problem I tried not to modify the original script too much.

1) I changed the initial value of 'charge_status' to 'Init' for the procedure added in point 2.
2) I added the code framed in pink (1), it just allows you to wait a little in order to receive the information coming from the JK-BMS sensors which are not available directly just after boot.
3) Modified the value of the variable in box (2)

In the original script, in HA if we force the charge with the 'Charging manually (top bal)' switch then deactivate it we stay on 'Wait', for me it's OK if the goal is to wait and not to resume normal operation immediately.

But then it was impossible to return to normal 'bulk' mode.

To correct this problem I modified the 'Wait' value in box (2) to 'Startup' which allows normal charging to be activated via an OFF/ON of the 'Charging enabled' switch.



1695280307225.png

1695287642535.png




Below you can see two videos of the behavior before and after.

A reset of the ESP32 is done before the start of each video.

1) First video with the original code, we get stuck on Wait


2) Second video with the modified code, it works ;-)


That said, I think this part of the code could probably be improved further.

Here is the new code.

C++:
            uint8_t can_mesg[7];
            if (id(charge_status) == "Init") {
                id(charge_status) = "Startup";
                ESP_LOGI("main", "Wait for JK-BMS data...");
            } else if ((!id(charging_switch).state) | (!id(inverter_charging).state)) {
               id(charge_status) = "Disabled";
            } else if (id(inverter_chg_on).state) {
                id(charge_status) = "Bulk Manually";
            } else if ((id(charging_switch).state) & (id(inverter_charging).state) & (id(charge_status) == "Disabled")) {
               id(charge_status) = "Startup";
            } else if ((!id(inverter_chg_on).state) & (id(charge_status) == "Bulk Manually")) {
               id(charge_status) = "Wait";
            } else if (id(total_voltage).state <= (id(charging_voltage).state - ${rebulk_offset})) { // Bulk Charge eg 53.6v 10%
                if (id(absorption_script).is_running()) id(absorption_script).stop();
                id(charge_status) = "Bulk";
            } else if ((id(total_voltage).state > (id(charging_voltage).state - ${rebulk_offset})) & (id(total_voltage).state < (id(charging_voltage).state - 0.05))) { // If in startup rebulk
                     if (id(charge_status) == "Startup") {
                        id(charge_status) = "Bulk"; // If in startup, 10% low rebulk
                     }
            } else if (id(total_voltage).state >= (id(charging_voltage).state  - 0.05)) { // 10 % from top start absorption timer
                     if (id(charge_status) == "Bulk") {
                        id(charge_status) = "Absorption";
                        if (!id(absorption_script).is_running()) id(absorption_script).execute();
                     }
            } else {
                id(charge_status) = "Wait";
            }
 
Last edited:
I did the tests below with a battery at +/- 53.1V
I set the offset to 3V to match the condition of the box marked "A".

Under these conditions when booting the ESP32 the charging status should be on Bulk but we remain stuck on Wait.

Why ?

Normal operation is for it not to charge till Voltage is below: absorption_v - rebulk_offset:
You don't want a rebooting esp32 to be constantly charging the battery.
Think of an edge case where the ESP is rebooting every 30 seconds, it will be constantly microcycling the battery.
My Interface boards do not reboot, I have them up for years, so under normal operation it charges up the battery and then waits for the Voltage to drop as per below:

55.2 - 3 = 52.2 this is where it will request bulk.
53.1 is above 52.2 so it will wait till the voltage is below 52.2v as per normal operation.

Your issues seem to be your rebooting ESP32 fix them and it works as intended.

Edit you are using very old code, Interface boards are shipping with V1.22 FW.

Regards.
 
Last edited:
Normal operation is for it not to charge till Voltage is below: absorption_v - rebulk_offset:
You don't want a rebooting esp32 to be constantly charging the battery.
Think of an edge case where the ESP is rebooting every 30 seconds, it will be constantly microcycling the battery.
My Interface boards do not reboot, I have them up for years, so under normal operation it charges up the battery and then waits for the Voltage to drop as per below:

55.2 - 3 = 52.2 this is where it will request bulk.
53.1 is above 52.2 so it will wait till the voltage is below 52.2v as per normal operation.

Your issues seem to be your rebooting ESP32 fix them and it works as intended.

Edit you are using very old code, Interface boards are shipping with V1.22 FW.

Regards.

I don't have any stability or reboot problems with my ESP32, it was a suggestion that I mentioned following the strange behavior that I noticed but I monitor the uptime now and it is stable, no problem of this side. It's only 5:44:50 because I made the videos this morning with reboot test to show them to you here. Tomorrow it will be 24 hours more!

I can understand that there is a risk of microcycling in this case, okay.

On the other hand, there is also a problem with leaving a battery in 'Wait' because its voltage is between (absorption_v) and (absorption_v - rebulk_offset) but its SoC is below 50% which is entirely possible. Simply connect the ESP32 just when the battery is charging with 30A or more.

It is possible to improve the code to take both scenarios into account.

Can you tell me why you programmed a 'Startup' procedure?

This procedure does not work for the reasons I cited in the previous post. Do the test yourself to see.

1695293886408.png

1695293933169.png


1695293047336.png
 
absorption_v: "55.2"
rebulk_offset: "2.5

55.2 - 2.5 = 52.7V

Normal operation is for it not to charge till Voltage is below: absorption_v - rebulk_offset:

So according to you this battery (at rest) which is at 71% and 53.32V is no longer allowed to charge?

It's a 280Ah pack, there are 199A left, so I can still charge 80Ah.

1695294899047.png
 
Can you tell me why you programmed a 'Startup' procedure?
I think I programed it initially, and then made more changes to fix other status, and when I tested it worked as it should.
I think at some point I changed my mind and decided that startup charging was not I good idea.

In later code it is very different, and the whole code base does not run till after a startup delay to give the BMS code time to update. (BMS code runs separately).

The offset at 2.5v with no load in reality is about SOC 80-90%, after charging the cells they with drop a fair bit of voltage in a few hours.
With a small load of 20-40A it very quickly drops below the 2.5V offset.

You can set the offset to whatever works for you.
 
So according to you this battery (at rest) which is at 71% and 53.32V is no longer allowed to charge?
Yep that's correct, because in real use case(for most people) the battery voltage will drop the surface charge in a few hours.
It will also not be at 71% after discharging all night.
When the morning rolls around it will be/have been below the offset at some point, and will be in bulk mode.
Voltage sags quickly at the knee of the charging curve.

It's why its configurable, if you want the offset less set as it pleases you!!!

I would suggest you run it in real world use case before you start throwing stones, you will see it works very well.
 
Last edited:
In later code it is very different, and the whole code base does not run till after a startup delay to give the BMS code time to update. (BMS code runs separately).

Well, I see that you have noticed the same problem that I mentioned regarding the fact that it is necessary to wait a little to receive the information from JK-BMS.
 
Well, I see that you have noticed the same problem that I mentioned regarding the fact that it is necessary to wait a little to receive the information from JK-BMS.
It's not really a problem here, it becomes troublesome when I wrote the MuliBMS code, and adding a new pack would send alarms to the master.
 
It's a 280Ah pack, there are 199A left, so I can still charge 80Ah.
Here is how it works in the real world when you are actually using the battery as intended.
You will see the battery has gone back to bulk at 17:30 right as it starts to discharge.
I'm charging to 56V (testing if balancing better, spoiler it does) with a 2.5V rebulk_offset

1695298027043.png
 
Last edited:
Here is how it works in the real world when you are actually using the battery as intended.

This is what was happening in the real world at my house on 03.06.2023.

At 6:00 AM I am still at 87% SoC and 53V.

This is very different from what happens now or in winter.

Fortunately we can configure the 'rebulk_offset' value as desired and even improve the script.

Long live open source.

Thank you for your work ;)

1695303548850.png
 
This is what was happening in the real world at my house on 03.06.2023.
By my rough cals you have used 36AH in 11 Hours = 3.27A * 53v = 176.58 W average, which is basically just a fridge running.
Do you have the whole house connected or just a few circuits, or is no one living there?
In cases like these there is probably no need to charge every day, just charge every 2, or 3 days, your battery is big enough, charging every day is just cycling the battery for no real need.
Adjust the Rebulk_offset to cater for your anemic usage.
 
By my rough cals you have used 36AH in 11 Hours = 3.27A * 53v = 176.58 W average, which is basically just a fridge running.
Do you have the whole house connected or just a few circuits, or is no one living there?
In cases like these there is probably no need to charge every day, just charge every 2, or 3 days, your battery is big enough, charging every day is just cycling the battery for no real need.
Adjust the Rebulk_offset to cater for your anemic usage.

:ROFLMAO: maybe a weekend when we were away from home ;)
 
I simplified the code, it has exactly the same behavior as your version V1.13.3 except that I added a 'Rebulk Offset V.' slider which allows to exit the 'Wait' state if necessary without needing to activate 'Bulk Manually'.

This therefore prevents microcycling in the event that the ESP32 is unstable and will reboot.

Behavior video :



C++:
            // +---------------+
            // | Charge Status |
            // +---------------+
       
            // Disabled : charging disabled if BMS or HA switch is OFF
            if ((!id(charging_switch).state) | (!id(inverter_charging).state)) {
               id(charge_status) = "Disabled";
            }
            // Wait : all charging swith is ON and charge status is 'Disabled'
            else if ((id(charging_switch).state) & (id(inverter_charging).state) & (id(charge_status) == "Disabled")) {
               id(charge_status) = "Wait";
            }
            // Bulk Manually : forced battery charging via HA 'Charging manually (top bal)' switch
            else if (id(inverter_chg_on).state) {
                id(charge_status) = "Bulk Manually";
            }
            // Wait : after switch OFF 'Charging manually (top bal)' HA switch
            else if ((!id(inverter_chg_on).state) & (id(charge_status) == "Bulk Manually")) {
               id(charge_status) = "Wait";
            }
            // Bulk : if Batt. V. <= ( Absorption V. - Offset V. ) ? by default is 55.2-2.5 = 52.7 V
            else if (id(total_voltage).state <= (id(charging_voltage).state - id(rebulk_offset).state)) {
                if (id(absorption_script).is_running()) id(absorption_script).stop();
                id(charge_status) = "Bulk";
            }
            // Absorption : if Batt. V >= ( Absorption V. - 0.05 V ) ? by default is 55.2-0.05 = 55.15 V
            else if (id(total_voltage).state >= (id(charging_voltage).state  - 0.05)) {
                if (id(charge_status) == "Bulk") {
                    id(charge_status) = "Absorption";
                    // 10 % from top start absorption timer
                    if (!id(absorption_script).is_running()) id(absorption_script).execute();
                }
            }
 
Last edited:
allows to exit the 'Wait' state if necessary without needing to activate 'Bulk Manually'.
If you increase the absorption voltage slider(and then return it to normal) it will also trigger the battery into Bulk mode
eg if you move the absorption slider to 57.6 - 2.5v = 55.1V battery voltage below this would trigger Bulk.
 
I would suggest you run it in real world use case before you start throwing stones, you will see it works very well.

Hi @uksa007

My goal is not to throw stones, I just tested and analyzed your script in different situations and I am telling you what I discovered with the sole aim of improving it.

That said, this is probably useless because you have already done it in the new version 1.16 which I will happily test when it is available.

1695453477193.png

Your issues seem to be your rebooting ESP32 fix them and it works as intended.

Interestingly, you wrote in black and white that you solved a daily reboot bug in the case where there is no connection of the ESP32 with HA.

During our discussion regarding my problems where I mentioned a possible instability of my ESP32 you never asked me if the ESP32 was well connected with Home Assistant.

And indeed I did not have an HA server, I added an HA server afterwards to monitor the uptime of the ESP32 which has been stable since it was connected with HA.

I understand better where the initial instability problems came from.

My ESP32 has not restarted since I sent the last code Thursday evening around 19:00.

1695454991648.png

1695454498797.png

Once again, thank you for your work which is much appreciated.

I like to test things thoroughly and find the little beast.

I wish you a nice day ;)
 
Last edited:
JK is releasing a new BMS compatible with a large number of inverters.

It will soon be tested on Andy's channel.

More info in the links below.

 
Back
Top