mkaiser / Sungrow-SHx-Inverter-Modbus-Home-Assistant

Sungrow SH Integration for Home Assistant for SH3K6, SH4K6, SH5K-20, SH5K-V13, SH3K6-30, SH4K6-30, SH5K-30, SH3.RS, SH3.6RS, SH4.0RS, SH5.0RS, SH6.0RS, SH5.0RT, SH6.0RT, SH8.0RT, SH10RT, SH5.0RT-20, SH6.0RT-20, SH8.0RT-20, SH10RT-20, SH5.0RT-V112, SH6.0RT-V112, SH8.0RT-V112, SH10RT-V112, SH5.0RT-V122, SH6.0RT-V122, SH8.0RT-V122, SH10RT-V122, SH4.6R
363 stars 94 forks source link

battery SoC versus real SoC #73

Closed dylan09 closed 1 year ago

dylan09 commented 1 year ago

Hi, another thing I have observed when playing with backup:

The inverter always supplies the SoC based on the value set in sg_min_soc and sg_max_soc. Min SoC = 35%; Max SoC = 100%; Then the SoC supplied by the inverter covers the remaining 65% with battery SoC 0% - 100% (sg_battery_level).

So, if the reported SoC is 50% in this example, the real SoC is 67,5% (0,35 + 0,5 * 0,65 => 0,675).

If you play a little bit with the min and max, the 60 day and the 180 day diagram are a little bit of meaningless. Important to me is: How often I could charge the battery to 100% and how much real energy (SoC) is left. So I would like to create a template sensor calculating the real SoC?

Did such a template sensor makes any sense? Or am I on the wrong way?

mkaiser commented 1 year ago

good points there!

I guess a template sensor (ore more) would be suitable here:

just thinking loud here, for (re)naming:

based on a this, we could make a new sensor "battery_charge" = battery_capacity * SoC

dylan09 commented 1 year ago

I think both sensors should be available. Because most users will be confused why there are two sensors. For most users (without backup circuit connected) the normal setting would be min SoC 5%, max SoC 100%. And in this case the SoC reported from inverter tells the real truth. How much charge is left before I have to take energy from the grid.

The template sensor is only of meaning if backup circuit is connected and someone is playing with min SoC and max SoC.

Here a short description about how backup could be configured so it is working automatic versus manually: The normal way as documented in the Sungrow documentation is to use min SoC and max SoC the same way as above and to use reserved for backup SoC to have enough energy left in case of grid blackout. But this has the drawback, that the inverter will never fall asleep. Means: he is always drawing around 80W from battery or grid. The whole night.

One solution to spare some energy in the night, would be to increase min SoC to something like 25 or more %. And to set reserved SoC to 0%. Then the inverter should go to sleep, when the reported SoC is 0%. Meaning no standby power for the inverters, when battery is empty. Drawback with this approach is, no automatic failover in case of grid blackout. You have to login to the inverter with the app locally and change the values for min SoC and reserved SoC. After a short while the inverter should start off-grid mode and backup is online.

I am testing a little bit with this settings. And thought about how would this impact the longterm statistics graph.

Your idea with a charge sensor is really good? Makes thinking for as human a little bit easier. "Hey there are 4.5 kWh charge left in battery. We need around 400W. So battery will last for around 10 hours..." But this leads to the need for 2 such sensors: 1 for the reported battery level and one for the calculated "real" value 🤯😀

andi-blafasl commented 1 year ago

I don't think there should be a "real SoC" shown as the default SoC Parameter! And changing the SoC to SoC_raw feels like a bad Idea for me, too. The main SoC displayed should always be the usable SoC that's determined by the Batterie Manufacturer.

If you really need the "total SoC" for anything, make a separate sensor for that and name it "Batterie total SoC".

Remember: If you deep discharge LiPo Cells, they get damaged beyond repair!

For Example: If you go below the 5% SoC (that's min SoC of my BYD), you could kill your Batterie! As long as you have Grid available, the Inverter is keeping the Battery at min SoC even if it has to use Grid to charge them. If you discharge your Batterie to 0% "real SoC" in a Backup situation without Grid, the self discharge and standby usage of the BMS and Inverter could kill the Batterie beyond repair. Another Problem with deep discharging a LiPo Block with multiple cells could be the drift between them. The Cells never discharge/charge equally. If you go to 0% SoC there could be a single cell that drops below it's deep discharge voltage. This could also happen with self discharge of the lowest cell without any usage of your Batterie.

Why not just set the "reserved SoC for backup" parameter to a higher level if you want to preserve some Energie in your batterie? I think that's what this parameter is designed for?

PS: Here is an example of the "emergency charge" of the battery to keep it dropping below min SoC image I tried to set min SoC to 10%, to reduce this. But the inverter then is keeping the battery at 10% with this short charges from Grid.

elektrinis commented 1 year ago

Commenting as a battery and BMS engineer. SOC is SOC. There is no such thing as "minimal SOC" and there is certainly no level at which there will be damage. min/max SOC values are tied to the cell voltage. For example 0% SOC for Li-ion is usually 3.0Vper cell. You can easily go to 0% SOC and it only means there is no significant usable energy left, but if cell voltage stays above 3.0V, there will be no damage. Even at 2.5V there will be no real damage. Also internal BMS will not allow it to discharge below 3.0V, it will simply disconnect the battery. Yes, battery is aging quicker if kept at 100% or close to 0% all the time, but it's not damage, but normal wear instead.

For me it was very unusual and frustrating to see SOC jumping around when changing "reserve" and "min/max SOC" values. This is nonsense. If I have a reserve of 20%, I want to see it. Same goes for max SOC. If I set it to 90%, I want to see charging stopping at 90%, and not at 100.

Bigger issue is that, as it is now, even if there is no reserve set and min/max is set at 0 and 100%, there seems to be 20% of energy missing, at least in my Sungrow SBR battery. It says it's 22.4kW, but I can only get 18-19kWh on a full cycle.

andi-blafasl commented 1 year ago

Ok, so calling SoC "State of Charge" is wrong. Sungrow is using it as a SoruCiP "State of remaining usable Capacity in Percent" 😉 I still think the default SoC shown should reflect the remaining usable Capacity, like in the iSolarCloud. Everything else would lead to confusion.

Bigger issue is that, as it is now, even if there is no reserve set and min/max is set at 0 and 100%, there seems to be 20% of energy missing, at least in my Sungrow SBR battery. It says it's 22.4kW, but I can only get 18-19kWh on a full cycle.

Could this be efficiency related? 80% is a bit low, but plausible? And how about the charging-/discharging-rate? On Lead Acid Batterie the stated capacity is at a C20 rating, not sure at which rating you get the stated capacity from your LiPo Pack ¯\(ツ)/¯

PS: I have a Camper Van with Solar and good old AGMs (planning a LiFePo upgrade) and a Battery Computer (shunt). That's my source of Knowledge 😉🤣

elektrinis commented 1 year ago

Well, we should probably have two separate SOCs. The real one is the physical capability of battery itself. If we set a reserve at 20%, our SOC should move in range of 20-100%. Because, if we set min SOC at 25% and max SOC at 75%, the displayed SOC will still move between 0-100% and this will represent only half of capacity.

I understand that sometimes we might need (can't think of a use case now) a representation that moves in range of 0-100% regardless of what limits are set, but that can be an extra helper, but not the main thing.

As for efficiency... Lead-acid is a notorious waster of energy. Lithium, however, is 99.9 efficient regardless or charge/discharge rate (in Ah, not Wh). We can lose 3-5% of energy due to voltage drop, but certainly not 20%.

dylan09 commented 1 year ago

I have defined a new template sensor which will calculate the nominal SoC based on the configured Min SoC and Max SoC and the SoC reported from the inverter:

    - name: sg_battery_level_nom
      unique_id: sg_battery_level_nom
      unit_of_measurement: "%"
      device_class: battery
      state_class: measurement
      availability: >-
        {{
            states('sensor.sg_battery_level') | is_number and
            states('sensor.sg_min_soc') | is_number and
            states('sensor.sg_max_soc') | is_number
        }}
      state: >-
        {% set soc_min = states('sensor.sg_min_soc') | float %}
        {% set soc_max = states('sensor.sg_max_soc') | float %}
        {% set soc_cur = states('sensor.sg_battery_level') | float %}
        {{ (soc_min) + (soc_max - soc_min) * (soc_cur / 100) }}

But didn't find the time to adopt it to the package configuration from the GitHub. Maybe someone could check if my calculation is valid. And create a pull request to get the changes to the repository.

dylan09 commented 1 year ago

Based on the sensor sg_battery_level and sg_battery_level_nom i have added two template sensors to calculate the remaining charge.

    - name: sg_battery_charge_soc
      unique_id: sg_battery_charge_soc
      unit_of_measurement: kWh
      device_class: energy
      availability: >-
        {{
            states('sensor.sg_battery_capacity') | is_number and
            states('sensor.sg_battery_level') | is_number and
            states('sensor.sg_min_soc') | is_number and
            states('sensor.sg_max_soc') | is_number
        }}
      state: >-
        {{  
            states('sensor.sg_battery_capacity') | float *
              ((states('sensor.sg_max_soc') | float - states('sensor.sg_min_soc') | float) * 
               states('sensor.sg_battery_level') | float / 10000) 
        }}

    - name: sg_battery_charge_nom
      unique_id: sg_battery_charge_nom
      unit_of_measurement: kWh
      device_class: energy
      availability: >-
        {{
            states('sensor.sg_battery_capacity') | is_number and
            states('sensor.sg_battery_level_nom') | is_number
        }}
      state: >-
        {{ 
          states('sensor.sg_battery_capacity') | float * 
          states('sensor.sg_battery_level_nom') | float / 100 
        }}

The first one calculates the remaining charge based on Min SoC and Max SoC configured in the inverter. This is the available energy left in the battery and is usable with the current SoC settings. The second one gives the remaining charge if Min SoC is set to 0% and Max SoC is set to 100%. Hope my calculations are correct.

dylan09 commented 1 year ago

Since I don't want to have my backup in hot standby permanently, I change the values for Min SoC, Max SoC and Reserved SoC as I need it.

If I want automatic switching to off-grid mode in case of grid blackout, I set Min SoC=5%, Max SoC=100% and Reserved SoC 25%-50%. This is my preferred setting if I am away from home for longer times.

If I want manual switching on grid blackout, I change the values to Min SoC 25%-50%, Max SoC=100% and Reserved SoC=0%. This is my preferred setting if I am at home.

To make the minimum and maximum charge of the battery comparable in the long-term diagram, the SoC value supplied by the inverter is then no longer usable. Comparable values are then only provided by the nominal SoC calculated by the template sensor.

Translated with www.DeepL.com/Translator (free version)

Louisbertelsmann commented 1 year ago

Added the sensors in my new pull request.