Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync Dev with Main #286

Merged
merged 2 commits into from
Nov 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 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.16.1
# PV Opt: Home Assistant Solar/Battery Optimiser v3.17.0

<h2>This documentation needs updating!</h2>

Expand Down Expand Up @@ -498,6 +498,50 @@ These parameters will define how PV Opt estimates daily consumption:
| Daily Consumption | kWh | `number.pvopt_daily_consumption_kwh` | 17 | Estimated daily consumption to use when predicting future load |
| Shape Consumption Profile | `on`/`off` | `switch.pvopt_shape_consumption_profile` | On | Defines whether to shapoe the consumption to a typical daily profile (`on`) or to assume constant usage (`off`) |

<h3>Pricing Parameters</h3>
These parameters set the price that PV Opt uses:

<h4>Octopus Tariffs (usinng the Octopus API)</h4>

| Parameter | Units | Entity | Default | Description |
|:--|:--:| :-- | :--:|:--|
| Octopus Auto|`on`/`off` | `octopus_auto` | On | Read tariffs from the Octopus Energy integration. If successful this over-rides the following parameters
| Octopus Account | `string` | `octopus_account` | | Octopus Account ID (Axxxxxxxx) - not required if Octopus Auto is set|
| Octopus API Key | `string` | `octopus_api_key` | | Octopus API Key - not required if Octopus Auto is set |
| Octopus Import Tariff Code| fraction | `octopus_import_tariff_code` | | Import Tariff Code (eg `E-1R-AGILE-23-12-06-G`) |
| Octopus Export Tariff Code| fraction | `octopus_export_tariff_code` | | Export Tariff Code (eg `E-1R-AGILE-OUTGOING-19-05-13-G`)|

<h4>Manual Tariffs</h4>

Import and/or export tarifs can be set manually as follows. These can be combined with Octopus Account Codes (ie you could set Octopus Agile for input using `octopus_import_tariff_code` and a manual export). Manual tariffs <b>will not work</b> with either `Octopus Auto` or `Octopus Account`.

manual_import_tariff: True
manual_import_tariff_name: Test Importe
manual_import_tariff_tz: GB
manual_import_tariff_standing: 43
manual_import_tariff_unit:
- period_start: "00:00"
price: 4.2
- period_start: "05:00"
price: 9.7
- period_start: "16:00"
price: 77.0
- period_start: "19:00"
price: -2.0

manual_export_tariff: True
manual_export_tariff_name: Test Export
manual_export_tariff_tz: GB
manual_export_tariff_unit:
- period_start: "01:00"
price: 14.2
- period_start: "03:00"
price: 19.7
- period_start: "16:00"
price: 50.0
- period_start: "14:00"
price: 0.0


<h3>Tuning Parameters</h3>
These parameters will tweak how PV Opt runs:
Expand Down
34 changes: 30 additions & 4 deletions apps/pv_opt/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pv_opt:


# If true the current config in HA will be over-written with that in the config.yaml.
overwrite_ha_on_restart: false
overwrite_ha_on_restart: true
list_entities: true

# If true the personal data will be redacted from the log files.
Expand Down Expand Up @@ -119,12 +119,38 @@ 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

manual_import_tariff: True
manual_import_tariff_name: Test Importe
manual_import_tariff_tz: GB
manual_import_tariff_standing: 43
manual_import_tariff_unit:
- period_start: "00:00"
price: 4.2
- period_start: "05:00"
price: 9.7
- period_start: "16:00"
price: 77.0
- period_start: "19:00"
price: -2.0

manual_export_tariff: True
manual_export_tariff_name: Test Export
manual_export_tariff_tz: GB
manual_export_tariff_unit:
- period_start: "01:00"
price: 14.2
- period_start: "03:00"
price: 19.7
- period_start: "16:00"
price: 50.0
- period_start: "14:00"
price: 0.0


# The following Can be omitted if either of the above options is working correctly:

# octopus_import_tariff_code: E-2R-VAR-22-11-01-G
Expand Down
95 changes: 71 additions & 24 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.16.1"
VERSION = "3.17.0"


OCTOPUS_PRODUCT_URL = r"https://api.octopus.energy/v1/products/"
Expand Down Expand Up @@ -921,35 +921,43 @@ def _load_contract(self):
)

if self.contract is None:
tariffs = {x: None for x in IMPEXP}

if (
"octopus_import_tariff_code" in self.config
and self.config["octopus_import_tariff_code"] is not None
):
try:
str = f"Trying to load tariff codes: Import: {self.config['octopus_import_tariff_code']}"

if "octopus_export_tariff_code" in self.config:
str += f" Export: {self.config['octopus_export_tariff_code']}"
self.rlog(str)

tariffs = {x: None for x in IMPEXP}
for imp_exp in IMPEXP:
if f"octopus_{imp_exp}_tariff_code" in self.config:
tariffs[imp_exp] = pv.Tariff(
self.config[f"octopus_{imp_exp}_tariff_code"],
export=(imp_exp == "export"),
host=self,
)

self.contract = pv.Contract(
"current",
imp=tariffs["import"],
exp=tariffs["export"],
self.rlog(f"Trying to load tariff codes: Import: {self.config['octopus_import_tariff_code']}")
# try:
# First load the import as we always need that
tariffs["import"] = pv.Tariff(
self.config[f"octopus_import_tariff_code"],
export=False,
host=self,
)
elif self.get_config("manual_import_tariff", False):
tariffs["import"] = self._manual_tariff("import")

if tariffs["import"] is not None:
if "octopus_export_tariff_code" in self.config:
self.rlog(f"Trying to load tariff codes: Export: {self.config['octopus_export_tariff_code']}")
tariffs["export"] = pv.Tariff(
self.config[f"octopus_export_tariff_code"],
export=False,
host=self,
)
self.rlog("Contract tariffs loaded OK from Tariff Codes")
except Exception as e:
self.rlog(f"Unable to load Tariff Codes {e}", level="ERROR")
elif self.get_config("manual_export_tariff", False):
tariffs["export"] = self._manual_tariff("export")

self.contract = pv.Contract(
"current",
imp=tariffs["import"],
exp=tariffs["export"],
host=self,
)
self.rlog("Contract tariffs loaded OK from Tariff Codes / Manual Spec")
# except Exception as e:
# self.rlog(f"Unable to load Tariff Codes {e}", level="ERROR")

if self.contract is None:
i += 1
Expand All @@ -976,6 +984,26 @@ def _load_contract(self):

self.rlog("Finished loading contract")

def _manual_tariff(self, direction="import"):
name = self.get_config(f"manual_{direction}_tariff_name")
self.log(f"Trying to load manual {direction} tariff {name}")
tz = self.get_config(f"manual_{direction}_tariff_tz")
if direction == "import":
fixed = self.get_config(f"manual_{direction}_tariff_standing", 0.0)
else:
fixed = None
unit = self.get_config(f"manual_{direction}_tariff_unit")

return pv.Tariff(
name=name,
octopus=False,
export=(direction == "export"),
fixed=fixed,
unit=unit,
host=self,
manual=True,
)

def _check_tariffs(self):
if self.bottlecap_entities["import"] is not None:
self._check_tariffs_vs_bottlecap()
Expand Down Expand Up @@ -1004,6 +1032,7 @@ def _check_tariffs(self):
self.log(
f" {direction.title()}: {tariff.name:40s} Start: {tariff.start().strftime(DATE_TIME_FORMAT_LONG)} End: {z} "
)
self.log(tariff.to_df().to_string())
if "AGILE" in tariff.name:
self.agile = True
if "INTELLI" in tariff.name:
Expand Down Expand Up @@ -1184,6 +1213,24 @@ def _load_args(self, items=None):
self.rlog(f" {str1:34s} {str2} {str3} {x['hour']:5.2f} {str4} {x['consumption']:5.0f} W")
self.yaml_config[item] = self.config[item]

elif re.match("^manual_..port_tariff_unit$", item):
self.config[item] = values
for i, x in enumerate(values):
if i == 0:
str1 = item
str2 = "="
str3 = "Period Start:"
str4 = "Price:"
else:
str1 = ""
str2 = " "
str3 = " "
str4 = " "
self.rlog(
f" {str1:34s} {str2} {str3} {pd.Timestamp(x['period_start']).strftime('%H:%M')} {str4} {x['price']:5.0f} p/kWh"
)
self.yaml_config[item] = self.config[item]

elif "id_" in item:
self.log(f">>> Test: {self.entity_exists('update.home_assistant_core_update')}")
for v in values:
Expand Down
Loading
Loading