Skip to content

Commit 6ad2022

Browse files
cshagenLKuemmel
andauthored
Electricity tariffs (EKZ, Groupe E) (#2757)
* add electricity tariffs for EKZ and Group E * fix lint errors * fix github lint issues * fix github flake issues * fix github flake issues * fix github flake issues * Update packages/modules/electricity_tariffs/group_e/tariff.py Co-authored-by: LKuemmel <76958050+LKuemmel@users.noreply.github.com> * switch to 15min interval * 15 minute intervals for tariffs * 15 minute intervals for tariffs * fix ekz price calculation * update ekz and group-e prices modeules --------- Co-authored-by: LKuemmel <76958050+LKuemmel@users.noreply.github.com>
1 parent 62ac6e8 commit 6ad2022

6 files changed

Lines changed: 132 additions & 0 deletions

File tree

packages/modules/electricity_tariffs/ekz/__init__.py

Whitespace-only changes.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
class EkzTariffConfiguration:
2+
def __init__(self):
3+
self.country = "ch"
4+
self.unit = "rp"
5+
6+
7+
class EkzTariff:
8+
def __init__(self,
9+
name: str = "EKZ (CH)",
10+
type: str = "ekz",
11+
official: bool = False,
12+
configuration: EkzTariffConfiguration = None) -> None:
13+
self.name = name
14+
self.type = type
15+
self.official = official
16+
self.configuration = configuration or EkzTariffConfiguration()
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/usr/bin/env python3
2+
from datetime import datetime, timezone, timedelta
3+
from dateutil import tz
4+
from urllib.parse import quote
5+
from typing import Dict
6+
from modules.common import req
7+
from modules.common.abstract_device import DeviceDescriptor
8+
from modules.common.component_state import TariffState
9+
from modules.electricity_tariffs.ekz.config import EkzTariffConfiguration
10+
from modules.electricity_tariffs.ekz.config import EkzTariff
11+
12+
13+
# Extract timestamp from power price entry
14+
def timestamp(power):
15+
return str(int(datetime.strptime(power['start_timestamp'], "%Y-%m-%dT%H:%M:%S%z")
16+
.astimezone(tz.tzutc()).timestamp()))
17+
18+
19+
# Read prices from EKZ API
20+
def readApi() -> list[tuple[str, float]]:
21+
endpoint = "https://api.tariffs.ekz.ch/v1/tariffs"
22+
tariff_power = "electricity_dynamic"
23+
tariff_grid = "grid_400D_inclFees"
24+
utcnow = datetime.now(timezone.utc)
25+
startDate = utcnow.strftime("%Y-%m-%dT%H:00:00Z")
26+
endDate = (utcnow + timedelta(days=2)).strftime("%Y-%m-%dT%H:00:00Z")
27+
session = req.get_http_session()
28+
power_raw = session.get(
29+
url=endpoint +
30+
f"?tariff_name={tariff_power}&start_timestamp={quote(startDate)}&end_timestamp={quote(endDate)}",
31+
).json()["prices"]
32+
grid_raw = session.get(
33+
url=endpoint +
34+
f"?tariff_name={tariff_grid}&start_timestamp={quote(startDate)}&end_timestamp={quote(endDate)}",
35+
).json()["prices"]
36+
return [(timestamp(power), (power['electricity'][1]['value']+grid['grid'][1]['value'])/1000)
37+
for power, grid in zip(power_raw, grid_raw)]
38+
39+
40+
# Fetch electricity prices from EKZ API
41+
# API Reference: https://api.tariffs.ekz.ch/swagger
42+
def fetch_prices(config: EkzTariffConfiguration) -> Dict[str, float]:
43+
pricelist = readApi()
44+
prices: Dict[str, float] = dict(pricelist)
45+
return prices
46+
47+
48+
def create_electricity_tariff(config: EkzTariff):
49+
def updater():
50+
return TariffState(prices=fetch_prices(config.configuration))
51+
return updater
52+
53+
54+
device_descriptor = DeviceDescriptor(configuration_factory=EkzTariff)

packages/modules/electricity_tariffs/groupe_e/__init__.py

Whitespace-only changes.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class GroupeETariffConfiguration:
2+
def __init__(self):
3+
self.country = "ch"
4+
5+
6+
class GroupeETariff:
7+
def __init__(self,
8+
name: str = "Groupe E (CH)",
9+
type: str = "groupe_e",
10+
official: bool = False,
11+
configuration: GroupeETariffConfiguration = None) -> None:
12+
self.name = name
13+
self.type = type
14+
self.official = official
15+
self.configuration = configuration or GroupeETariffConfiguration()
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/usr/bin/env python3
2+
from datetime import datetime, timedelta
3+
from dateutil import tz
4+
from urllib.parse import quote
5+
from typing import Dict
6+
from modules.common import req
7+
from modules.common.abstract_device import DeviceDescriptor
8+
from modules.common.component_state import TariffState
9+
from modules.electricity_tariffs.groupe_e.config import GroupeETariffConfiguration
10+
from modules.electricity_tariffs.groupe_e.config import GroupeETariff
11+
12+
13+
# Extract timestamp from power price entry
14+
def timestamp(power):
15+
return str(int(datetime.strptime(power['start_timestamp'], "%Y-%m-%dT%H:%M:%S%z")
16+
.astimezone(tz.tzutc()).timestamp()))
17+
18+
19+
# Read prices from Groupe E API
20+
def readApi() -> list[tuple[str, float]]:
21+
endpoint = "https://api.tariffs.groupe-e.ch/v1/tariffs"
22+
tariffName = "vario_plus"
23+
startDate = datetime.now().strftime("%Y-%m-%dT%H:00:00+01:00")
24+
endDate = (datetime.now() + timedelta(days=2)).strftime("%Y-%m-%dT%H:00:00+01:00")
25+
session = req.get_http_session()
26+
prices_raw = session.get(
27+
url=endpoint +
28+
f"?start_timestamp={ quote(startDate) }&end_timestamp={ quote(endDate) }",
29+
).json()
30+
return [(timestamp(power), (power[tariffName]/100000))
31+
for power in prices_raw]
32+
33+
34+
# Fetch prices and return as a dictionary
35+
def fetch_prices(config: GroupeETariffConfiguration) -> Dict[str, float]:
36+
pricelist = readApi()
37+
prices: Dict[str, float] = dict(pricelist)
38+
return prices
39+
40+
41+
def create_electricity_tariff(config: GroupeETariff):
42+
def updater():
43+
return TariffState(prices=fetch_prices(config.configuration))
44+
return updater
45+
46+
47+
device_descriptor = DeviceDescriptor(configuration_factory=GroupeETariff)

0 commit comments

Comments
 (0)