Skip to content
This repository has been archived by the owner on Mar 6, 2022. It is now read-only.

Commit

Permalink
Fixes #1
Browse files Browse the repository at this point in the history
  • Loading branch information
fbjerggaard committed Jan 3, 2022
1 parent 92aabbb commit 5bb85dc
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 21 deletions.
106 changes: 86 additions & 20 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,117 @@
"""The Barry App integration."""
import logging
from random import randint
from datetime import datetime, timedelta
from pytz import timezone

from pybarry import Barry

import voluptuous as vol

from homeassistant import config_entries
from homeassistant.const import CONF_ACCESS_TOKEN

from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.core import Config,HomeAssistant
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.event import async_call_later, async_track_time_change

from .const import DOMAIN, PRICE_CODE
from .events import async_track_time_change_in_tz

PLATFORMS = ["sensor"]
EVENT_NEW_DATA = "barry_update"
RANDOM_MINUTE = randint(0, 10)
RANDOM_SECOND = randint(0, 59)

_LOGGER = logging.getLogger(__name__)

CONFIG_SCHEMA = vol.Schema({DOMAIN: vol.Schema({})}, extra=vol.ALLOW_EXTRA)

async def async_setup(hass, config):
"""Set up the Barry component."""
class BarryData:
def __init__(self, hass: HomeAssistant):
self._hass = hass
self.listeners = []
self.barry_connection = None

if DOMAIN not in config:
return True
async def _dry_setup(hass, entry) -> bool:
"""Setup"""
_LOGGER.debug("Running _dry_setup")

hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data=config[DOMAIN],
if DOMAIN not in hass.data:
_LOGGER.debug("Setting up integration: %s", entry)
api = BarryData(hass)

api.barry_connection = Barry(
access_token=entry.data[CONF_ACCESS_TOKEN],
)
)

hass.data[DOMAIN] = api

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

async def new_data_cb(n):
"""Callback to fetch new data for tomorrows prices at 1300ish CET
and notify any sensors, about the new data
"""
_LOGGER.debug("Called new_data_cb")
async_dispatcher_send(hass, EVENT_NEW_DATA)

cb_update_tomorrow = async_track_time_change_in_tz(
hass,
new_data_cb,
hour=13,
minute=RANDOM_MINUTE,
second=RANDOM_SECOND,
tz=timezone("Europe/Stockholm"),
)

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)

return True


async def async_setup_entry(hass, entry):
async def async_setup(hass: HomeAssistant, config: ConfigEntry):
# """Set up the Barry component."""
# #hass.data[DOMAIN] = {}
# #return await _dry_setup(hass, entry.data)
return True


async def async_setup_entry(hass, entry) -> bool:
"""Set up a config entry."""
res = await _dry_setup(hass, entry)

barry_connection = Barry(
access_token=entry.data[CONF_ACCESS_TOKEN],
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, "sensor")
)
hass.data[DOMAIN] = barry_connection
hass.data[PRICE_CODE] = entry.data[PRICE_CODE]

hass.config_entries.async_setup_platforms(entry, PLATFORMS)

return True
return res


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
unload_ok = await hass.config_entries.async_forward_entry_unload(entry, "sensor")

if unload_ok:
for unsub in hass.data[DOMAIN].listeners:
unsub()
hass.data.pop(DOMAIN)

return True

return False


async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Reload config entry."""
await async_unload_entry(hass, entry)
await async_setup_entry(hass, entry)
91 changes: 91 additions & 0 deletions events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from datetime import datetime, timedelta
from typing import Any, Callable, Optional

from homeassistant.const import ATTR_NOW, EVENT_TIME_CHANGED
from homeassistant.core import CALLBACK_TYPE, Event, HomeAssistant, callback
from homeassistant.loader import bind_hass
from homeassistant.util import dt as dt_util
from pytz import timezone


def stock(d):
"""convert datetime to Copenhagen time."""
return d.astimezone(timezone("Europe/Copenhagen"))


@callback
@bind_hass
def async_track_utc_time_change(
hass: HomeAssistant,
action: Callable[..., None],
hour: Optional[Any] = None,
minute: Optional[Any] = None,
second: Optional[Any] = None,
tz: Optional[Any] = None,
) -> CALLBACK_TYPE:
"""Add a listener that will fire if time matches a pattern."""
# We do not have to wrap the function with time pattern matching logic
# if no pattern given
if all(val is None for val in (hour, minute, second)):

@callback
def time_change_listener(event: Event) -> None:
"""Fire every time event that comes in."""
hass.async_run_job(action, event.data[ATTR_NOW])

return hass.bus.async_listen(EVENT_TIME_CHANGED, time_change_listener)

matching_seconds = dt_util.parse_time_expression(second, 0, 59)
matching_minutes = dt_util.parse_time_expression(minute, 0, 59)
matching_hours = dt_util.parse_time_expression(hour, 0, 23)

next_time = None

def calculate_next(now: datetime) -> None:
"""Calculate and set the next time the trigger should fire."""
nonlocal next_time

localized_now = now.astimezone(tz) if tz else now
next_time = dt_util.find_next_time_expression_time(
localized_now, matching_seconds, matching_minutes, matching_hours
)

# Make sure rolling back the clock doesn't prevent the timer from
# triggering.
last_now: Optional[datetime] = None

@callback
def pattern_time_change_listener(event: Event) -> None:
"""Listen for matching time_changed events."""
nonlocal next_time, last_now

now = event.data[ATTR_NOW]

if last_now is None or now < last_now:
# Time rolled back or next time not yet calculated
calculate_next(now)

last_now = now

if next_time <= now:
hass.async_run_job(action, now.astimezone(tz) if tz else now)
calculate_next(now + timedelta(seconds=1))

# We can't use async_track_point_in_utc_time here because it would
# break in the case that the system time abruptly jumps backwards.
# Our custom last_now logic takes care of resolving that scenario.
return hass.bus.async_listen(EVENT_TIME_CHANGED, pattern_time_change_listener)


@callback
@bind_hass
def async_track_time_change_in_tz(
hass: HomeAssistant,
action: Callable[..., None],
hour: Optional[Any] = None,
minute: Optional[Any] = None,
second: Optional[Any] = None,
tz: Optional[Any] = None,
) -> CALLBACK_TYPE:
"""Add a listener that will fire if UTC time matches a pattern."""
return async_track_utc_time_change(hass, action, hour, minute, second, tz)
3 changes: 2 additions & 1 deletion sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def _dry_setup(hass, config, add_devices, discovery_info=None):
"""Setup platform"""
_LOGGER.debug("Dumping config %r", config)
_LOGGER.debug("Dumping hass data", hass.data)
barry_connection = hass.data[DOMAIN]
barry_connection = hass.data[DOMAIN].barry_connection
price_code = config[PRICE_CODE]
meter_id = config[MPID]
sensor = BarrySensor(
Expand Down Expand Up @@ -88,6 +88,7 @@ def current_spot_price(self) -> float:

def _update_current_price(self) -> None:
_LOGGER.debug("Updating current price")
_LOGGER.debug("barry_home: %s", self._barry_home)
self._current_total_price = self._barry_home.update_total_price(self._meter_id)[0]
self._current_spot_price = self._barry_home.update_spot_price(self._price_code)[0]
_LOGGER.debug("Updated %s with new prices: %s/%s", self.name, self._current_total_price, self._current_spot_price)
Expand Down

0 comments on commit 5bb85dc

Please sign in to comment.