Skip to content

Commit

Permalink
Re-work execute code to account for calling service last
Browse files Browse the repository at this point in the history
  • Loading branch information
springfall2008 authored Dec 31, 2024
1 parent ffc4803 commit e0b8ce0
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 22 deletions.
66 changes: 48 additions & 18 deletions apps/predbat/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,14 +160,13 @@ def execute_plan(self):
status = "Freeze charging"
status_extra = " target {}%".format(inverter.soc_percent)
self.log("Inverter {} Freeze charging with soc {}%".format(inverter.id, inverter.soc_percent))
inverter.adjust_charge_immediate(inverter.soc_percent, freeze=True)
else:
# We can only hold charge if a) we have a way to hold the charge level on the reserve or with a pause feature
# and the current charge level is above the target for all inverters
target_soc = calc_percent_limit(max(self.charge_limit_best[0] if self.charge_limit_best[0] != self.reserve else self.soc_kw, self.reserve), self.soc_max)
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, inverter.soc_percent, target_soc, self.charge_limit_percent_best[0], self.set_discharge_during_charge))
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
Expand All @@ -192,11 +191,9 @@ def execute_plan(self):
else:
inverter.adjust_charge_window(charge_start_time, charge_end_time, self.minutes_now)

inverter.adjust_charge_immediate(target_soc, freeze=True)
else:
status = "Charging"
inverter.adjust_charge_window(charge_start_time, charge_end_time, self.minutes_now)
inverter.adjust_charge_immediate(target_soc)

status_extra = " target {}%-{}%".format(inverter.soc_percent, target_soc)

Expand Down Expand Up @@ -307,7 +304,6 @@ def execute_plan(self):
status = "Exporting"
status_extra = " target {}%-{}%".format(inverter.soc_percent, self.export_limits_best[0])
# Immediate export mode
inverter.adjust_export_immediate(self.export_limits_best[0])
else:
inverter.adjust_force_export(False)
disabled_export = True
Expand All @@ -327,12 +323,10 @@ def execute_plan(self):
status_extra = " current SoC {}%".format(inverter.soc_percent) # Discharge limit (99) is meaningless when Freeze Exporting so don't display it
isExporting = True
self.isExporting_Target = self.export_limits_best[0]
inverter.adjust_export_immediate(inverter.soc_percent, freeze=True)
else:
status = "Hold exporting"
status_extra = " target {}%-{}%".format(inverter.soc_percent, self.export_limits_best[0])
self.log("Export Hold (Demand mode) as export is now at/below target or freeze only is set - current SoC {} and target {}".format(self.soc_kw, discharge_soc))
inverter.adjust_export_immediate(0)
else:
if (self.minutes_now < minutes_end) and ((minutes_start - self.minutes_now) <= self.set_window_minutes) and (self.export_limits_best[0] < 100):
inverter.adjust_force_export(False, discharge_start_time, discharge_end_time)
Expand Down Expand Up @@ -388,12 +382,6 @@ def execute_plan(self):
else:
status = "Hold for iBoost"

# Charging/Discharging off via service
if not isCharging and self.set_charge_window:
inverter.adjust_charge_immediate(0)
if not isExporting and self.set_export_window:
inverter.adjust_export_immediate(0)

# Reset charge/discharge rate
if resetPause:
inverter.adjust_pause_mode()
Expand All @@ -402,12 +390,36 @@ def execute_plan(self):
if resetCharge:
inverter.adjust_charge_rate(inverter.battery_rate_max_charge * MINUTE_WATT)


if self.charge_limit_best:
clm = self.charge_limit_best[0]
else:
clm = 0

# Set the SoC just before or within the charge window
if self.set_soc_enable:
if (isExporting and not disabled_export) and not self.set_reserve_enable:
# If we are discharging and not setting reserve then we should reset the target SoC to the discharge target
# as some inverters can use this as a target for discharge
self.adjust_battery_target_multi(inverter, self.export_limits_best[0], isCharging, isExporting)
if isExporting:
if not disabled_export and not self.set_reserve_enable:
# If we are discharging and not setting reserve then we should reset the target SoC to the discharge target
# as some inverters can use this as a target for discharge
self.adjust_battery_target_multi(inverter, self.export_limits_best[0], isCharging, isExporting)
elif not inverter.inv_has_discharge_enable_time:
self.adjust_battery_target_multi(inverter, 0, isCharging, isExporting)
elif not self.inverter_hybrid and self.inverter_soc_reset and inverter.inv_has_target_soc:
# AC Coupled, charge to 100 on solar
self.log("Resetting charging SoC to 100 as we are not charging and inverter_soc_reset is enabled")
self.adjust_battery_target_multi(inverter, 100.0, isCharging, isExporting)
else:
# Reset to 0
self.adjust_battery_target_multi(inverter, 0, isCharging, isExporting)

# Immediate controls
if self.set_export_freeze and self.export_limits_best[0] == 99:
inverter.adjust_export_immediate(inverter.soc_percent, freeze=True)
elif not disabled_export:
inverter.adjust_export_immediate(self.export_limits_best[0])
else:
inverter.adjust_export_immediate(0)

elif self.charge_limit_best and (self.minutes_now < inverter.charge_end_time_minutes) and ((inverter.charge_start_time_minutes - self.minutes_now) <= self.set_soc_minutes) and not (disabled_charge_window):
if inverter.inv_has_charge_enable_time or isCharging:
Expand All @@ -416,6 +428,7 @@ def execute_plan(self):
if isCharging:
self.log("Within charge freeze setting target soc to current soc {}".format(inverter.soc_percent))
self.adjust_battery_target_multi(inverter, inverter.soc_percent, isCharging, isExporting, isFreezeCharge=True)
inverter.adjust_charge_immediate(inverter.soc_percent, freeze=True)
elif not inverter.inv_has_target_soc:
self.adjust_battery_target_multi(inverter, 0, isCharging, isExporting)
else:
Expand All @@ -431,6 +444,10 @@ def execute_plan(self):
target_soc = calc_percent_limit(max(self.charge_limit_best[0] if self.charge_limit_best[0] != self.reserve else self.soc_kw, self.reserve), self.soc_max)
self.log("Setting charging SOC to {} as per target".format(target_soc))
self.adjust_battery_target_multi(inverter, target_soc, isCharging, isExporting)
if (self.charge_limit_best[0] == self.reserve):
inverter.adjust_charge_immediate(calc_percent_limit(max(inverter.soc_kw, inverter.reserve), inverter.soc_max), freeze=True)
else:
inverter.adjust_charge_immediate(target_soc, freeze=True)
elif not inverter.inv_has_target_soc:
self.log("Setting charging SOC to 0 as we are not charging and inverter doesn't support target soc")
self.adjust_battery_target_multi(inverter, 0, isCharging, isExporting)
Expand All @@ -445,7 +462,7 @@ def execute_plan(self):
self.log("Setting charging SOC to 0 as we are not charging or exporting and inverter doesn't support target soc")
self.adjust_battery_target_multi(inverter, 0, isCharging, isExporting)
elif not self.inverter_hybrid and self.inverter_soc_reset and inverter.inv_has_target_soc:
# AC Coupled, charge to 0 on solar
# AC Coupled, charge to 100 on solar
self.log("Resetting charging SoC to 100 as we are not charging and inverter_soc_reset is enabled")
self.adjust_battery_target_multi(inverter, 100.0, isCharging, isExporting)
else:
Expand All @@ -471,6 +488,19 @@ def execute_plan(self):
)
if not inverter.inv_has_charge_enable_time:
self.adjust_battery_target_multi(inverter, 0, isCharging, isExporting)

# Charge immediate
if isCharging:
if (self.charge_limit_best[0] == self.reserve):
inverter.adjust_charge_immediate(inverter.soc_percent, freeze=True)
else:
inverter.adjust_charge_immediate(calc_percent_limit(max(self.charge_limit_best[0], self.reserve), self.soc_max), freeze=True)

# Charging/Discharging off via service
if not isCharging and self.set_charge_window:
inverter.adjust_charge_immediate(0)
if not isExporting and self.set_export_window:
inverter.adjust_export_immediate(0)

# Reset reserve as discharge is enable but not running right now
if self.set_reserve_enable and resetReserve:
Expand Down
13 changes: 9 additions & 4 deletions apps/predbat/unit_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1669,6 +1669,7 @@ def __init__(self, id, soc_kw, soc_max, now_utc):
self.inv_has_target_soc = True
self.inv_has_charge_enable_time = True
self.inv_has_timed_pause = True
self.inv_has_discharge_enable_time = True
self.soc_kw = soc_kw
self.soc_max = soc_max
self.soc_percent = calc_percent_limit(soc_kw, soc_max)
Expand Down Expand Up @@ -1807,6 +1808,7 @@ def run_execute_test(
in_calibration=False,
set_discharge_during_charge=True,
assert_immediate_soc_target=None,
assert_immediate_soc_target_array=None,
set_reserve_enable=True,
has_timed_pause=True,
has_target_soc=True,
Expand Down Expand Up @@ -1946,13 +1948,16 @@ def run_execute_test(
print("ERROR: Inverter {} SOC target should be {} got {}".format(inverter.id, assert_soc_target, inverter.soc_target))
failed = True

if assert_immediate_soc_target_array:
assert_immediate_soc_target = assert_immediate_soc_target_array[inverter.id]

assert_soc_target_force = assert_immediate_soc_target if assert_status in ["Charging", "Hold charging", "Freeze charging", "Hold charging, Hold for iBoost", "Freeze charging, Hold for iBoost"] else 0
if not set_charge_window:
assert_soc_target_force = -1
if inverter.immediate_charge_soc_target != assert_soc_target_force:
print("ERROR: Inverter {} Immediate charge SOC target should be {} got {}".format(inverter.id, assert_soc_target_force, inverter.immediate_charge_soc_target))
failed = True
if assert_status in ["Hold charging"] and inverter.immediate_charge_soc_freeze != True:
if assert_status in ["Freeze charging"] and inverter.immediate_charge_soc_freeze != True:
print("ERROR: Inverter {} Immediate charge SOC freeze should be True got {}".format(inverter.id, inverter.immediate_charge_soc_freeze))
failed = True
assert_soc_target_force_dis = assert_immediate_soc_target if assert_status in ["Exporting", "Freeze exporting"] else 0
Expand Down Expand Up @@ -3062,7 +3067,7 @@ def run_execute_tests(my_predbat):
assert_status="Hold charging",
assert_reserve=0,
assert_soc_target_array=[10, 40],
assert_immediate_soc_target=20,
assert_immediate_soc_target_array=[10, 40],
assert_charge_start_time_minutes=-1,
assert_charge_end_time_minutes=my_predbat.minutes_now + 60,
soc_kw_array=[0, 2],
Expand All @@ -3083,7 +3088,7 @@ def run_execute_tests(my_predbat):
assert_status="Hold charging",
assert_reserve=0,
assert_soc_target_array=[40, 10],
assert_immediate_soc_target=20,
assert_immediate_soc_target_array=[40, 10],
assert_charge_start_time_minutes=-1,
assert_charge_end_time_minutes=my_predbat.minutes_now + 60,
soc_kw_array=[2, 0],
Expand Down Expand Up @@ -3126,7 +3131,7 @@ def run_execute_tests(my_predbat):
assert_status="Hold charging",
assert_reserve=0,
assert_soc_target_array=[10, 15],
assert_immediate_soc_target=10,
assert_immediate_soc_target_array=[10, 15],
assert_charge_start_time_minutes=-1,
assert_charge_end_time_minutes=my_predbat.minutes_now + 60,
soc_kw_array=[0.25, 0.75],
Expand Down

0 comments on commit e0b8ce0

Please sign in to comment.