From f4db08958f112c0bb937d9967d5ff731baf1582b Mon Sep 17 00:00:00 2001 From: Trefor Southwell <48591903+springfall2008@users.noreply.github.com> Date: Thu, 26 Dec 2024 18:37:35 +0000 Subject: [PATCH] Try to export everything left if allowed (#1790) * Try to export everything left if allowed https://github.com/springfall2008/batpred/issues/1704 * Tests * [pre-commit.ci lite] apply automatic fixes --------- Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> --- apps/predbat/execute.py | 2 +- apps/predbat/prediction.py | 7 ++----- apps/predbat/unit_test.py | 37 +++++++++++++++++++++++++++++++++---- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/apps/predbat/execute.py b/apps/predbat/execute.py index fe1bf0e35..633602876 100644 --- a/apps/predbat/execute.py +++ b/apps/predbat/execute.py @@ -280,7 +280,7 @@ def execute_plan(self): discharge_soc = max((self.export_limits_best[0] * self.soc_max) / 100.0, self.reserve, self.best_soc_min) self.log("Next export window will be: {} - {} at reserve {}".format(discharge_start_time, discharge_end_time, self.export_limits_best[0])) if (self.minutes_now >= minutes_start) and (self.minutes_now < minutes_end) and (self.export_limits_best[0] < 100.0): - if not self.set_export_freeze_only and self.export_limits_best[0] < 99.0 and ((self.soc_kw - PREDICT_STEP * inverter.battery_rate_max_discharge_scaled) >= discharge_soc): + if not self.set_export_freeze_only and self.export_limits_best[0] < 99.0 and (self.soc_kw > discharge_soc): self.log("Exporting now - current SoC {} and target {}".format(self.soc_kw, dp2(discharge_soc))) inverter.adjust_discharge_rate(inverter.battery_rate_max_discharge * MINUTE_WATT) resetDischarge = False diff --git a/apps/predbat/prediction.py b/apps/predbat/prediction.py index 2e2c998f9..8c2994bd3 100644 --- a/apps/predbat/prediction.py +++ b/apps/predbat/prediction.py @@ -409,10 +409,7 @@ def run_prediction(self, charge_limit, charge_window, export_window, export_limi # Once a force discharge is set the four hour rule is disabled if four_hour_rule: - if minute < 4 * 60: - keep_minute_scaling = 0 - else: - keep_minute_scaling = min(((minute - 4 * 60) / (2 * 60)), 1.0) * self.best_soc_keep_weight + keep_minute_scaling = min((minute / (4 * 60)), 1.0) * self.best_soc_keep_weight else: keep_minute_scaling = self.best_soc_keep_weight @@ -587,7 +584,7 @@ def run_prediction(self, charge_limit, charge_window, export_window, export_limi if export_window_n >= 0: discharge_min = max(self.soc_max * export_limits[export_window_n] / 100.0, self.reserve, self.best_soc_min) - if not self.set_export_freeze_only and (export_window_n >= 0) and export_limits[export_window_n] < 99.0 and (soc - step * self.battery_rate_max_discharge_scaled) >= discharge_min: + if not self.set_export_freeze_only and (export_window_n >= 0) and export_limits[export_window_n] < 99.0 and (soc > discharge_min): # Discharge enable discharge_rate_now = self.battery_rate_max_discharge # Assume discharge becomes enabled here discharge_rate_now_curve = get_discharge_rate_curve(soc, discharge_rate_now, self.soc_max, self.battery_rate_max_discharge, self.battery_discharge_power_curve, self.battery_rate_min) * self.battery_rate_max_scaling_discharge diff --git a/apps/predbat/unit_test.py b/apps/predbat/unit_test.py index 134f4134e..b7fec413f 100644 --- a/apps/predbat/unit_test.py +++ b/apps/predbat/unit_test.py @@ -1675,8 +1675,8 @@ def run_execute_test( def run_single_debug(test_name, my_predbat, debug_file, expected_file=None): print("**** Running debug test {} ****\n".format(debug_file)) - re_do_rates = True - reset_load_model = True + re_do_rates = False + reset_load_model = False load_override = 1.0 my_predbat.load_user_config() failed = False @@ -1692,7 +1692,8 @@ def run_single_debug(test_name, my_predbat, debug_file, expected_file=None): # Force off combine export XXX: print("Combined export slots {} min_improvement_export {} set_export_freeze_only {}".format(my_predbat.combine_export_slots, my_predbat.metric_min_improvement_export, my_predbat.set_export_freeze_only)) if not expected_file: - my_predbat.combine_export_slots = False + pass + # my_predbat.combine_export_slots = False # my_predbat.best_soc_keep = 1.0 # my_predbat.metric_min_improvement_export = 5 @@ -1720,6 +1721,7 @@ def run_single_debug(test_name, my_predbat, debug_file, expected_file=None): # Reset load model if reset_load_model: + print("Reset load model") my_predbat.load_minutes_step = my_predbat.step_data_history( my_predbat.load_minutes, my_predbat.minutes_now, @@ -1797,7 +1799,7 @@ def run_single_debug(test_name, my_predbat, debug_file, expected_file=None): print("ERROR: Actual plan does not match expected plan") failed = True # Write actual plan - filename = test_name + "_actual.json" + filename = test_name + ".actual.json" open(filename, "w").write(actual_json) print("Wrote plan json to {}".format(filename)) return failed @@ -4116,6 +4118,20 @@ def run_model_tests(my_predbat): keep=1, keep_weight=0.5, ) + failed |= simple_scenario( + "battery_discharge_keep2", + my_predbat, + 0, + 0, + assert_final_metric=-export_rate * 1, + assert_final_soc=0, + with_battery=True, + discharge=0, + battery_soc=1, + assert_keep=23 * import_rate * 0.5 + ((1 + (1 / 12)) * import_rate * 0.5 * 0.5), + keep=1, + keep_weight=0.5, + ) failed |= simple_scenario( "battery_discharge_loss", my_predbat, @@ -4166,6 +4182,19 @@ def run_model_tests(my_predbat): keep=1.0, keep_weight=1.0, ) + failed |= simple_scenario( + "battery_load_keep_four_hour", + my_predbat, + 1.0, + 0, + assert_final_metric=import_rate * 20, + assert_final_soc=0, + with_battery=True, + battery_soc=4, + assert_keep=20 * import_rate * 4 + 53, + keep=4.0, + keep_weight=1.0, + ) failed |= simple_scenario( "battery_discharge_load_keep_mode_test1", my_predbat,