forked from openWB/core
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Rabot dynamischer Tarif (openWB#1655)
* Grundstruktur ohne Anpassung * Anapssung Rabot * fix Umrechnungsfaktor * fix flake8 + added try except for get_raw_prices
- Loading branch information
Showing
3 changed files
with
121 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from typing import Optional | ||
|
||
|
||
class RabotToken(): | ||
def __init__(self, | ||
access_token: Optional[str] = None, | ||
expires_in: Optional[str] = None, | ||
created_at: Optional[str] = None) -> None: | ||
self.access_token = access_token # don't show in UI | ||
self.expires_in = expires_in # don't show in UI | ||
self.created_at = created_at # don't show in UI | ||
|
||
|
||
class RabotTariffConfiguration: | ||
def __init__(self, | ||
client_id: Optional[str] = None, | ||
client_secret: Optional[str] = None, | ||
token: RabotToken = None): | ||
self.client_id = client_id | ||
self.client_secret = client_secret | ||
self.token = token or RabotToken() | ||
|
||
|
||
class RabotTariff: | ||
def __init__(self, | ||
name: str = "Rabot", | ||
type: str = "rabot", | ||
configuration: RabotTariffConfiguration = None) -> None: | ||
self.name = name | ||
self.type = type | ||
self.configuration = configuration or RabotTariffConfiguration() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
#!/usr/bin/env python3 | ||
import datetime | ||
import logging | ||
from typing import Dict | ||
import pytz | ||
from requests.exceptions import HTTPError | ||
|
||
from dataclass_utils import asdict | ||
from helpermodules import timecheck | ||
from helpermodules.pub import Pub | ||
from modules.common import configurable_tariff, req | ||
from modules.common.abstract_device import DeviceDescriptor | ||
from modules.common.component_state import TariffState | ||
from modules.electricity_tariffs.rabot.config import RabotTariff, RabotToken | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
def validate_token(config: RabotTariff) -> None: | ||
if config.configuration.token.expires_in: | ||
expiration = config.configuration.token.created_at + config.configuration.token.expires_in | ||
log.debug("No need to authenticate. Valid token already present.") | ||
if timecheck.create_timestamp() > expiration: | ||
log.debug("Access token expired. Refreshing token.") | ||
_refresh_token(config) | ||
else: | ||
_refresh_token(config) | ||
|
||
|
||
def _refresh_token(config: RabotTariff): | ||
data = { | ||
'client_id': {config.configuration.client_id}, | ||
'client_secret': {config.configuration.client_secret}, | ||
'grant_type': 'client_credentials', | ||
'scope': 'openid offline_access api:hems', | ||
} | ||
response = req.get_http_session().post( | ||
'https://test-auth.rabot-charge.de/connect/token?client_id=&client_secret=&username=&password=&scope=*&' | ||
+ 'grant_type=client_credentials', data=data).json() | ||
config.configuration.token = RabotToken(access_token=response["access_token"], | ||
expires_in=response["expires_in"], | ||
created_at=timecheck.create_timestamp()) | ||
Pub().pub("openWB/set/optional/et/provider", asdict(config)) | ||
|
||
|
||
def fetch(config: RabotTariff) -> None: | ||
def get_raw_prices(): | ||
return req.get_http_session().get( | ||
"https://test-api.rabot-charge.de/hems/v1/day-ahead-prices/limited", | ||
headers={"Content-Type": "application/json", | ||
"Authorization": f'Bearer {config.configuration.token.access_token}'}, | ||
params={"from": start_date, "tz": timezone} | ||
).json()["records"] | ||
|
||
validate_token(config) | ||
# start_date von voller Stunde sonst liefert die API die nächste Stunde | ||
start_date = datetime.datetime.fromtimestamp( | ||
timecheck.create_unix_timestamp_current_full_hour()).astimezone( | ||
pytz.timezone("Europe/Berlin")).isoformat(sep="T", timespec="seconds") | ||
if datetime.datetime.today().astimezone(pytz.timezone("Europe/Berlin")).dst().total_seconds()/3600: | ||
# Sommerzeit | ||
timezone = "UTC+2:00" | ||
else: | ||
timezone = "UTC+1:00" | ||
try: | ||
raw_prices = get_raw_prices() | ||
except HTTPError as error: | ||
if error.response.status_code == 401: | ||
_refresh_token(config) | ||
raw_prices = get_raw_prices() | ||
else: | ||
raise error | ||
prices: Dict[int, float] = {} | ||
for data in raw_prices: | ||
formatted_price = data["priceInCentPerKwh"]/100000 # Cent/kWh -> €/Wh | ||
timestamp = datetime.datetime.fromisoformat(data["timestamp"]).astimezone( | ||
pytz.timezone("Europe/Berlin")).timestamp() | ||
prices.update({int(timestamp): formatted_price}) | ||
return prices | ||
|
||
|
||
def create_electricity_tariff(config: RabotTariff): | ||
validate_token(config) | ||
|
||
def updater(): | ||
return TariffState(prices=fetch(config)) | ||
return configurable_tariff.ConfigurableElectricityTariff(config=config, component_updater=updater) | ||
|
||
|
||
device_descriptor = DeviceDescriptor(configuration_factory=RabotTariff) |