Skip to content

Commit

Permalink
Merge pull request #136 from fboundy/dev
Browse files Browse the repository at this point in the history
3.9.2 - Handle no Export tariff
  • Loading branch information
fboundy authored Feb 24, 2024
2 parents 2ca8476 + 0128bce commit 5222970
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 41 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.9.1
# PV Opt: Home Assistant Solar/Battery Optimiser v3.9.2

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
4 changes: 2 additions & 2 deletions apps/pv_opt/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pv_opt:
# Octopus account parameters
# ========================================

# octopus_auto: False # Read tariffs from the Octopus Energy integration. If successful this over-rides the following parameters
octopus_auto: False # Read tariffs from the Octopus Energy integration. If successful this over-rides the following parameters

# octopus_account: !secret octopus_account
# octopus_api_key: !secret octopus_api_key
Expand All @@ -91,7 +91,7 @@ pv_opt:
# octopus_import_tariff_code: E-2R-VAR-22-11-01-G
# octopus_export_tariff_code: E-1R-AGILE-OUTGOING-19-05-13-G

# octopus_import_tariff_code: E-1R-AGILE-FLEX-22-11-25-G
octopus_import_tariff_code: E-1R-AGILE-23-12-06-G
# octopus_export_tariff_code: E-1R-OUTGOING-LITE-FIX-12M-23-09-12-G

# octopus_import_tariff_code: E-1R-FLUX-IMPORT-23-02-14-G
Expand Down
46 changes: 26 additions & 20 deletions apps/pv_opt/pv_opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#
USE_TARIFF = True

VERSION = "3.9.1"
VERSION = "3.9.2"
DEBUG = False

DATE_TIME_FORMAT_LONG = "%Y-%m-%d %H:%M:%S%z"
Expand Down Expand Up @@ -724,7 +724,8 @@ def _load_contract(self):
raise ValueError(e)

else:
# self._check_tariffs()
if self.contract.tariffs["export"] is None:
self.contract.tariffs["export"] = pv.Tariff("None", export=True, unit=0, octopus=False, host=self)

self.rlog("")
self._load_saving_events()
Expand All @@ -738,27 +739,28 @@ def _check_tariffs(self):
self.log("Checking tariff start and end times:")
self.log("------------------------------------")
tariff_error = False
for tariff in self.contract.tariffs:
for direction in self.contract.tariffs:
# for imp_exp, t in zip(IMPEXP, [self.contract.imp, self.contract.exp]):
t = self.contract.tariffs[tariff]
try:
z = t.end().strftime(DATE_TIME_FORMAT_LONG)
if t.end() < pd.Timestamp.now(tz="UTC"):
z = z + " <<< ERROR: Tariff end datetime in past"
tariff_error = True
tariff = self.contract.tariffs[direction]
if tariff is not None:
try:
z = tariff.end().strftime(DATE_TIME_FORMAT_LONG)
if tariff.end() < pd.Timestamp.now(tz="UTC"):
z = z + " <<< ERROR: Tariff end datetime in past"
tariff_error = True

except:
z = "N/A"
except:
z = "N/A"

if t.start() > pd.Timestamp.now(tz="UTC"):
z = z + " <<< ERROR: Tariff start datetime in future"
tariff_error = True
if tariff.start() > pd.Timestamp.now(tz="UTC"):
z = z + " <<< ERROR: Tariff start datetime in future"
tariff_error = True

self.log(
f" {tariff.title()}: {t.name:40s} Start: {t.start().strftime(DATE_TIME_FORMAT_LONG)} End: {z} "
)
if "AGILE" in t.name:
self.agile = True
self.log(
f" {direction.title()}: {tariff.name:40s} Start: {tariff.start().strftime(DATE_TIME_FORMAT_LONG)} End: {z} "
)
if "AGILE" in tariff.name:
self.agile = True

if self.agile:
self.log(" AGILE tariff detected. Rates will update at 16:00 daily")
Expand Down Expand Up @@ -2255,7 +2257,11 @@ def _check_tariffs_vs_bottlecap(self):
self.log("-----------------------------------------------------")
for direction in self.contract.tariffs:
if self.bottlecap_entities[direction] is None:
str_log = "No OE Integration entity found"
str_log = "No OE Integration entity found."

elif self.contract.tariffs[direction].name == "None":
str_log = "No export tariff."

else:
df = pd.DataFrame(self.get_state(self.bottlecap_entities[direction], attribute=("rates"))).set_index('start')['value_inc_vat']
df.index = pd.to_datetime(df.index)
Expand Down
45 changes: 27 additions & 18 deletions apps/pv_opt/pvpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ def __init__(
self,
name,
export=False,
fixed=None,
unit=None,
fixed=0,
unit=0,
valid_from = pd.Timestamp.now(tz="UTC").normalize() - pd.Timedelta(hours=24),
day=None,
night=None,
eco7=False,
Expand All @@ -44,10 +45,11 @@ def __init__(
self.get_octopus(**kwargs)

else:
self.fixed = fixed
self.unit = unit
self.day = day
self.night = night
self.fixed = [{'value_inc_vat': fixed, 'valid_from': valid_from}]
self.unit = [{'value_inc_vat': unit, 'valid_from': valid_from}]
if eco7:
self.day = [{'value_inc_vat': day, 'valid_from': valid_from}]
self.night = [{'value_inc_vat': night, 'valid_from': valid_from}]

def _oct_time(self, d):
# print(d)
Expand Down Expand Up @@ -467,7 +469,8 @@ def net_cost(self, grid_flow, **kwargs):
nc += imp_df["unit"] * grid_imp / 2000
if kwargs.get("log"):
self.log(f">>> Export{self.tariffs['export'].to_df(start,end).to_string()}")
nc += self.tariffs["export"].to_df(start, end, **kwargs)["unit"] * grid_exp / 2000
if self.tariffs["export"] is not None:
nc += self.tariffs["export"].to_df(start, end, **kwargs)["unit"] * grid_exp / 2000

return nc

Expand Down Expand Up @@ -574,22 +577,23 @@ def optimised_force(self, initial_soc, static_flows, contract: Contract, **kwarg

prices = pd.DataFrame()
for direction in contract.tariffs:
prices = pd.concat(
[
prices,
contract.tariffs[direction].to_df(
start=static_flows.index[0], end=static_flows.index[-1]
)["unit"],
],
axis=1,
)
if contract.tariffs[direction] is not None:
prices = pd.concat(
[
prices,
contract.tariffs[direction].to_df(
start=static_flows.index[0], end=static_flows.index[-1]
)["unit"],
],
axis=1,
)

if log:
self.log(
f" Optimiser prices loaded for period {prices.index[0].strftime(TIME_FORMAT)} - {prices.index[-1].strftime(TIME_FORMAT)}"
)

prices = prices.set_axis(contract.tariffs.keys(), axis=1)
prices = prices.set_axis([t for t in contract.tariffs.keys() if contract.tariffs[t] is not None], axis=1)

df = pd.concat(
[prices, consumption, self.flows(initial_soc, static_flows, **kwargs)],
Expand Down Expand Up @@ -812,7 +816,12 @@ def optimised_force(self, initial_soc, static_flows, contract: Contract, **kwarg
)

slots_added = 999
j = 0
# Only do the rest if there is an export tariff:
if prices['export'].sum() >0:
j = 0
else:
j = max_iters


while (slots_added > 0) and (j < max_iters):
slots_added = 0
Expand Down

0 comments on commit 5222970

Please sign in to comment.