Home Assistant Unofficial Reference 2024.12.1
services.py
Go to the documentation of this file.
1 """Services for easyEnergy integration."""
2 
3 from __future__ import annotations
4 
5 from datetime import date, datetime
6 from enum import Enum
7 from functools import partial
8 from typing import Final
9 
10 from easyenergy import Electricity, Gas, VatOption
11 import voluptuous as vol
12 
13 from homeassistant.config_entries import ConfigEntry, ConfigEntryState
14 from homeassistant.core import (
15  HomeAssistant,
16  ServiceCall,
17  ServiceResponse,
18  SupportsResponse,
19  callback,
20 )
21 from homeassistant.exceptions import ServiceValidationError
22 from homeassistant.helpers import selector
23 from homeassistant.util import dt as dt_util
24 
25 from .const import DOMAIN
26 from .coordinator import EasyEnergyDataUpdateCoordinator
27 
28 ATTR_CONFIG_ENTRY: Final = "config_entry"
29 ATTR_START: Final = "start"
30 ATTR_END: Final = "end"
31 ATTR_INCL_VAT: Final = "incl_vat"
32 
33 GAS_SERVICE_NAME: Final = "get_gas_prices"
34 ENERGY_USAGE_SERVICE_NAME: Final = "get_energy_usage_prices"
35 ENERGY_RETURN_SERVICE_NAME: Final = "get_energy_return_prices"
36 SERVICE_SCHEMA: Final = vol.Schema(
37  {
38  vol.Required(ATTR_CONFIG_ENTRY): selector.ConfigEntrySelector(
39  {
40  "integration": DOMAIN,
41  }
42  ),
43  vol.Required(ATTR_INCL_VAT): bool,
44  vol.Optional(ATTR_START): str,
45  vol.Optional(ATTR_END): str,
46  }
47 )
48 
49 
50 class PriceType(str, Enum):
51  """Type of price."""
52 
53  ENERGY_USAGE = "energy_usage"
54  ENERGY_RETURN = "energy_return"
55  GAS = "gas"
56 
57 
58 def __get_date(date_input: str | None) -> date | datetime:
59  """Get date."""
60  if not date_input:
61  return dt_util.now().date()
62 
63  if value := dt_util.parse_datetime(date_input):
64  return value
65 
67  "Invalid datetime provided.",
68  translation_domain=DOMAIN,
69  translation_key="invalid_date",
70  translation_placeholders={
71  "date": date_input,
72  },
73  )
74 
75 
76 def __serialize_prices(prices: list[dict[str, float | datetime]]) -> ServiceResponse:
77  """Serialize prices to service response."""
78  return {
79  "prices": [
80  {
81  key: str(value) if isinstance(value, datetime) else value
82  for key, value in timestamp_price.items()
83  }
84  for timestamp_price in prices
85  ]
86  }
87 
88 
90  hass: HomeAssistant, call: ServiceCall
91 ) -> EasyEnergyDataUpdateCoordinator:
92  """Get the coordinator from the entry."""
93  entry_id: str = call.data[ATTR_CONFIG_ENTRY]
94  entry: ConfigEntry | None = hass.config_entries.async_get_entry(entry_id)
95 
96  if not entry:
98  translation_domain=DOMAIN,
99  translation_key="invalid_config_entry",
100  translation_placeholders={
101  "config_entry": entry_id,
102  },
103  )
104  if entry.state != ConfigEntryState.LOADED:
106  translation_domain=DOMAIN,
107  translation_key="unloaded_config_entry",
108  translation_placeholders={
109  "config_entry": entry.title,
110  },
111  )
112 
113  coordinator: EasyEnergyDataUpdateCoordinator = hass.data[DOMAIN][entry_id]
114  return coordinator
115 
116 
117 async def __get_prices(
118  call: ServiceCall,
119  *,
120  hass: HomeAssistant,
121  price_type: PriceType,
122 ) -> ServiceResponse:
123  """Get prices from easyEnergy."""
124  coordinator = __get_coordinator(hass, call)
125 
126  start = __get_date(call.data.get(ATTR_START))
127  end = __get_date(call.data.get(ATTR_END))
128 
129  vat = VatOption.INCLUDE
130  if call.data.get(ATTR_INCL_VAT) is False:
131  vat = VatOption.EXCLUDE
132 
133  data: Electricity | Gas
134 
135  if price_type == PriceType.GAS:
136  data = await coordinator.easyenergy.gas_prices(
137  start_date=start,
138  end_date=end,
139  vat=vat,
140  )
141  return __serialize_prices(data.timestamp_prices)
142  data = await coordinator.easyenergy.energy_prices(
143  start_date=start,
144  end_date=end,
145  vat=vat,
146  )
147 
148  if price_type == PriceType.ENERGY_USAGE:
149  return __serialize_prices(data.timestamp_usage_prices)
150  return __serialize_prices(data.timestamp_return_prices)
151 
152 
153 @callback
154 def async_setup_services(hass: HomeAssistant) -> None:
155  """Set up services for easyEnergy integration."""
156 
157  hass.services.async_register(
158  DOMAIN,
159  GAS_SERVICE_NAME,
160  partial(__get_prices, hass=hass, price_type=PriceType.GAS),
161  schema=SERVICE_SCHEMA,
162  supports_response=SupportsResponse.ONLY,
163  )
164  hass.services.async_register(
165  DOMAIN,
166  ENERGY_USAGE_SERVICE_NAME,
167  partial(__get_prices, hass=hass, price_type=PriceType.ENERGY_USAGE),
168  schema=SERVICE_SCHEMA,
169  supports_response=SupportsResponse.ONLY,
170  )
171  hass.services.async_register(
172  DOMAIN,
173  ENERGY_RETURN_SERVICE_NAME,
174  partial(__get_prices, hass=hass, price_type=PriceType.ENERGY_RETURN),
175  schema=SERVICE_SCHEMA,
176  supports_response=SupportsResponse.ONLY,
177  )
ServiceResponse __get_prices(ServiceCall call, *HomeAssistant hass, PriceType price_type)
Definition: services.py:122
EasyEnergyDataUpdateCoordinator __get_coordinator(HomeAssistant hass, ServiceCall call)
Definition: services.py:91
None async_setup_services(HomeAssistant hass)
Definition: services.py:154
date|datetime __get_date(str|None date_input)
Definition: services.py:58
ServiceResponse __serialize_prices(list[dict[str, float|datetime]] prices)
Definition: services.py:76