Skip to content
Closed
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
30 changes: 13 additions & 17 deletions custom_components/nordpool/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
ISSUEURL,
DOMAIN,
EVENT_NEW_DAY,
EVENT_NEW_HOUR,
EVENT_NEW_QUARTERHOUR,
EVENT_NEW_PRICE,
_CURRENCY_LIST,
RANDOM_MINUTE,
Expand Down Expand Up @@ -73,7 +73,7 @@ async def _update(self, type_="today", dt=None, areas=None):
# Keeping this for now, but this should be changed.
for currency in self.currency:
spot = AioPrices(currency, client)
data = await spot.hourly(
data = await spot.quarterhourly(
end_date=dt, areas=self.areas if len(self.areas) > 0 else None
)
if data:
Expand Down Expand Up @@ -122,7 +122,7 @@ async def _someday(self, area: str, currency: str, day: str):

# Send a new data request after new data is updated for this first run
# This way if the user has multiple sensors they will all update
async_dispatcher_send(self._hass, EVENT_NEW_HOUR)
async_dispatcher_send(self._hass, EVENT_NEW_QUARTERHOUR)

return self._data.get(currency, {}).get(day, {}).get(area)

Expand Down Expand Up @@ -156,10 +156,10 @@ async def new_day_cb(_):

async_dispatcher_send(hass, EVENT_NEW_DAY)

async def new_hr(_):
async def new_quarterhr(_):
"""Callback to tell the sensors to update on a new hour."""
_LOGGER.debug("Called new_hr callback")
async_dispatcher_send(hass, EVENT_NEW_HOUR)
_LOGGER.debug("Called new_quarterhr callback")
async_dispatcher_send(hass, EVENT_NEW_QUARTERHOUR)

@backoff.on_exception(
backoff.constant,
Expand All @@ -178,24 +178,20 @@ async def new_data_cb(_):
async_dispatcher_send(hass, EVENT_NEW_PRICE)

# Handles futures updates
cb_update_tomorrow = async_track_time_change_in_tz(
api.listeners.append(async_track_time_change_in_tz(
hass,
new_data_cb,
hour=13,
minute=RANDOM_MINUTE,
second=RANDOM_SECOND,
tz=await dt_utils.async_get_time_zone("Europe/Stockholm"),
)

cb_new_day = async_track_time_change(
hass, new_day_cb, hour=0, minute=0, second=0
)

cb_new_hr = async_track_time_change(hass, new_hr, minute=0, second=0)
))

api.listeners.append(cb_update_tomorrow)
api.listeners.append(cb_new_hr)
api.listeners.append(cb_new_day)
api.listeners.append(async_track_time_change(hass, new_day_cb, hour=0, minute=0, second=0))
api.listeners.append(async_track_time_change(hass, new_quarterhr, minute=0, second=0))
api.listeners.append(async_track_time_change(hass, new_quarterhr, minute=15, second=0))
api.listeners.append(async_track_time_change(hass, new_quarterhr, minute=30, second=0))
api.listeners.append(async_track_time_change(hass, new_quarterhr, minute=45, second=0))

return True

Expand Down
35 changes: 16 additions & 19 deletions custom_components/nordpool/aio_price.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ async def join_result_for_correct_time(results, dt):
if start_of_day <= local <= end_of_day:
if local == local_end:
_LOGGER.info(
"Hour has the same start and end, most likly due to dst change %s exluded this hour",
"Period has the same start and end, most likly due to dst change %s exluded this hour",
val,
)
elif val["value"] in INVALID_VALUES:
Expand All @@ -95,19 +95,17 @@ def __init__(self, currency, client, timeezone=None):
# super().__init__(currency)
self.client = client
self.timeezone = timeezone
(self.HOURLY, self.DAILY, self.WEEKLY, self.MONTHLY, self.YEARLY) = (
"DayAheadPrices",
"AggregatePrices",
"AggregatePrices",
"AggregatePrices",
"AggregatePrices/GetAnnuals",
)
self.QUARTERHOURLY = "DayAheadPrices"
self.DAILY = "AggregatePrices"
self.WEEKLY = "AggregatePrices"
self.MONTHLY = "AggregatePrices"
self.YEARLY = "AggregatePrices/GetAnnuals"
self.API_URL = "https://dataportal-api.nordpoolgroup.com/api/%s"
self.currency = currency

async def _io(self, url, **kwargs):
resp = await self.client.get(url, params=kwargs)
_LOGGER.debug("requested %s %s", resp.url, kwargs)
_LOGGER.debug("requested %s %s %d", resp.url, kwargs, resp.status)

if resp.status == 204:
return None
Expand Down Expand Up @@ -143,7 +141,7 @@ def _parse_json(self, data, areas=None, data_type=None):
_LOGGER.debug("data type in _parser %s, areas %s", data_type, areas)

# Ripped from Kipe's nordpool
if data_type == self.HOURLY:
if data_type == self.QUARTERHOURLY:
data_source = ("multiAreaEntries", "entryPerArea")
elif data_type == self.DAILY:
data_source = ("multiAreaDailyAggregates", "averagePerArea")
Expand Down Expand Up @@ -217,7 +215,7 @@ async def _fetch_json(self, data_type, end_date=None, areas=None):
"""Fetch JSON from API"""
# If end_date isn't set, default to tomorrow
if data_type is None:
data_type = self.HOURLY
data_type = self.QUARTERHOURLY

if areas is None or len(areas) == 0:
raise Exception("Cannot query with empty areas")
Expand All @@ -234,12 +232,11 @@ async def _fetch_json(self, data_type, end_date=None, areas=None):
"currency": self.currency,
"market": "DayAhead",
"deliveryArea": ",".join(areas),
# This one is default for hourly..
"date": end_date.strftime("%Y-%m-%d"),
}

if data_type != self.HOURLY:
kws.pop("date")
if data_type == self.QUARTERHOURLY:
kws["date"] = end_date.strftime("%Y-%m-%d")
else:
kws["year"] = end_date.strftime("%Y")

return await self._io(self.API_URL % data_type, **kws)
Expand All @@ -254,7 +251,7 @@ async def fetch(self, data_type, end_date=None, areas=None, raw=False):
Fetch data from API.
Inputs:
- data_type
API page id, one of Prices.HOURLY, Prices.DAILY etc
API page id, one of Prices.QUARTERHOURLY, Prices.DAILY etc
- end_date
datetime to end the data fetching
defaults to tomorrow
Expand Down Expand Up @@ -283,7 +280,7 @@ async def fetch(self, data_type, end_date=None, areas=None, raw=False):
yesterday = today - timedelta(days=1)
tomorrow = today + timedelta(days=1)

if data_type == self.HOURLY:
if data_type == self.QUARTERHOURLY:
if raw:
return await self._fetch_json(data_type, today, areas)
jobs = [
Expand Down Expand Up @@ -314,11 +311,11 @@ async def _async_parse_json(self, data, areas, data_type):
None, self._parse_json, data, areas, data_type
)

async def hourly(self, end_date=None, areas=None, raw=False):
async def quarterhourly(self, end_date=None, areas=None, raw=False):
"""Helper to fetch hourly data, see Prices.fetch()"""
if areas is None:
areas = []
return await self.fetch(self.HOURLY, end_date, areas, raw=raw)
return await self.fetch(self.QUARTERHOURLY, end_date, areas, raw=raw)

async def daily(self, end_date=None, areas=None):
"""Helper to fetch daily data, see Prices.fetch()"""
Expand Down
2 changes: 1 addition & 1 deletion custom_components/nordpool/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
DOMAIN = "nordpool"
RANDOM_MINUTE = randint(10, 30)
RANDOM_SECOND = randint(0, 59)
EVENT_NEW_HOUR = "nordpool_update_hour"
EVENT_NEW_QUARTERHOUR = "nordpool_update_quarterhour"
EVENT_NEW_DAY = "nordpool_update_day"
EVENT_NEW_PRICE = "nordpool_update_new_price"
SENTINEL = object()
Expand Down
19 changes: 0 additions & 19 deletions custom_components/nordpool/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
"is_new",
"has_junk",
"extract_attrs",
"start_of",
"end_of",
"stock",
"add_junk",
]
Expand Down Expand Up @@ -54,30 +52,13 @@ def stock(d):
"""convert datetime to stocholm time."""
return d.astimezone(stockholm_tz)


def start_of(d, typ_="hour"):
if typ_ == "hour":
return d.replace(minute=0, second=0, microsecond=0)
elif typ_ == "day":
return d.replace(hour=0, minute=0, microsecond=0)


def time_in_range(start, end, x):
"""Return true if x is in the range [start, end]"""
if start <= end:
return start <= x <= end
else:
return start <= x or x <= end


def end_of(d, typ_="hour"):
"""Return end our hour"""
if typ_ == "hour":
return d.replace(minute=59, second=59, microsecond=999999)
elif typ_ == "day":
return d.replace(hour=23, minute=59, second=59, microsecond=999999)


def is_new(date=None, typ="day") -> bool:
"""Utility to check if its a new hour or day."""
# current = pendulum.now()
Expand Down
18 changes: 9 additions & 9 deletions custom_components/nordpool/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
DOMAIN,
EVENT_NEW_DAY,
EVENT_NEW_PRICE,
EVENT_NEW_HOUR,
EVENT_NEW_QUARTERHOUR,
SENTINEL,
RANDOM_MINUTE,
RANDOM_SECOND,
Expand All @@ -35,7 +35,7 @@
_CURRENTY_TO_CENTS,
_CENT_MULTIPLIER,
)
from .misc import start_of, stock
from .misc import time_in_range, stock


_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -429,7 +429,7 @@ async def _update_current_price(self) -> None:
data = await self._api.today(self._area, self._currency)
if data:
for item in self._someday(data):
if item["start"] == start_of(local_now, "hour"):
if time_in_range(item["start"], item["end"], local_now):
self._current_price = item["value"]
_LOGGER.debug(
"Updated %s _current_price %s", self.name, item["value"]
Expand All @@ -442,11 +442,11 @@ async def handle_new_day(self):
_LOGGER.debug("handle_new_day")
self._data_tomorrow = None
# update attrs for the new day
await self.handle_new_hr()
await self.handle_new_quarterhr()

async def handle_new_hr(self):
async def handle_new_quarterhr(self):
"""Update attrs for the new hour"""
_LOGGER.debug("handle_new_hr")
_LOGGER.debug("handle_new_quarterhr")
today = await self._api.today(self._area, self._currency)
if today:
self._data_today = today
Expand All @@ -473,7 +473,7 @@ async def handle_new_price(self):
if tomorrow:
self._data_tomorrow = tomorrow

await self.handle_new_hr()
await self.handle_new_quarterhr()

async def async_added_to_hass(self):
"""Connect to dispatcher listening for entity data notifications."""
Expand All @@ -484,5 +484,5 @@ async def async_added_to_hass(self):
async_dispatcher_connect(
self._api._hass, EVENT_NEW_PRICE, self.handle_new_price
)
async_dispatcher_connect(self._api._hass, EVENT_NEW_HOUR, self.handle_new_hr)
await self.handle_new_hr()
async_dispatcher_connect(self._api._hass, EVENT_NEW_QUARTERHOUR, self.handle_new_quarterhr)
await self.handle_new_quarterhr()
14 changes: 7 additions & 7 deletions custom_components/nordpool/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def validator(value):
return validator


HOURLY_SCHEMA = vol.Schema(
QUARTERHOURLY_SCHEMA = vol.Schema(
{
vol.Required("currency"): str,
vol.Required("date"): cv.date,
Expand All @@ -54,16 +54,16 @@ async def async_setup_services(hass: HomeAssistant):

client = async_get_clientsession(hass)

async def hourly(service_call: ServiceCall) -> Any:
async def quarterhourly(service_call: ServiceCall) -> Any:
sc = service_call.data
_LOGGER.debug("called hourly with %r", sc)
_LOGGER.debug("called quarterhourly with %r", sc)

# Convert the date to datetime as the rest of the code expects a datetime. We will want to keep date as it easier for ppl to use.
end_date = datetime(
year=sc["date"].year, month=sc["date"].month, day=sc["date"].day
)

value = await AioPrices(sc["currency"], client).hourly(
value = await AioPrices(sc["currency"], client).quarterhourly(
areas=sc["area"], end_date=end_date, raw=True
)

Expand Down Expand Up @@ -114,9 +114,9 @@ async def daily(service_call: ServiceCall):

hass.services.async_register(
domain="nordpool",
service="hourly",
service_func=hourly,
schema=HOURLY_SCHEMA,
service="quarterhourly",
service_func=quarterhourly,
schema=QUARTERHOURLY_SCHEMA,
supports_response=SupportsResponse.OPTIONAL,
)
hass.services.async_register(
Expand Down
6 changes: 3 additions & 3 deletions custom_components/nordpool/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ monthly:
description: "Return the prices for what price area"
example: "NO2"

hourly:
name: hourly
quarterhourly:
name: quarterhourly
description: >-
Action that gets the raw hourly price for spesific date from Nordpool
Action that gets the raw quarterhourly price for spesific date from Nordpool
fields:
currency:
description: "What currecy should the prices be returned in"
Expand Down
Loading