Skip to content

Commit

Permalink
Merge pull request #210 from fboundy/patch
Browse files Browse the repository at this point in the history
Patch
  • Loading branch information
fboundy authored Apr 15, 2024
2 parents 0d85a38 + efa2c79 commit 7157ac3
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 40 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# PV Opt: Home Assistant Solar/Battery Optimiser v3.14.2
# PV Opt: Home Assistant Solar/Battery Optimiser v3.14.3

Solar / Battery Charging Optimisation for Home Assistant. This appDaemon application attempts to optimise charging and discharging of a home solar/battery system to minimise cost electricity cost on a daily basis using freely available solar forecast data from SolCast. This is particularly beneficial for Octopus Agile but is also benefeficial for other time-of-use tariffs such as Octopus Flux or simple Economy 7.

Expand Down
6 changes: 5 additions & 1 deletion apps/pv_opt/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,13 @@ pv_opt:
# supports_hold_soc: false
# update_cycle_seconds: 300


# Tariff comparison
# id_daily_solar: sensor.{device_name}_power_generation_today
id_solar_power: sensor.{device_name}_pv_total_power
id_solar_power:
- sensor.{device_name}_pv_power_1
- sensor.{device_name}_pv_power_2

alt_tariffs:
- name: Agile_Fix
octopus_import_tariff_code: E-1R-AGILE-23-12-06-G
Expand Down
46 changes: 19 additions & 27 deletions apps/pv_opt/pv_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from numpy import nan
import re

VERSION = "3.14.2"
VERSION = "3.14.3"

OCTOPUS_PRODUCT_URL = r"https://api.octopus.energy/v1/products/"

Expand Down Expand Up @@ -650,7 +650,7 @@ def _load_inverter(self):
self.log(f"Inverter type: {self.inverter_type}: inverter module: {inverter_brand}.py")
self.inverter = InverterController(inverter_type=self.inverter_type, host=self)
self.log(f" Device name: {self.device_name}")
self.log(f" Serial number: {self.inverter_sn}")
self.rlog(f" Serial number: {self.inverter_sn}")

else:
e = f"Inverter type {self.inverter_type} is not yet supported. Only read-only mode with explicit config from the YAML will work."
Expand Down Expand Up @@ -2557,34 +2557,26 @@ def _get_solar(self, start, end):
f"Getting yesterday's solar generation ({start.strftime(DATE_TIME_FORMAT_SHORT)} - {end.strftime(DATE_TIME_FORMAT_SHORT)}):"
)
# entity_id = self.config["id_daily_solar"]
entity_id = self.config["id_solar_power"]
if entity_id is None or not self.entity_exists(entity_id):
return

# dt = pd.date_range(
# start,
# end,
# freq="30min",
# )
entity_ids = self.config["id_solar_power"]
if not isinstance(entity_ids, list):
entity_ids = [entity_ids]

df = None
days = (pd.Timestamp.now(tz="UTC") - start).days + 1
# df = self.hass2df(entity_id, days=days).astype(float).resample("30min").ffill()

df = self.hass2df(entity_id, days=days)
if df is not None:

df = (self.riemann_avg(df).loc[start : end - pd.Timedelta("30min")] / 10).round(0) * 10

# df.index = pd.to_datetime(df.index)
# self.log(f" - {df.loc[dt[-2]]:0.1f} kWh")
# df = -df.loc[dt[0] : dt[-1]].diff(-1).clip(upper=0).iloc[:-1] * 2000
# self.log(f"\n{df.to_string()}")
# self.log(f"\n{df2.to_string()}")

else:
self.log(" - FAILED")
self.log("")
return df
for entity_id in entity_ids:
if self.entity_exists(entity_id):
x = self.hass2df(entity_id, days=days)
if x is not None:
x = (self.riemann_avg(x).loc[start : end - pd.Timedelta("30min")] / 10).round(0) * 10
if df is None:
df = x
else:
df += x
else:
self.log(" - FAILED")
self.log("")
return df

def _check_tariffs_vs_bottlecap(self):
self.ulog("Checking tariff prices vs Octopus Energy Integration:")
Expand Down
17 changes: 7 additions & 10 deletions apps/pv_opt/pvpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,6 @@ def to_df(self, start=None, end=None, **kwargs):
self.log(f"Cleared day ahead forecast for tariff {self.name}")

if pd.Timestamp.now(tz=self.tz).hour > 11 and df.index[-1].day != end.day:
# self.log(f">>> {pd.Timestamp.now(tz=self.tz).hour}")
# self.log(f">>> {df.index[-1].day}")
# self.log(f">>> {end.day}")

# if it is after 11 but we don't have new Agile prices yet, check for a day-ahead forecast
if self.day_ahead is None:
Expand Down Expand Up @@ -754,13 +751,13 @@ def optimised_force(self, initial_soc, static_flows, contract: Contract, **kwarg
min_power = min(
slot_power_required, slot_charger_power_available, slot_available_capacity
)
if log:
str_log_x = (
f">>> Slot: {slot.strftime(TIME_FORMAT)} Factor: {factor:0.3f} Forced: {x['forced'].loc[slot]:6.0f}W "
+ f"End SOC: {x['soc_end'].loc[slot]:4.1f}% SPR: {slot_power_required:6.0f}W "
+ f"SCPA: {slot_charger_power_available:6.0f}W SAC: {slot_available_capacity:6.0f}W Min Power: {min_power:6.0f}W"
)
self.log(str_log_x)
# if log:
# str_log_x = (
# f">>> Slot: {slot.strftime(TIME_FORMAT)} Factor: {factor:0.3f} Forced: {x['forced'].loc[slot]:6.0f}W "
# + f"End SOC: {x['soc_end'].loc[slot]:4.1f}% SPR: {slot_power_required:6.0f}W "
# + f"SCPA: {slot_charger_power_available:6.0f}W SAC: {slot_available_capacity:6.0f}W Min Power: {min_power:6.0f}W"
# )
# self.log(str_log_x)
slots.append(
(
slot,
Expand Down
6 changes: 5 additions & 1 deletion apps/pv_opt/sunsynk.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
"id_consumption": "sensor.{device_name}_{inverter_sn}_load_power",
"id_grid_import_today": "sensor.{device_name}_{inverter_sn}_day_grid_import",
"id_grid_export_today": "sensor.{device_name}_{inverter_sn}_day_grid_export",
"id_solar_power": [
"sensor.{device_name}_{inverter_sn}_pv1_power",
"sensor.{device_name}_{inverter_sn}_pv2_power",
],
"supports_hold_soc": False,
"update_cycle_seconds": 300,
},
Expand Down Expand Up @@ -198,7 +202,7 @@ def control_discharge(self, enable, **kwargs):
self.config["json_gen_discharge_enable"]: False,
} | {x: "00:00" for x in self.config["json_timed_discharge_unused"]}

self._solarsynk_set_helper(params)
self._solarsynk_set_helper(**params)

else:
params = {
Expand Down

0 comments on commit 7157ac3

Please sign in to comment.