3 from __future__
import annotations
6 from collections
import Counter
7 from collections.abc
import Awaitable, Callable
8 from typing
import Literal, TypedDict
10 import voluptuous
as vol
15 from .const
import DOMAIN
21 @singleton.singleton(f"{DOMAIN}_manager")
23 """Return an initialized data manager."""
25 await manager.async_initialize()
30 """Dictionary describing the 'from' stat for the grid source."""
41 entity_energy_price: str |
None
42 number_energy_price: float |
None
46 """Dictionary describing the 'to' stat for the grid source."""
54 stat_compensation: str |
None
57 entity_energy_price: str |
None
58 number_energy_price: float |
None
62 """Dictionary holding the source of grid energy consumption."""
66 flow_from: list[FlowFromGridSourceType]
67 flow_to: list[FlowToGridSourceType]
69 cost_adjustment_day: float
73 """Dictionary holding the source of energy production."""
75 type: Literal[
"solar"]
78 config_entry_solar_forecast: list[str] |
None
82 """Dictionary holding the source of battery storage."""
84 type: Literal[
"battery"]
91 """Dictionary holding the source of gas consumption."""
100 stat_cost: str |
None
103 entity_energy_price: str |
None
104 number_energy_price: float |
None
108 """Dictionary holding the source of water consumption."""
110 type: Literal[
"water"]
112 stat_energy_from: str
117 stat_cost: str |
None
120 entity_energy_price: str |
None
121 number_energy_price: float |
None
134 """Dictionary holding the source of individual device consumption."""
137 stat_consumption: str
144 """Dictionary holding the energy data."""
146 energy_sources: list[SourceType]
147 device_consumption: list[DeviceConsumption]
151 """all types optional."""
155 val: FlowFromGridSourceType,
156 ) -> FlowFromGridSourceType:
157 """Ensure we use a single price source."""
159 val[
"entity_energy_price"]
is not None
160 and val[
"number_energy_price"]
is not None
162 raise vol.Invalid(
"Define either an entity or a fixed number for the price")
167 FLOW_FROM_GRID_SOURCE_SCHEMA = vol.All(
170 vol.Required(
"stat_energy_from"): str,
171 vol.Optional(
"stat_cost"): vol.Any(str,
None),
173 vol.Remove(
"entity_energy_from"): vol.Any(str,
None),
174 vol.Optional(
"entity_energy_price"): vol.Any(str,
None),
175 vol.Optional(
"number_energy_price"): vol.Any(vol.Coerce(float),
None),
178 _flow_from_ensure_single_price,
182 FLOW_TO_GRID_SOURCE_SCHEMA = vol.Schema(
184 vol.Required(
"stat_energy_to"): str,
185 vol.Optional(
"stat_compensation"): vol.Any(str,
None),
187 vol.Remove(
"entity_energy_to"): vol.Any(str,
None),
188 vol.Optional(
"entity_energy_price"): vol.Any(str,
None),
189 vol.Optional(
"number_energy_price"): vol.Any(vol.Coerce(float),
None),
195 """Generate a validator that ensures a value is only used once."""
197 def validate_uniqueness(
200 """Ensure that the user doesn't add duplicate values."""
201 counts = Counter(flow_from[key]
for flow_from
in val)
203 for value, count
in counts.items():
205 raise vol.Invalid(f
"Cannot specify {value} more than once")
209 return validate_uniqueness
212 GRID_SOURCE_SCHEMA = vol.Schema(
214 vol.Required(
"type"):
"grid",
215 vol.Required(
"flow_from"): vol.All(
216 [FLOW_FROM_GRID_SOURCE_SCHEMA],
219 vol.Required(
"flow_to"): vol.All(
220 [FLOW_TO_GRID_SOURCE_SCHEMA],
223 vol.Required(
"cost_adjustment_day"): vol.Coerce(float),
226 SOLAR_SOURCE_SCHEMA = vol.Schema(
228 vol.Required(
"type"):
"solar",
229 vol.Required(
"stat_energy_from"): str,
230 vol.Optional(
"config_entry_solar_forecast"): vol.Any([str],
None),
233 BATTERY_SOURCE_SCHEMA = vol.Schema(
235 vol.Required(
"type"):
"battery",
236 vol.Required(
"stat_energy_from"): str,
237 vol.Required(
"stat_energy_to"): str,
240 GAS_SOURCE_SCHEMA = vol.Schema(
242 vol.Required(
"type"):
"gas",
243 vol.Required(
"stat_energy_from"): str,
244 vol.Optional(
"stat_cost"): vol.Any(str,
None),
246 vol.Remove(
"entity_energy_from"): vol.Any(str,
None),
247 vol.Optional(
"entity_energy_price"): vol.Any(str,
None),
248 vol.Optional(
"number_energy_price"): vol.Any(vol.Coerce(float),
None),
251 WATER_SOURCE_SCHEMA = vol.Schema(
253 vol.Required(
"type"):
"water",
254 vol.Required(
"stat_energy_from"): str,
255 vol.Optional(
"stat_cost"): vol.Any(str,
None),
256 vol.Optional(
"entity_energy_price"): vol.Any(str,
None),
257 vol.Optional(
"number_energy_price"): vol.Any(vol.Coerce(float),
None),
263 """Validate that we don't have too many of certain types."""
264 types = Counter([val[
"type"]
for val
in value])
266 if types.get(
"grid", 0) > 1:
267 raise vol.Invalid(
"You cannot have more than 1 grid source")
272 ENERGY_SOURCE_SCHEMA = vol.All(
275 cv.key_value_schemas(
278 "grid": GRID_SOURCE_SCHEMA,
279 "solar": SOLAR_SOURCE_SCHEMA,
280 "battery": BATTERY_SOURCE_SCHEMA,
281 "gas": GAS_SOURCE_SCHEMA,
282 "water": WATER_SOURCE_SCHEMA,
290 DEVICE_CONSUMPTION_SCHEMA = vol.Schema(
292 vol.Required(
"stat_consumption"): str,
293 vol.Optional(
"name"): str,
299 """Manage the instance energy prefs."""
302 """Initialize energy manager."""
304 self.
_store_store = storage.Store[EnergyPreferences](
305 hass, STORAGE_VERSION, STORAGE_KEY
307 self.
datadata: EnergyPreferences |
None =
None
308 self._update_listeners: list[Callable[[], Awaitable]] = []
311 """Initialize the energy integration."""
316 """Return default preferences."""
318 "energy_sources": [],
319 "device_consumption": [],
323 """Update the preferences."""
324 if self.
datadata
is None:
325 data = EnergyManager.default_preferences()
327 data = self.
datadata.copy()
331 "device_consumption",
334 data[key] = update[key]
339 if not self._update_listeners:
342 await asyncio.gather(*(listener()
for listener
in self._update_listeners))
346 """Listen for data updates."""
347 self._update_listeners.append(update_listener)
EnergyPreferences default_preferences()
None async_initialize(self)
None async_listen_updates(self, Callable[[], Awaitable] update_listener)
None __init__(self, HomeAssistant hass)
None async_update(self, EnergyPreferencesUpdate update)
Callable[[list[dict]], list[dict]] _generate_unique_value_validator(str key)
EnergyManager async_get_manager(HomeAssistant hass)
list[SourceType] check_type_limits(list[SourceType] value)
FlowFromGridSourceType _flow_from_ensure_single_price(FlowFromGridSourceType val)
None async_load(HomeAssistant hass)
None async_delay_save(self, Callable[[], _T] data_func, float delay=0)