batpred icon indicating copy to clipboard operation
batpred copied to clipboard

Hold charge does not adjust max charge rate

Open azebro opened this issue 9 months ago • 7 comments

When hold chanrge is execured, only discharge rate is adjusted as per the code below:

inverter.adjust_discharge_rate(0)

in execute.py:

if self.set_soc_enable and self.soc_percent >= target_soc:
                                status = "Hold charging"
                                self.log("Inverter {} Hold charging as soc {}% is above target {}% set_discharge_during_charge {}".format(inverter.id, self.soc_percent, target_soc, self.charge_limit_percent_best[0], self.set_discharge_during_charge))

                                if (target_soc < 100.0) and (abs(inverter.soc_percent - target_soc) <= 1.0):
                                    # If we are within 1% of the target but not at 100% then we can hold charge
                                    # otherwise keep charging enabled
                                    if self.set_soc_enable and ((self.set_reserve_enable and self.set_reserve_hold and inverter.reserve_max >= inverter.soc_percent) or inverter.inv_has_timed_pause):
                                        inverter.disable_charge_window()
                                        disabled_charge_window = True

                                        if self.set_reserve_enable and not inverter.inv_has_timed_pause:
                                            inverter.adjust_reserve(min(inverter.soc_percent + 1, 100))
                                            resetReserve = False
                                    else:
                                        inverter.adjust_charge_window(charge_start_time, charge_end_time, self.minutes_now)

                                    # Pause?
                                    if inverter.inv_has_timed_pause:
                                        inverter.adjust_pause_mode(pause_discharge=True)
                                        resetPause = False
                                    else:
                                        **inverter.adjust_discharge_rate(0)**
                                        
                                        resetDischarge = False

this caused the inverter to keep charging.

Suggest changing it to (or introducing config value to trigger):

inverter.adjust_discharge_rate(0)
inverter.adjust_charge_rate(0)

in execute.py:

          if self.set_soc_enable and self.soc_percent >= target_soc:
                                status = "Hold charging"
                                self.log("Inverter {} Hold charging as soc {}% is above target {}% set_discharge_during_charge {}".format(inverter.id, self.soc_percent, target_soc, self.charge_limit_percent_best[0], self.set_discharge_during_charge))

                                if (target_soc < 100.0) and (abs(inverter.soc_percent - target_soc) <= 1.0):
                                    # If we are within 1% of the target but not at 100% then we can hold charge
                                    # otherwise keep charging enabled
                                    if self.set_soc_enable and ((self.set_reserve_enable and self.set_reserve_hold and inverter.reserve_max >= inverter.soc_percent) or inverter.inv_has_timed_pause):
                                        inverter.disable_charge_window()
                                        disabled_charge_window = True

                                        if self.set_reserve_enable and not inverter.inv_has_timed_pause:
                                            inverter.adjust_reserve(min(inverter.soc_percent + 1, 100))
                                            resetReserve = False
                                    else:
                                        inverter.adjust_charge_window(charge_start_time, charge_end_time, self.minutes_now)

                                    # Pause?
                                    if inverter.inv_has_timed_pause:
                                        inverter.adjust_pause_mode(pause_discharge=True)
                                        resetPause = False
                                    else:
                                        **inverter.adjust_discharge_rate(0)
                                        inverter.adjust_charge_rate(0)**
                                        resetDischarge = False

to make sure the charge is stopped.

azebro avatar Mar 17 '25 08:03 azebro

I don't set the charge rate to 0 as it would cause solar to be exported rather than it being sent to the battery. Hold charge should disable the charge window instead.

What is the issue you have?

springfall2008 avatar Mar 18 '25 08:03 springfall2008

My issue is that when the battery charges from grid on the cheap tariff and then goes to hold charge. When hold action is invoked, it only changes discharge to 0 (fine), but the charging continues as max charge is not changed. So either hold charge should disable charge (not happening), or leave charge and set max charge to 0.

If I modify code adding inverter.adjust_charge_rate(0):

 if self.set_soc_enable and self.soc_percent >= target_soc:
                                status = "Hold charging"
                                self.log("Inverter {} Hold charging as soc {}% is above target {}% set_discharge_during_charge {}".format(inverter.id, self.soc_percent, target_soc, self.charge_limit_percent_best[0], self.set_discharge_during_charge))

                                if (target_soc < 100.0) and (abs(inverter.soc_percent - target_soc) <= 1.0):
                                    # If we are within 1% of the target but not at 100% then we can hold charge
                                    # otherwise keep charging enabled
                                    if self.set_soc_enable and ((self.set_reserve_enable and self.set_reserve_hold and inverter.reserve_max >= inverter.soc_percent) or inverter.inv_has_timed_pause):
                                        inverter.disable_charge_window()
                                        disabled_charge_window = True

                                        if self.set_reserve_enable and not inverter.inv_has_timed_pause:
                                            inverter.adjust_reserve(min(inverter.soc_percent + 1, 100))
                                            resetReserve = False
                                    else:
                                        inverter.adjust_charge_window(charge_start_time, charge_end_time, self.minutes_now)

                                    # Pause?
                                    if inverter.inv_has_timed_pause:
                                        inverter.adjust_pause_mode(pause_discharge=True)
                                        resetPause = False
                                    else:
                                        inverter.adjust_discharge_rate(0)
                                        inverter.adjust_charge_rate(0)
                                        resetDischarge = False

Then all works fine. PV production is not affected btw.


From: Trefor Southwell Sent: Tuesday, March 18, 2025 08:24 To: springfall2008/batpred Cc: Adam Zebrowski; Author Subject: Re: [springfall2008/batpred] Hold charge does not adjust max charge rate (Issue #2114)

[springfall2008]springfall2008 left a comment (springfall2008/batpred#2114)https://github.com/springfall2008/batpred/issues/2114#issuecomment-2732086842

I don't set the charge rate to 0 as it would cause solar to be exported rather than it being sent to the battery. Hold charge should disable the charge window instead.

What is the issue you have?

— Reply to this email directly, view it on GitHubhttps://github.com/springfall2008/batpred/issues/2114#issuecomment-2732086842, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AAIKHIH3HOQDVALEN25OZT32U7J3RAVCNFSM6AAAAABZE2BEF6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDOMZSGA4DMOBUGI. You are receiving this because you authored the thread.

azebro avatar Mar 18 '25 09:03 azebro

Is this issue related? https://github.com/springfall2008/batpred/issues/2035

I've added a debug log for the behaviour in my last comment on that issue. I appreciate you get a lot of issues reported so I'm really just trying to bump this back to the front page 😊

sammort avatar Mar 18 '25 12:03 sammort

@azebro What type of inverter do you have? From what you've said I suspect you may be facing a similar problem to Growatt inverters, where the inverter has no "target SOC", only a charge limit, and so you're looking at other ways in which "Hold charge" mode could/should stop the inverter from charging from the grid. As the other commenter mentioned, the difficulty is not accidentally preventing excess PV from charging the battery at the same time.

For Growatt inverters (connected via Solar Assistant), control is done via defined service calls, and I've fixed Hold charge for myself by adding a charge_freeze_service ("Freeze charge" seems to often be used in preference to "Hold charge", if it's available, although I'm not too sure on the difference) that sets the inverter's priority to "Battery first" and disables "Battery first grid charge". These options/settings are likely Growatt-specific, but your inverter may have something similar.

It's worth noting that to enable charge_freeze_service to actually be used I had to define my inverter manually in apps.yaml instead of using the built-in "SA" config, so that I could define support_charge_freeze: True.

tomkentpayne avatar Mar 21 '25 15:03 tomkentpayne

I have something similar, where both hold charge and freeze charge still charge the battery at full rate during the overnight cheap period. Discharge rate goes to zero for unclear reasons (it does not need to be zeroed during charging for my inverter), but charge rate is still maxed out at 7kW.

Almost certainly something off with inverter configuration in my apps.yaml, so I'm going to talk it through in a discussion thread first. My inverter does not have timed charging / pauses etc.

Thinking of using the inverter's max_soc hard limit for target_soc, but switch.predbat_inverter_soc_reset doesn't seem to set it back to 100% after charging is complete (it drops right down to the same as the reserve/min_soc for the rest of the day) despite switch.predbat_inverter_soc_reset being set on. The reason that is a problem is that number.max_soc will block all charging including from clipped PV. I'll give max_soc a go tonight, but because it doesn't reset to 100% I can't use it long term.

If that doesn't work, then I might investigate the 'backup' work-mode, not even sure if my inverter supports it (it's a fairly recent introduction and has appeared on some but not others), but in theory it should hold the charge at the number.min_soc_on_grid level.

The example here is with target_soc not configured, reserve configured with number.min_soc_on_grid.

Image

predbat_plan.html.txt

predbat (2).log

apps (2).yaml.txt

---- Edit:

It looks like this:

  inverter:
    has_target_soc: True
    has_reserve_soc: True
    ...

  charge_limit:
    - number.max_soc
  reserve:
    - number.min_soc_on_grid  

is working for hold charge overnight, although due to the fact it doesn't reset to 100% despite switch.predbat_inverter_soc_reset being set on, but instead matches the reserve_soc at 15% I don't think I can actually use number.max_soc (since that would prevent the battery from being charged at all from PV during the day). So tomorrow night I will experiment to see if backup mode works on this inverter.

---- Edit2:

This is what I am going to try tonight. I have experimented and Back-up mode does work on my firmware version. Fairly confident that this will solve it, and won't block PV charging like the target_soc = number.max_soc does.

  inverter:
    has_target_soc: False
    has_reserve_soc: True
    support_charge_freeze: true
    support_discharge_freeze: true
    ...

  charge_freeze_service:
    service: select.select_option
    entity_id: select.work_mode
    option: "Back-up"

  reserve:
    - number.min_soc_on_grid

---- Edit3:

This is the result of using the 'back-up' mode:

Image

Conclusion

  • Hold charge and Freeze charge both work when using charge_freeze_service to set 'Back-up' mode on the inverter (with a matching reserve_soc set to number.min_soc_on_grid). This is for Fox inverters which have the recent firmware which enables this work-mode. Therefore this is the solution I would recommend to anyone running a Fox inverter (and perhaps other inverter types which support a similar mode).
  • Hold charge and freeze charge work when configured via target_soc being set to number.max_soc, but this solution is unusable on the Fox inverters due to switch.predbat_inverter_soc_reset not resetting the max_soc to 100% for the rest of the day (instead it is set to the reserve_soc which means that it cannot be charged from clipped PV, or any other charging source)
  • Hold charge & freeze charge do not seem to work when the inverter does not have a timed pause mode and does not have charge periods, and isn't being controlled via target_soc or the charge_freeze_service, because it seems to be trying to control the pause by setting a zero discharge rate (this is the code fragment from the original post). Nor does it seem to be stopping charge mode, so the system just keeps charging at full speed.
  • For some reason the discharge rate is being set to zero during the hold charge & freeze charge periods, which has no purpose on the Fox inverters, at least, since the Fox inverters don't pause charging as a result of the discharge rate being set to zero (perhaps this would be effective if the inverter mode was changed to discharge instead of staying in charging mode).

apps.yaml_FOX.txt

WyndStryke avatar Mar 21 '25 22:03 WyndStryke

@azebro What type of inverter do you have? From what you've said I suspect you may be facing a similar problem to Growatt inverters, where the inverter has no "target SOC", only a charge limit, and so you're looking at other ways in which "Hold charge" mode could/should stop the inverter from charging from the grid. As the other commenter mentioned, the difficulty is not accidentally preventing excess PV from charging the battery at the same time.

For Growatt inverters (connected via Solar Assistant), control is done via defined service calls, and I've fixed Hold charge for myself by adding a charge_freeze_service ("Freeze charge" seems to often be used in preference to "Hold charge", if it's available, although I'm not too sure on the difference) that sets the inverter's priority to "Battery first" and disables "Battery first grid charge". These options/settings are likely Growatt-specific, but your inverter may have something similar.

It's worth noting that to enable charge_freeze_service to actually be used I had to define my inverter manually in apps.yaml instead of using the built-in "SA" config, so that I could define support_charge_freeze: True.

I have Sigenergy Sigenstore. I could introduce the freeze potentially, but it actually works well if I change the code as above.

azebro avatar Mar 24 '25 12:03 azebro

I have Sigenergy Sigenstore. I could introduce the freeze potentially, but it actually works well if I change the code as above.

According to the manual, the SigenStor has a 'backup reserve' mode. This sounds very similar to what I used to implement the charge_freeze_service on my Fox inverter.

Backup Reserve If there is a Gateway in the network, you can manually set the "Backup Reserve" value in mySigen App. When the grid is connected, the battery stops discharging when the set backup SOC is reached; when the grid is powered down, the battery power from the backup can be used. Example: Self-Consumption Mode involves backup SOC.

Can this be controlled via the integration (the predbat reserve_soc would be configured to use the backup_soc control, and the mode would be set by charge_freeze_service)?

WyndStryke avatar Mar 24 '25 12:03 WyndStryke

Covering in #2077

gcoan avatar Dec 09 '25 23:12 gcoan