Skip to content

Commit 0713c71

Browse files
Minor fix to ensure 'base' is in the same record window, show record window on the prediction chart
1 parent 4d965b6 commit 0713c71

2 files changed

Lines changed: 26 additions & 9 deletions

File tree

example_chart.yml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,20 @@ series:
8686
b[0] })
8787
show:
8888
in_header: raw
89-
89+
- entity: predbat.record
90+
stroke_width: 2
91+
curve: stepline
92+
name: record
93+
type: column
94+
color: black
95+
data_generator: >
96+
let res = []; for (const [key, value] of
97+
Object.entries(entity.attributes.results)) { res.push([new
98+
Date(key).getTime(), value]); } return res.sort((a, b) => { return a[0] -
99+
b[0] })
100+
show:
101+
in_header: raw
102+
90103
# This is a cost chart
91104
type: custom:apexcharts-card
92105
header:

predbat.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ def scenario_summary(self, datap):
720720
txt += "%6s" % str(self.dp2(value))
721721
return txt
722722

723-
def run_prediction(self, charge_limit, charge_window, discharge_window, discharge_enable, load_minutes, pv_forecast_minute, save=None, step=5):
723+
def run_prediction(self, charge_limit, charge_window, discharge_window, discharge_enable, load_minutes, pv_forecast_minute, save=None, step=5, end_record=None):
724724
"""
725725
Run a prediction scenario given a charge limit, options to save the results or not to HA entity
726726
"""
@@ -748,13 +748,15 @@ def run_prediction(self, charge_limit, charge_window, discharge_window, discharg
748748
pv_kwh_time = {}
749749
export_kwh_time = {}
750750
import_kwh_time = {}
751+
record_time = {}
751752
car_soc = self.car_charging_soc
752753

753754
# self.log("Sim discharge window {} enable {}".format(discharge_window, discharge_enable))
754755

755756
# For the SOC calculation we need to stop 24 hours after the first charging window starts
756757
# to avoid wrapping into the next day
757-
end_record = self.record_length(charge_window)
758+
if not end_record:
759+
end_record = self.record_length(charge_window)
758760
record = True
759761

760762
# Simulate each forward minute
@@ -899,6 +901,7 @@ def run_prediction(self, charge_limit, charge_window, discharge_window, discharg
899901
import_kwh_time[stamp] = self.dp2(import_kwh)
900902
export_kwh_time[stamp] = self.dp2(export_kwh)
901903
predict_car_soc_time[stamp] = self.dp2(car_soc / self.car_charging_battery_size * 100.0)
904+
record_time[stamp] = 0 if record else self.soc_max
902905

903906
# Store the number of minutes until the battery runs out
904907
if record and soc <= self.reserve:
@@ -970,6 +973,7 @@ def run_prediction(self, charge_limit, charge_window, discharge_window, discharg
970973
self.set_state("predbat.best_import_energy_battery", state=self.dp3(import_kwh_battery), attributes = {'friendly_name' : 'Predicted import to battery best', 'state_class': 'measurement', 'unit_of_measurement': 'kwh', 'icon': 'mdi:transmission-tower-import'})
971974
self.set_state("predbat.best_import_energy_house", state=self.dp3(import_kwh_house), attributes = {'friendly_name' : 'Predicted import to house best', 'state_class': 'measurement', 'unit_of_measurement': 'kwh', 'icon': 'mdi:transmission-tower-import'})
972975
self.set_state("predbat.best_metric", state=self.dp2(metric), attributes = {'results' : metric_time, 'friendly_name' : 'Predicted best metric (cost)', 'state_class': 'measurement', 'unit_of_measurement': 'p', 'icon': 'mdi:currency-usd'})
976+
self.set_state("predbat.record", state=0.0, attributes = {'results' : record_time, 'friendly_name' : 'Prediction window', 'state_class' : 'measurement'})
973977

974978
if save and save=='best10' and not SIMULATE:
975979
self.set_state("predbat.soc_kw_best10", state=self.dp3(final_soc), attributes = {'results' : predict_soc_time, 'friendly_name' : 'Battery SOC kwh best 10%', 'state_class': 'measurement', 'unit_of_measurement': 'kwh', 'icon' : 'mdi:battery'})
@@ -1880,7 +1884,7 @@ def update_pred(self):
18801884
self.soc_kw += inverter.soc_kw
18811885
self.reserve += inverter.reserve
18821886
self.inverters.append(inverter)
1883-
self.log("Found {} inverters total reserve {} soc_max {} soc {} charge rate {} discharge rate".format(len(self.inverters), self.reserve, self.soc_max, self.soc_kw, self.charge_rate_max, self.discharge_rate_max))
1887+
self.log("Found {} inverters total reserve {} soc_max {} soc {} charge rate {} kw discharge rate {} kw".format(len(self.inverters), self.reserve, self.soc_max, self.soc_kw, self.charge_rate_max * 60, self.discharge_rate_max * 60))
18841888

18851889
# Work out current charge limits
18861890
self.charge_limit = [self.current_charge_limit * self.soc_max / 100.0 for i in range(0, len(self.charge_window))]
@@ -1943,12 +1947,12 @@ def update_pred(self):
19431947
else:
19441948
self.log("Car charging hold {} threshold {}".format(self.car_charging_hold, self.car_charging_threshold*60.0))
19451949

1946-
# Simulate current settings (inverter 0)
1947-
metric, self.charge_limit_percent, import_kwh_battery, import_kwh_house, export_kwh, soc_min, soc = self.run_prediction(self.charge_limit, self.charge_window, self.discharge_window, self.discharge_enable, load_minutes, pv_forecast_minute, save='base')
1950+
# Simulate current settings
1951+
end_record = self.record_length(self.charge_window_best)
1952+
metric, self.charge_limit_percent, import_kwh_battery, import_kwh_house, export_kwh, soc_min, soc = self.run_prediction(self.charge_limit, self.charge_window, self.discharge_window, self.discharge_enable, load_minutes, pv_forecast_minute, save='base', end_record=end_record)
19481953

19491954
# Try different battery SOCs to get the best result
19501955
if self.get_arg('calculate_best', False):
1951-
end_record = self.record_length(self.charge_window_best)
19521956
record_charge_windows = max(self.max_charge_windows(end_record + self.minutes_now, self.charge_window_best), 1)
19531957
self.log("Record charge windows is {} end_record_abs was {}".format(record_charge_windows, self.time_abs_str(end_record + self.minutes_now)))
19541958

@@ -1978,8 +1982,8 @@ def update_pred(self):
19781982
self.log("Best charge limit window {} (adjusted) soc calculated at {} min {} (margin added {} and min {}) with metric {} cost {} windows {}".format(window_n, self.dp2(best_soc), self.dp2(soc_min), self.best_soc_margin, self.best_soc_min, self.dp2(best_metric), self.dp2(best_cost), self.charge_limit_best))
19791983

19801984
# Try different discharge options
1981-
if self.get_arg('set_discharge_window', False) and self.discharge_window_best:
1982-
end_record = self.record_length(self.discharge_window_best)
1985+
if self.get_arg('calculate_best', False) and self.get_arg('set_discharge_window', False) and self.discharge_window_best:
1986+
end_record = self.record_length(self.charge_window_best)
19831987
record_discharge_windows = max(self.max_charge_windows(end_record + self.minutes_now, self.discharge_window_best), 1)
19841988

19851989
# Set all to off

0 commit comments

Comments
 (0)