From 32ecbebc562a2339f4e6ac0a546e6aca004de062 Mon Sep 17 00:00:00 2001 From: Trefor Southwell <48591903+springfall2008@users.noreply.github.com> Date: Wed, 27 Dec 2023 10:12:07 +0000 Subject: [PATCH 1/6] Tweaks to optimisation to try to prevent locked in discharge --- apps/predbat/predbat.py | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/apps/predbat/predbat.py b/apps/predbat/predbat.py index 9aefe7294..c349c9715 100644 --- a/apps/predbat/predbat.py +++ b/apps/predbat/predbat.py @@ -18,7 +18,7 @@ import os import yaml -THIS_VERSION = "v7.14.26" +THIS_VERSION = "v7.14.27" TIME_FORMAT = "%Y-%m-%dT%H:%M:%S%z" TIME_FORMAT_SECONDS = "%Y-%m-%dT%H:%M:%S.%f%z" TIME_FORMAT_OCTOPUS = "%Y-%m-%d %H:%M:%S%z" @@ -4721,7 +4721,7 @@ def rate_replicate(self, rates, rate_io={}, is_import=True, is_gas=False): and (minute_mod in self.future_energy_rates_export) ): prev_rate = rate_offset - rate_offset = rate_offset - self.future_energy_rates_export[minute_mod] + self.future_energy_rates_export[minute] + rate_offset = max(rate_offset - self.future_energy_rates_export[minute_mod] + self.future_energy_rates_export[minute], 0) elif is_import: rate_offset = rate_offset + self.metric_future_rate_offset_import elif (not is_import) and (not is_gas): @@ -7709,10 +7709,6 @@ def optimise_all_windows(self, load_minutes_step, load_minutes_step10, pv_foreca best_price, best_price_discharge, lowest_price_charge, self.charge_limit_best ) ) - charge_windows = [] - discharge_windows = [] - charge_socs = [] - discharge_socs = [] for start_at_low in [False, True]: if start_at_low: price_set.reverse() @@ -7729,12 +7725,14 @@ def optimise_all_windows(self, load_minutes_step, load_minutes_step10, pv_foreca # Store price set with window self.charge_window_best[window_n]["set"] = price - # Skip those outside threshold + # For start at high only tune down excess high slots if (not start_at_low) and (price > best_price) and (self.charge_limit_best[window_n] != self.soc_max): if self.debug_enable: self.log("Skip start at high window {} best limit {}".format(window_n, (self.charge_limit_best[window_n]))) continue - if start_at_low and price <= best_price: + + # Start at low is to add extra charge slots above threshold only + if start_at_low and (price <= best_price or (self.charge_limit_best[window_n] == 0)): continue if self.calculate_best_charge: @@ -7757,8 +7755,6 @@ def optimise_all_windows(self, load_minutes_step, load_minutes_step10, pv_foreca end_record=self.end_record, ) self.charge_limit_best[window_n] = best_soc - charge_windows.append(self.charge_window_best[window_n]) - charge_socs.append(self.calc_percent_limit(best_soc)) if 0: # Find all adjacent windows in price range @@ -7818,7 +7814,8 @@ def optimise_all_windows(self, load_minutes_step, load_minutes_step10, pv_foreca self.discharge_window_best[window_n]["set"] = price # Do highest price first - if start_at_low: + # Second pass to tune down any excess exports only + if start_at_low and ((price > best_price) or (self.discharge_limits_best[window_n] == 100.0)): continue if self.calculate_best_discharge: @@ -7858,8 +7855,7 @@ def optimise_all_windows(self, load_minutes_step, load_minutes_step10, pv_foreca ) self.discharge_limits_best[window_n] = best_soc self.discharge_window_best[window_n]["start"] = best_start - discharge_windows.append(self.discharge_window_best[window_n]) - discharge_socs.append(best_soc) + if self.debug_enable: self.log( "Best discharge limit window {} time {} - {} cost {} discharge_limit {} (adjusted) min {} @ {} (margin added {} and min {}) with metric {} cost {}".format( @@ -7877,17 +7873,18 @@ def optimise_all_windows(self, load_minutes_step, load_minutes_step10, pv_foreca ) ) - # Log new set of charge and discharge windows - if charge_windows: + # Log set of charge and discharge windows + if self.calculate_best_charge: self.log( "Best charge windows in price group {} best_metric {} best_cost {} metric_keep {} windows {}".format( - price, self.dp2(best_metric), self.dp2(best_cost), self.dp2(best_keep), self.window_as_text(charge_windows, charge_socs, ignore_min=True) + price, self.dp2(best_metric), self.dp2(best_cost), self.dp2(best_keep), self.window_as_text(self.charge_window_best, self.charge_limit_best, ignore_min=True) ) ) - if discharge_windows: + + if self.calculate_best_discharge: self.log( "Best discharge windows in price group {} best_metric {} best_cost {} metric_keep {} windows {}".format( - price, self.dp2(best_metric), self.dp2(best_cost), self.dp2(best_keep), self.window_as_text(discharge_windows[::-1], discharge_socs[::-1], ignore_max=True) + price, self.dp2(best_metric), self.dp2(best_cost), self.dp2(best_keep), self.window_as_text(self.discharge_window_best, self.discharge_limits_best, ignore_max=True) ) ) From a154a58636411dcde7a25f773ce6e96613696752 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Wed, 27 Dec 2023 10:13:59 +0000 Subject: [PATCH 2/6] [pre-commit.ci lite] apply automatic fixes --- apps/predbat/predbat.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/predbat/predbat.py b/apps/predbat/predbat.py index c349c9715..a723113fc 100644 --- a/apps/predbat/predbat.py +++ b/apps/predbat/predbat.py @@ -7725,7 +7725,7 @@ def optimise_all_windows(self, load_minutes_step, load_minutes_step10, pv_foreca # Store price set with window self.charge_window_best[window_n]["set"] = price - # For start at high only tune down excess high slots + # For start at high only tune down excess high slots if (not start_at_low) and (price > best_price) and (self.charge_limit_best[window_n] != self.soc_max): if self.debug_enable: self.log("Skip start at high window {} best limit {}".format(window_n, (self.charge_limit_best[window_n]))) @@ -7877,14 +7877,22 @@ def optimise_all_windows(self, load_minutes_step, load_minutes_step10, pv_foreca if self.calculate_best_charge: self.log( "Best charge windows in price group {} best_metric {} best_cost {} metric_keep {} windows {}".format( - price, self.dp2(best_metric), self.dp2(best_cost), self.dp2(best_keep), self.window_as_text(self.charge_window_best, self.charge_limit_best, ignore_min=True) + price, + self.dp2(best_metric), + self.dp2(best_cost), + self.dp2(best_keep), + self.window_as_text(self.charge_window_best, self.charge_limit_best, ignore_min=True), ) ) if self.calculate_best_discharge: self.log( "Best discharge windows in price group {} best_metric {} best_cost {} metric_keep {} windows {}".format( - price, self.dp2(best_metric), self.dp2(best_cost), self.dp2(best_keep), self.window_as_text(self.discharge_window_best, self.discharge_limits_best, ignore_max=True) + price, + self.dp2(best_metric), + self.dp2(best_cost), + self.dp2(best_keep), + self.window_as_text(self.discharge_window_best, self.discharge_limits_best, ignore_max=True), ) ) From c83046015975477199b9e613d694d9ee79f283d6 Mon Sep 17 00:00:00 2001 From: Trefor Southwell <48591903+springfall2008@users.noreply.github.com> Date: Wed, 27 Dec 2023 10:20:55 +0000 Subject: [PATCH 3/6] Tweaks --- apps/predbat/predbat.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/apps/predbat/predbat.py b/apps/predbat/predbat.py index a723113fc..326e622ca 100644 --- a/apps/predbat/predbat.py +++ b/apps/predbat/predbat.py @@ -7725,14 +7725,14 @@ def optimise_all_windows(self, load_minutes_step, load_minutes_step10, pv_foreca # Store price set with window self.charge_window_best[window_n]["set"] = price - # For start at high only tune down excess high slots + # For start at high only tune down excess high slots if (not start_at_low) and (price > best_price) and (self.charge_limit_best[window_n] != self.soc_max): if self.debug_enable: self.log("Skip start at high window {} best limit {}".format(window_n, (self.charge_limit_best[window_n]))) continue - # Start at low is to add extra charge slots above threshold only - if start_at_low and (price <= best_price or (self.charge_limit_best[window_n] == 0)): + # Start at low is to add extra charge slots above threshold or tune down below threshold slots + if start_at_low and (price <= best_price and (self.charge_limit_best[window_n] == 0)): continue if self.calculate_best_charge: @@ -7877,22 +7877,14 @@ def optimise_all_windows(self, load_minutes_step, load_minutes_step10, pv_foreca if self.calculate_best_charge: self.log( "Best charge windows in price group {} best_metric {} best_cost {} metric_keep {} windows {}".format( - price, - self.dp2(best_metric), - self.dp2(best_cost), - self.dp2(best_keep), - self.window_as_text(self.charge_window_best, self.charge_limit_best, ignore_min=True), + price, self.dp2(best_metric), self.dp2(best_cost), self.dp2(best_keep), self.window_as_text(self.charge_window_best, self.charge_limit_best, ignore_min=True) ) ) if self.calculate_best_discharge: self.log( "Best discharge windows in price group {} best_metric {} best_cost {} metric_keep {} windows {}".format( - price, - self.dp2(best_metric), - self.dp2(best_cost), - self.dp2(best_keep), - self.window_as_text(self.discharge_window_best, self.discharge_limits_best, ignore_max=True), + price, self.dp2(best_metric), self.dp2(best_cost), self.dp2(best_keep), self.window_as_text(self.discharge_window_best, self.discharge_limits_best, ignore_max=True) ) ) From 750f709c1919f0c1c6f28b4453c36d863817716e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Wed, 27 Dec 2023 10:21:50 +0000 Subject: [PATCH 4/6] [pre-commit.ci lite] apply automatic fixes --- apps/predbat/predbat.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/predbat/predbat.py b/apps/predbat/predbat.py index 326e622ca..72da57fa7 100644 --- a/apps/predbat/predbat.py +++ b/apps/predbat/predbat.py @@ -7725,7 +7725,7 @@ def optimise_all_windows(self, load_minutes_step, load_minutes_step10, pv_foreca # Store price set with window self.charge_window_best[window_n]["set"] = price - # For start at high only tune down excess high slots + # For start at high only tune down excess high slots if (not start_at_low) and (price > best_price) and (self.charge_limit_best[window_n] != self.soc_max): if self.debug_enable: self.log("Skip start at high window {} best limit {}".format(window_n, (self.charge_limit_best[window_n]))) @@ -7877,14 +7877,22 @@ def optimise_all_windows(self, load_minutes_step, load_minutes_step10, pv_foreca if self.calculate_best_charge: self.log( "Best charge windows in price group {} best_metric {} best_cost {} metric_keep {} windows {}".format( - price, self.dp2(best_metric), self.dp2(best_cost), self.dp2(best_keep), self.window_as_text(self.charge_window_best, self.charge_limit_best, ignore_min=True) + price, + self.dp2(best_metric), + self.dp2(best_cost), + self.dp2(best_keep), + self.window_as_text(self.charge_window_best, self.charge_limit_best, ignore_min=True), ) ) if self.calculate_best_discharge: self.log( "Best discharge windows in price group {} best_metric {} best_cost {} metric_keep {} windows {}".format( - price, self.dp2(best_metric), self.dp2(best_cost), self.dp2(best_keep), self.window_as_text(self.discharge_window_best, self.discharge_limits_best, ignore_max=True) + price, + self.dp2(best_metric), + self.dp2(best_cost), + self.dp2(best_keep), + self.window_as_text(self.discharge_window_best, self.discharge_limits_best, ignore_max=True), ) ) From 73862528d2d8e2c4cdb3251cafd040410b70a620 Mon Sep 17 00:00:00 2001 From: Trefor Southwell <48591903+springfall2008@users.noreply.github.com> Date: Wed, 27 Dec 2023 10:32:48 +0000 Subject: [PATCH 5/6] Tweaks --- apps/predbat/predbat.py | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/apps/predbat/predbat.py b/apps/predbat/predbat.py index 72da57fa7..d37b2ec05 100644 --- a/apps/predbat/predbat.py +++ b/apps/predbat/predbat.py @@ -7725,16 +7725,12 @@ def optimise_all_windows(self, load_minutes_step, load_minutes_step10, pv_foreca # Store price set with window self.charge_window_best[window_n]["set"] = price - # For start at high only tune down excess high slots + # For start at high only tune down excess high slots if (not start_at_low) and (price > best_price) and (self.charge_limit_best[window_n] != self.soc_max): if self.debug_enable: self.log("Skip start at high window {} best limit {}".format(window_n, (self.charge_limit_best[window_n]))) continue - # Start at low is to add extra charge slots above threshold or tune down below threshold slots - if start_at_low and (price <= best_price and (self.charge_limit_best[window_n] == 0)): - continue - if self.calculate_best_charge: if not printed_set: self.log("Optimise price set {} start_at_low {} best_price {}".format(price, start_at_low, best_price)) @@ -7877,22 +7873,14 @@ def optimise_all_windows(self, load_minutes_step, load_minutes_step10, pv_foreca if self.calculate_best_charge: self.log( "Best charge windows in price group {} best_metric {} best_cost {} metric_keep {} windows {}".format( - price, - self.dp2(best_metric), - self.dp2(best_cost), - self.dp2(best_keep), - self.window_as_text(self.charge_window_best, self.charge_limit_best, ignore_min=True), + price, self.dp2(best_metric), self.dp2(best_cost), self.dp2(best_keep), self.window_as_text(self.charge_window_best, self.charge_limit_best, ignore_min=True) ) ) if self.calculate_best_discharge: self.log( "Best discharge windows in price group {} best_metric {} best_cost {} metric_keep {} windows {}".format( - price, - self.dp2(best_metric), - self.dp2(best_cost), - self.dp2(best_keep), - self.window_as_text(self.discharge_window_best, self.discharge_limits_best, ignore_max=True), + price, self.dp2(best_metric), self.dp2(best_cost), self.dp2(best_keep), self.window_as_text(self.discharge_window_best, self.discharge_limits_best, ignore_max=True) ) ) From 992d1acd63a9fae4cb432803b728a0e3e6299717 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Wed, 27 Dec 2023 10:33:42 +0000 Subject: [PATCH 6/6] [pre-commit.ci lite] apply automatic fixes --- apps/predbat/predbat.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/predbat/predbat.py b/apps/predbat/predbat.py index d37b2ec05..df5bfcc39 100644 --- a/apps/predbat/predbat.py +++ b/apps/predbat/predbat.py @@ -7725,7 +7725,7 @@ def optimise_all_windows(self, load_minutes_step, load_minutes_step10, pv_foreca # Store price set with window self.charge_window_best[window_n]["set"] = price - # For start at high only tune down excess high slots + # For start at high only tune down excess high slots if (not start_at_low) and (price > best_price) and (self.charge_limit_best[window_n] != self.soc_max): if self.debug_enable: self.log("Skip start at high window {} best limit {}".format(window_n, (self.charge_limit_best[window_n]))) @@ -7873,14 +7873,22 @@ def optimise_all_windows(self, load_minutes_step, load_minutes_step10, pv_foreca if self.calculate_best_charge: self.log( "Best charge windows in price group {} best_metric {} best_cost {} metric_keep {} windows {}".format( - price, self.dp2(best_metric), self.dp2(best_cost), self.dp2(best_keep), self.window_as_text(self.charge_window_best, self.charge_limit_best, ignore_min=True) + price, + self.dp2(best_metric), + self.dp2(best_cost), + self.dp2(best_keep), + self.window_as_text(self.charge_window_best, self.charge_limit_best, ignore_min=True), ) ) if self.calculate_best_discharge: self.log( "Best discharge windows in price group {} best_metric {} best_cost {} metric_keep {} windows {}".format( - price, self.dp2(best_metric), self.dp2(best_cost), self.dp2(best_keep), self.window_as_text(self.discharge_window_best, self.discharge_limits_best, ignore_max=True) + price, + self.dp2(best_metric), + self.dp2(best_cost), + self.dp2(best_keep), + self.window_as_text(self.discharge_window_best, self.discharge_limits_best, ignore_max=True), ) )