Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions apps/predbat/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -790,25 +790,32 @@ def execute_plan(self):
# Don't disable discharge during force charge/discharge slots but otherwise turn it off to prevent
# from draining the battery
if not isExporting:
if inverter.inv_has_timed_pause:
if resetPause:
inverter.adjust_pause_mode(pause_discharge=True)
pause_discharge_requested = True
resetPause = False
# Not while this inverter is actually charging, unless it can pause: the battery is being
# filled from the grid, so it cannot be feeding the car. A discharge rate of 0 adds nothing
# then, and some GivEnergy inverters will not grid-charge at all with it at 0 and the SoC on
# the reserve (#5419); pinning reserve just above a rising SoC costs a write for every 1% of
# the climb (#3899). Both are left to reset below for the duration, and applied once charging
# stops - which is the point the inverter returns to demand and the hold starts to mean
# something. A timed pause is one latched write that blocks only discharge, so it stays on
# through the charge, covering the moments the inverter reaches its target before Predbat
# sees it. The sibling iBoost hold below already sits out a charge for the same reason.
hold_deferred = (not inverter.inv_has_timed_pause) and status_per_inverter.get(inverter.id) == "Charging"
if hold_deferred:
self.log("Inverter {} is charging, so the hold for car {} leaves the discharge rate and reserve alone until charging stops".format(inverter.id, car_n))
else:
if discharge_rate is None:
discharge_rate = 0
# Not while actually charging: the battery is being filled from the grid, so it
# cannot be feeding the car, and pinning reserve just above a rising SoC costs a
# write for every 1% of the climb (#3899). Left to reset below for the duration,
# and latched at the SoC reached once charging stops - which is the point the
# inverter returns to demand and the hold starts to mean something. The sibling
# iBoost hold below already sits out a charge for the same reason.
if self.set_reserve_enable and status != "Charging":
inverter.adjust_reserve(min(inverter.soc_percent + 1, 100))
resetReserve = False
if inverter.inv_has_timed_pause:
if resetPause:
inverter.adjust_pause_mode(pause_discharge=True)
pause_discharge_requested = True
resetPause = False
else:
if discharge_rate is None:
discharge_rate = 0
if self.set_reserve_enable:
inverter.adjust_reserve(min(inverter.soc_percent + 1, 100))
resetReserve = False
self.log("Disabling battery discharge whilst car {} is charging".format(car_n))
carHolding = True
self.log("Disabling battery discharge whilst car {} is charging".format(car_n))
if ("Hold for car" not in status) and (status_hold_car == ""):
if status == "Demand":
status = "Hold for car"
Expand Down
25 changes: 24 additions & 1 deletion apps/predbat/tests/test_execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -3707,9 +3707,32 @@ def run_execute_tests(my_predbat):
assert_immediate_soc_target=100,
has_timed_pause=False,
assert_pause_discharge=False,
assert_discharge_rate=0,
assert_reserve=0,
)
# #5419: nor may it pin the discharge rate to 0 while charging - a charging battery cannot feed the car, and
# some GivEnergy inverters will not grid-charge at all with the rate at 0 and the SoC on the reserve. The
# scenario above asserts the rate staying at its maximum. Once the battery stops charging and holds instead,
# it can feed the car again, so the rate hold must still apply there:
failed |= run_execute_test(
my_predbat,
"car_charge2_no_pause",
charge_window_best=charge_window_best,
charge_limit_best=charge_limit_best2,
soc_kw=10,
car_slot=charge_window_best_slot,
assert_charge_time_enable=False,
set_charge_window=True,
set_export_window=True,
assert_status="Hold charging, Hold for car",
assert_charge_start_time_minutes=-1,
assert_charge_end_time_minutes=-1,
assert_immediate_soc_target=50,
assert_soc_target=100,
assert_reserve=100,
has_timed_pause=False,
assert_pause_discharge=False,
assert_discharge_rate=0,
)
failed |= run_execute_test(
my_predbat,
"car_charge2",
Expand Down
1 change: 1 addition & 0 deletions docs/car-charging.md
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,7 @@ Note: [Multiple cars](car-charging.md#multiple-electric-cars) can be planned wit
- **switch.predbat_car_charging_from_battery** - When set to On the car can drain the home battery, Predbat will manage the correct level of battery accordingly.
When set to Off home battery discharge will be prevented when your car charges, and all load from the car and home will be from the grid.
This is achieved by setting the battery discharge rate to 0 during car charging and to the maximum otherwise.
On inverters without a timed pause, the car hold does not set the discharge rate to 0 while the home battery is itself charging in a charge window, as a charging battery cannot feed the car.
The home battery can still charge from the grid/solar in either case. Only use this if Predbat knows your car charging plan,
e.g. you are using Intelligent Octopus or you use the car slots in Predbat to control your car charging.

Expand Down
Loading