1 """Amber Electric Coordinator."""
3 from __future__
import annotations
5 from datetime
import timedelta
9 from amberelectric.models.actual_interval
import ActualInterval
10 from amberelectric.models.channel
import ChannelType
11 from amberelectric.models.current_interval
import CurrentInterval
12 from amberelectric.models.forecast_interval
import ForecastInterval
13 from amberelectric.models.price_descriptor
import PriceDescriptor
14 from amberelectric.rest
import ApiException
19 from .const
import LOGGER
22 def is_current(interval: ActualInterval | CurrentInterval | ForecastInterval) -> bool:
23 """Return true if the supplied interval is a CurrentInterval."""
24 return isinstance(interval, CurrentInterval)
27 def is_forecast(interval: ActualInterval | CurrentInterval | ForecastInterval) -> bool:
28 """Return true if the supplied interval is a ForecastInterval."""
29 return isinstance(interval, ForecastInterval)
32 def is_general(interval: ActualInterval | CurrentInterval | ForecastInterval) -> bool:
33 """Return true if the supplied interval is on the general channel."""
34 return interval.channel_type == ChannelType.GENERAL
38 interval: ActualInterval | CurrentInterval | ForecastInterval,
40 """Return true if the supplied interval is on the controlled load channel."""
41 return interval.channel_type == ChannelType.CONTROLLEDLOAD
44 def is_feed_in(interval: ActualInterval | CurrentInterval | ForecastInterval) -> bool:
45 """Return true if the supplied interval is on the feed in channel."""
46 return interval.channel_type == ChannelType.FEEDIN
50 """Return the snake case versions of descriptor names. Returns None if the name is not recognized."""
51 if descriptor
is None:
53 if descriptor.value ==
"spike":
55 if descriptor.value ==
"high":
57 if descriptor.value ==
"neutral":
59 if descriptor.value ==
"low":
61 if descriptor.value ==
"veryLow":
63 if descriptor.value ==
"extremelyLow":
64 return "extremely_low"
65 if descriptor.value ==
"negative":
71 """AmberUpdateCoordinator - In charge of downloading the data for a site, which all the sensors read."""
74 self, hass: HomeAssistant, api: amberelectric.AmberApi, site_id: str
76 """Initialise the data service."""
87 """Update callback."""
89 result: dict[str, dict[str, Any]] = {
96 data = self.
_api_api.get_current_prices(self.
site_idsite_id, next=48)
97 intervals = [interval.actual_instance
for interval
in data]
98 except ApiException
as api_exception:
99 raise UpdateFailed(
"Missing price data, skipping update")
from api_exception
101 current = [interval
for interval
in intervals
if is_current(interval)]
102 forecasts = [interval
for interval
in intervals
if is_forecast(interval)]
103 general = [interval
for interval
in current
if is_general(interval)]
105 if len(general) == 0:
108 result[
"current"][
"general"] = general[0]
110 result[
"forecasts"][
"general"] = [
111 interval
for interval
in forecasts
if is_general(interval)
113 result[
"grid"][
"renewables"] = round(general[0].renewables)
114 result[
"grid"][
"price_spike"] = general[0].spike_status.value
115 tariff_information = general[0].tariff_information
116 if tariff_information:
117 result[
"grid"][
"demand_window"] = tariff_information.demand_window
123 result[
"current"][
"controlled_load"] = controlled_load[0]
125 controlled_load[0].descriptor
127 result[
"forecasts"][
"controlled_load"] = [
131 feed_in = [interval
for interval
in current
if is_feed_in(interval)]
133 result[
"current"][
"feed_in"] = feed_in[0]
135 feed_in[0].descriptor
137 result[
"forecasts"][
"feed_in"] = [
138 interval
for interval
in forecasts
if is_feed_in(interval)
141 LOGGER.debug(
"Fetched new Amber data: %s", intervals)
145 """Async update wrapper."""
None __init__(self, HomeAssistant hass, amberelectric.AmberApi api, str site_id)
dict[str, dict[str, Any]] update_price_data(self)
dict[str, Any] _async_update_data(self)
bool is_forecast(ActualInterval|CurrentInterval|ForecastInterval interval)
str|None normalize_descriptor(PriceDescriptor|None descriptor)
bool is_controlled_load(ActualInterval|CurrentInterval|ForecastInterval interval)
bool is_feed_in(ActualInterval|CurrentInterval|ForecastInterval interval)
bool is_current(ActualInterval|CurrentInterval|ForecastInterval interval)
bool is_general(ActualInterval|CurrentInterval|ForecastInterval interval)