Skip to content

Commit

Permalink
Hourly rate chart (#1587)
Browse files Browse the repository at this point in the history
* Hourly rate chart

* [pre-commit.ci lite] apply automatic fixes

* Update reporting

* Price chart with hourly rate

* [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>
  • Loading branch information
springfall2008 and pre-commit-ci-lite[bot] authored Nov 3, 2024
1 parent f8acc45 commit 652c6fe
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 8 deletions.
96 changes: 90 additions & 6 deletions apps/predbat/predbat.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import asyncio
import json

THIS_VERSION = "v8.5.6"
THIS_VERSION = "v8.5.7"
PREDBAT_FILES = ["predbat.py", "config.py", "prediction.py", "utils.py", "inverter.py", "ha.py", "download.py", "unit_test.py", "web.py", "predheat.py", "futurerate.py"]
from download import predbat_update_move, predbat_update_download, check_install

Expand Down Expand Up @@ -2306,6 +2306,15 @@ def run_prediction(self, charge_limit, charge_window, discharge_window, discharg
"icon": "mdi:battery",
},
)

# Compute battery value now and at end of plan
rate_min_now = self.rate_min_forward.get(self.minutes_now, self.rate_min) / self.inverter_loss / self.battery_loss + self.metric_battery_cycle
rate_min_end = self.rate_min_forward.get(end_record, self.rate_min) / self.inverter_loss / self.battery_loss + self.metric_battery_cycle
rate_export_min_now = self.rate_export_min * self.inverter_loss * self.battery_loss_discharge - self.metric_battery_cycle - rate_min_now
rate_export_min_end = self.rate_export_min * self.inverter_loss * self.battery_loss_discharge - self.metric_battery_cycle - rate_min_end
value_kwh_now = rate_min_now * self.metric_battery_value_scaling * max(rate_min_now, 1.0, rate_export_min_now)
value_kwh_end = rate_min_end * self.metric_battery_value_scaling * max(rate_min_end, 1.0, rate_export_min_end)

self.dashboard_item(
self.prefix + ".soc_kw_best",
state=self.dp3(final_soc),
Expand All @@ -2316,6 +2325,11 @@ def run_prediction(self, charge_limit, charge_window, discharge_window, discharg
"state_class": "measurement",
"unit_of_measurement": "kWh",
"first_charge_kwh": first_charge_soc,
"soc_now": self.dp2(self.soc_kw),
"value_per_kwh_now": self.dp2(value_kwh_now),
"value_per_kwh_end": self.dp2(value_kwh_end),
"value_now": self.dp2(self.soc_kw * value_kwh_now),
"value_end": self.dp2(final_soc * value_kwh_end),
"icon": "mdi:battery",
},
)
Expand Down Expand Up @@ -4532,6 +4546,42 @@ def today_cost(self, import_today, export_today, car_today):
day_carbon_time = {}
carbon_g = 0

hour_cost = 0
hour_cost_import = 0
hour_cost_export = 0
hour_cost_car = 0
hour_energy = 0
hour_energy_export = 0
hour_energy_import = 0
hour_energy_car = 0

for minute in range(60):
energy_import = self.get_from_incrementing(import_today, minute)

if car_today:
energy_car = self.get_from_incrementing(car_today, minute)
else:
energy_car = 0

if export_today:
energy_export = self.get_from_incrementing(export_today, minute)
else:
energy_export = 0

hour_energy += energy_import - energy_export
hour_energy_import += energy_import
hour_energy_export += energy_export
hour_energy_car += energy_car

if self.rate_import:
hour_cost += self.rate_import[minute] * energy_import
hour_cost_import += self.rate_import[minute] * energy_import
hour_cost_car += self.rate_import[minute] * energy_car

if self.rate_export:
hour_cost -= self.rate_export[minute] * energy_export
hour_cost_export -= self.rate_export[minute] * energy_export

for minute in range(self.minutes_now):
# Add in standing charge
if (minute % (24 * 60)) == 0:
Expand Down Expand Up @@ -4582,10 +4632,15 @@ def today_cost(self, import_today, export_today, car_today):
day_cost_time_export[stamp] = self.dp2(day_cost_export)
day_carbon_time[stamp] = self.dp2(carbon_g)

day_pkwh = 0
day_car_pkwh = 0
day_import_pkwh = 0
day_export_pkwh = 0
day_pkwh = self.rate_import.get(0, 0)
day_car_pkwh = self.rate_import.get(0, 0)
day_import_pkwh = self.rate_import.get(0, 0)
day_export_pkwh = self.rate_export.get(0, 0)
hour_pkwh = self.rate_import.get(0, 0)
hour_pkwh_import = self.rate_import.get(0, 0)
hour_pkwh_car = self.rate_import.get(0, 0)
hour_pkwh_export = self.rate_export.get(0, 0)

if day_energy_total > 0:
day_pkwh = day_cost_nosc / day_energy_total
if day_car > 0:
Expand All @@ -4594,20 +4649,49 @@ def today_cost(self, import_today, export_today, car_today):
day_import_pkwh = day_cost_nosc_import / day_import
if day_export > 0:
day_export_pkwh = day_cost_export / day_export
if hour_energy > 0:
hour_pkwh = hour_cost / hour_energy
if hour_energy_import > 0:
hour_pkwh_import = hour_cost_import / hour_energy_import
if hour_energy_export > 0:
hour_pkwh_export = hour_cost_export / hour_energy_export
if hour_energy_car > 0:
hour_pkwh_car = hour_cost_car / hour_energy_car

self.dashboard_item(
self.prefix + ".cost_today",
state=self.dp2(day_cost),
attributes={
"results": self.filtered_times(day_cost_time),
"friendly_name": "Cost so far today",
"friendly_name": "Cost so far today (since midnight)",
"state_class": "measurement",
"unit_of_measurement": self.currency_symbols[1],
"icon": "mdi:currency-usd",
"energy": self.dp2(day_energy_total),
"p/kWh": self.dp2(day_pkwh),
},
)
self.dashboard_item(
self.prefix + ".cost_hour",
state=self.dp2(hour_cost),
attributes={
"friendly_name": "Cost in last hour",
"state_class": "measurement",
"unit_of_measurement": self.currency_symbols[1],
"icon": "mdi:currency-usd",
"energy": self.dp2(hour_energy),
"energy_import": self.dp2(hour_energy_import),
"energy_export": self.dp2(hour_energy_export),
"energy_car": self.dp2(hour_energy_car),
"cost_import": self.dp2(hour_cost_import),
"cost_export": self.dp2(hour_cost_export),
"cost_car": self.dp2(hour_cost_car),
"p/kWh": self.dp2(hour_pkwh),
"p/kWh_car": self.dp2(hour_pkwh_car),
"p/kWh_import": self.dp2(hour_pkwh_import),
"p/kWh_export": self.dp2(hour_pkwh_export),
},
)
if self.num_cars > 0:
self.dashboard_item(
self.prefix + ".cost_today_car",
Expand Down
7 changes: 5 additions & 2 deletions apps/predbat/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def history_update(self):
self.pv_power_hist = self.history_attribute(self.base.get_history_wrapper(self.base.prefix + ".pv_power", 7))
self.pv_forecast_hist = self.history_attribute(self.base.get_history_wrapper("sensor." + self.base.prefix + "_pv_forecast_h0", 7))
self.cost_today_hist = self.history_attribute(self.base.get_history_wrapper(self.base.prefix + ".cost_today", 2), state_key="p/kWh", attributes=True)
self.cost_hour_hist = self.history_attribute(self.base.get_history_wrapper(self.base.prefix + ".cost_hour", 2), state_key="p/kWh", attributes=True)

async def start(self):
# Start the web server on port 5052
Expand Down Expand Up @@ -657,12 +658,14 @@ def get_chart(self, chart):
]
text += self.render_chart(series_data, self.base.currency_symbols[1], "Home Cost Prediction", now_str)
elif chart == "Rates":
cost_pkwh = self.prune_today(self.cost_today_hist, prune=False, prune_future=True)
cost_pkwh_today = self.prune_today(self.cost_today_hist, prune=False, prune_future=True)
cost_pkwh_hour = self.prune_today(self.cost_hour_hist, prune=False, prune_future=True)
series_data = [
{"name": "Import", "data": rates, "opacity": "1.0", "stroke_width": "3", "stroke_curve": "stepline"},
{"name": "Export", "data": rates_export, "opacity": "0.2", "stroke_width": "2", "stroke_curve": "stepline", "chart_type": "area"},
{"name": "Gas", "data": rates_gas, "opacity": "0.2", "stroke_width": "2", "stroke_curve": "stepline", "chart_type": "area"},
{"name": "Average p/kWh", "data": cost_pkwh, "opacity": "1.0", "stroke_width": "3", "stroke_curve": "stepline"},
{"name": "Hourly p/kWh", "data": cost_pkwh_hour, "opacity": "1.0", "stroke_width": "2", "stroke_curve": "stepline"},
{"name": "Today p/kWh", "data": cost_pkwh_today, "opacity": "1.0", "stroke_width": "2", "stroke_curve": "stepline"},
]
text += self.render_chart(series_data, self.base.currency_symbols[1], "Energy Rates", now_str)
elif chart == "InDay":
Expand Down

0 comments on commit 652c6fe

Please sign in to comment.