Skip to content

Commit

Permalink
Merge pull request #305 from custom-components/backoff
Browse files Browse the repository at this point in the history
Backoff
  • Loading branch information
Hellowlol authored Mar 26, 2023
2 parents 2b4ed5c + 3953f37 commit 8d76be1
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 79 deletions.
7 changes: 2 additions & 5 deletions custom_components/nordpool/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from homeassistant.core import Config, HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_call_later, async_track_time_change
from homeassistant.helpers.event import async_track_time_change
from homeassistant.util import dt as dt_utils
from pytz import timezone

Expand All @@ -32,7 +32,7 @@


NAME = DOMAIN
VERSION = "0.0.11"
VERSION = "0.0.13"
ISSUEURL = "https://github.com/custom-components/nordpool/issues"

STARTUP = f"""
Expand Down Expand Up @@ -73,9 +73,6 @@ async def _update(self, type_="today", dt=None):
data = await spot.hourly(end_date=dt)
if data:
self._data[currency][type_] = data["areas"]
else:
_LOGGER.info("Some crap happened, retrying request later.")
async_call_later(hass, 20, partial(self._update, type_=type_, dt=dt))

async def update_today(self, _: datetime):
"""Update today's prices"""
Expand Down
86 changes: 22 additions & 64 deletions custom_components/nordpool/aio_price.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@

from dateutil import tz
from dateutil.parser import parse as parse_dt
import backoff
import aiohttp
from nordpool.elspot import Prices

from .misc import add_junk
from .misc import add_junk, exceptions_raiser

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -141,8 +143,6 @@ def join_result_for_correct_time(results, dt):
else:
fin["areas"][key]["values"].append(val)

# _LOGGER.debug("Combines result: %s", fin)

return fin


Expand Down Expand Up @@ -177,6 +177,9 @@ async def _fetch_json(self, data_type, end_date=None):
endDate=end_date.strftime("%d-%m-%Y"),
)

# Add more exceptions as we find them. KeyError is raised when the api return
# junk due to currency not being available in the data.
@backoff.on_exception(backoff.expo, (aiohttp.ClientError, KeyError), logger=_LOGGER)
async def fetch(self, data_type, end_date=None, areas=None):
"""
Fetch data from API.
Expand All @@ -201,67 +204,22 @@ async def fetch(self, data_type, end_date=None, areas=None):
if areas is None:
areas = []

# now = datetime.utcnow()
# timezone_for_data = now.astimezone(tz.gettz(ts))
# stock = datetime.utcnow().astimezone(tz.gettz("Europe/Stockholm"))
# if stock.utcoffset(now) == timezone_for_data.utcoffset(now):
# pass

# compare utc offset
if self.timeezone == tz.gettz("Europe/Stockholm"):
data = await self._fetch_json(data_type, end_date)
return self._parse_json(data, areas)
else:
yesterday = datetime.now() - timedelta(days=1)
today = datetime.now()
tomorrow = datetime.now() + timedelta(days=1)

# days = [yesterday, today, tomorrow]
# Workaround for api changes.
# Disabled for now as nordpool have fixed the api endpoint that we used.
# if self.currency != "EUR":
# # Only need to check for today price
# # as this is only available for dk, nor, se
# # and all of them are in the correct timezone.
# days = [today, tomorrow]
# idx_list = COUNTRY_BASE_PAGE.values()
# stuff = []
# for d in days:
# dat = {"areas": {}}
# for pageidx in idx_list:
# task = self._io(
# self.API_URL_CURRENCY % pageidx,
# currency=self.currency,
# endDate=d.strftime("%d-%m-%Y"),
# )
# data = await task
#
# try:
# jd = self._parse_json(data, areas)
#
# for key, value in jd.get("areas").items():
# dat["areas"][key] = value
#
# except Exception as e:
# _LOGGER.debug("Error with %s %s", d, pageidx)
# raise
#
# stuff.append(dat)
#
# return join_result_for_correct_time(stuff, end_date)

# else:

jobs = [
self._fetch_json(data_type, yesterday),
self._fetch_json(data_type, today),
self._fetch_json(data_type, tomorrow),
]

res = await asyncio.gather(*jobs)

raw = [self._parse_json(i, areas) for i in res]
return join_result_for_correct_time(raw, end_date)
yesterday = datetime.now() - timedelta(days=1)
today = datetime.now()
tomorrow = datetime.now() + timedelta(days=1)

jobs = [
self._fetch_json(data_type, yesterday),
self._fetch_json(data_type, today),
self._fetch_json(data_type, tomorrow),
]

res = await asyncio.gather(*jobs)

raw = [self._parse_json(i, areas) for i in res]
# Just to test should be removed
# exceptions_raiser()
return join_result_for_correct_time(raw, end_date)

async def hourly(self, end_date=None, areas=None):
"""Helper to fetch hourly data, see Prices.fetch()"""
Expand Down
7 changes: 4 additions & 3 deletions custom_components/nordpool/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"iot_class": "cloud_polling",
"issue_tracker": "https://github.com/custom-components/nordpool/issues",
"requirements": [
"nordpool>=0.2"
"nordpool>=0.2",
"backoff"
],
"version": "0.0.11"
}
"version": "0.0.13"
}
13 changes: 13 additions & 0 deletions custom_components/nordpool/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,19 @@
_LOGGER = logging.getLogger(__name__)


def exceptions_raiser():
"""Utility to check that all exceptions are raised."""
import aiohttp
import random

exs = [KeyError, aiohttp.ClientError, None, None, None]
got = random.choice(exs)
if got is None:
pass
else:
raise got


def round_decimal(number, decimal_places=3):
decimal_value = Decimal(number)
return decimal_value.quantize(Decimal(10) ** -decimal_places)
Expand Down
12 changes: 5 additions & 7 deletions custom_components/nordpool/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@
from homeassistant.util import dt as dt_utils

# Import sensor entity and classes.
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorStateClass,
)
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity
from jinja2 import pass_context

from . import (
Expand Down Expand Up @@ -139,7 +135,7 @@ async def async_setup_entry(hass, config_entry, async_add_devices):
class NordpoolSensor(SensorEntity):
"Sensors data"
_attr_device_class = SensorDeviceClass.MONETARY
_attr_state_class = SensorStateClass.MEASUREMENT
_attr_suggested_display_precision = None

def __init__(
self,
Expand All @@ -158,7 +154,9 @@ def __init__(
self._area = area
self._currency = currency or _REGIONS[area][0]
self._price_type = price_type
# Should be depricated in a future version
self._precision = precision
self._attr_suggested_display_precision = precision
self._low_price_cutoff = low_price_cutoff
self._use_cents = use_cents
self._api = api
Expand Down Expand Up @@ -425,7 +423,7 @@ def extra_state_attributes(self) -> dict:
"raw_tomorrow": self.raw_tomorrow,
"current_price": self.current_price,
"additional_costs_current_hour": self.additional_costs,
"price_in_cents": self._use_cents
"price_in_cents": self._use_cents,
}

def _add_raw(self, data) -> list:
Expand Down

0 comments on commit 8d76be1

Please sign in to comment.