Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for Electric Kiwi sensors."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable
6 from dataclasses import dataclass
7 from datetime import datetime, timedelta
8 
9 from electrickiwi_api.model import AccountBalance, Hop
10 
12  SensorDeviceClass,
13  SensorEntity,
14  SensorEntityDescription,
15  SensorStateClass,
16 )
17 from homeassistant.config_entries import ConfigEntry
18 from homeassistant.const import CURRENCY_DOLLAR, PERCENTAGE
19 from homeassistant.core import HomeAssistant
20 from homeassistant.helpers.entity_platform import AddEntitiesCallback
21 from homeassistant.helpers.update_coordinator import CoordinatorEntity
22 from homeassistant.util import dt as dt_util
23 
24 from .const import ACCOUNT_COORDINATOR, ATTRIBUTION, DOMAIN, HOP_COORDINATOR
25 from .coordinator import (
26  ElectricKiwiAccountDataCoordinator,
27  ElectricKiwiHOPDataCoordinator,
28 )
29 
30 ATTR_EK_HOP_START = "hop_power_start"
31 ATTR_EK_HOP_END = "hop_power_end"
32 ATTR_TOTAL_RUNNING_BALANCE = "total_running_balance"
33 ATTR_TOTAL_CURRENT_BALANCE = "total_account_balance"
34 ATTR_NEXT_BILLING_DATE = "next_billing_date"
35 ATTR_HOP_PERCENTAGE = "hop_percentage"
36 
37 
38 @dataclass(frozen=True, kw_only=True)
40  """Describes Electric Kiwi sensor entity."""
41 
42  value_func: Callable[[AccountBalance], float | datetime]
43 
44 
45 ACCOUNT_SENSOR_TYPES: tuple[ElectricKiwiAccountSensorEntityDescription, ...] = (
47  key=ATTR_TOTAL_RUNNING_BALANCE,
48  translation_key="total_running_balance",
49  device_class=SensorDeviceClass.MONETARY,
50  state_class=SensorStateClass.TOTAL,
51  native_unit_of_measurement=CURRENCY_DOLLAR,
52  value_func=lambda account_balance: float(account_balance.total_running_balance),
53  ),
55  key=ATTR_TOTAL_CURRENT_BALANCE,
56  translation_key="total_current_balance",
57  device_class=SensorDeviceClass.MONETARY,
58  state_class=SensorStateClass.TOTAL,
59  native_unit_of_measurement=CURRENCY_DOLLAR,
60  value_func=lambda account_balance: float(account_balance.total_account_balance),
61  ),
63  key=ATTR_NEXT_BILLING_DATE,
64  translation_key="next_billing_date",
65  device_class=SensorDeviceClass.DATE,
66  value_func=lambda account_balance: datetime.strptime(
67  account_balance.next_billing_date, "%Y-%m-%d"
68  ),
69  ),
71  key=ATTR_HOP_PERCENTAGE,
72  translation_key="hop_power_savings",
73  native_unit_of_measurement=PERCENTAGE,
74  state_class=SensorStateClass.MEASUREMENT,
75  value_func=lambda account_balance: float(
76  account_balance.connections[0].hop_percentage
77  ),
78  ),
79 )
80 
81 
82 @dataclass(frozen=True, kw_only=True)
84  """Describes Electric Kiwi HOP sensor entity."""
85 
86  value_func: Callable[[Hop], datetime]
87 
88 
89 def _check_and_move_time(hop: Hop, time: str) -> datetime:
90  """Return the time a day forward if HOP end_time is in the past."""
91  date_time = datetime.combine(
92  dt_util.start_of_local_day(),
93  datetime.strptime(time, "%I:%M %p").time(),
94  dt_util.get_default_time_zone(),
95  )
96 
97  end_time = datetime.combine(
98  dt_util.start_of_local_day(),
99  datetime.strptime(hop.end.end_time, "%I:%M %p").time(),
100  dt_util.get_default_time_zone(),
101  )
102 
103  if end_time < dt_util.now():
104  return date_time + timedelta(days=1)
105  return date_time
106 
107 
108 HOP_SENSOR_TYPES: tuple[ElectricKiwiHOPSensorEntityDescription, ...] = (
110  key=ATTR_EK_HOP_START,
111  translation_key="hop_free_power_start",
112  device_class=SensorDeviceClass.TIMESTAMP,
113  value_func=lambda hop: _check_and_move_time(hop, hop.start.start_time),
114  ),
116  key=ATTR_EK_HOP_END,
117  translation_key="hop_free_power_end",
118  device_class=SensorDeviceClass.TIMESTAMP,
119  value_func=lambda hop: _check_and_move_time(hop, hop.end.end_time),
120  ),
121 )
122 
123 
125  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
126 ) -> None:
127  """Electric Kiwi Sensors Setup."""
128  account_coordinator: ElectricKiwiAccountDataCoordinator = hass.data[DOMAIN][
129  entry.entry_id
130  ][ACCOUNT_COORDINATOR]
131 
132  entities: list[SensorEntity] = [
134  account_coordinator,
135  description,
136  )
137  for description in ACCOUNT_SENSOR_TYPES
138  ]
139 
140  hop_coordinator: ElectricKiwiHOPDataCoordinator = hass.data[DOMAIN][entry.entry_id][
141  HOP_COORDINATOR
142  ]
143  entities.extend(
144  [
145  ElectricKiwiHOPEntity(hop_coordinator, description)
146  for description in HOP_SENSOR_TYPES
147  ]
148  )
149  async_add_entities(entities)
150 
151 
153  CoordinatorEntity[ElectricKiwiAccountDataCoordinator], SensorEntity
154 ):
155  """Entity object for Electric Kiwi sensor."""
156 
157  entity_description: ElectricKiwiAccountSensorEntityDescription
158  _attr_has_entity_name = True
159  _attr_attribution = ATTRIBUTION
160 
161  def __init__(
162  self,
163  coordinator: ElectricKiwiAccountDataCoordinator,
164  description: ElectricKiwiAccountSensorEntityDescription,
165  ) -> None:
166  """Entity object for Electric Kiwi sensor."""
167  super().__init__(coordinator)
168 
169  self._attr_unique_id_attr_unique_id = (
170  f"{coordinator._ek_api.customer_number}" # noqa: SLF001
171  f"_{coordinator._ek_api.connection_id}_{description.key}" # noqa: SLF001
172  )
173  self.entity_descriptionentity_description = description
174 
175  @property
176  def native_value(self) -> float | datetime:
177  """Return the state of the sensor."""
178  return self.entity_descriptionentity_description.value_func(self.coordinator.data)
179 
180 
182  CoordinatorEntity[ElectricKiwiHOPDataCoordinator], SensorEntity
183 ):
184  """Entity object for Electric Kiwi sensor."""
185 
186  entity_description: ElectricKiwiHOPSensorEntityDescription
187  _attr_has_entity_name = True
188  _attr_attribution = ATTRIBUTION
189 
190  def __init__(
191  self,
192  coordinator: ElectricKiwiHOPDataCoordinator,
193  description: ElectricKiwiHOPSensorEntityDescription,
194  ) -> None:
195  """Entity object for Electric Kiwi sensor."""
196  super().__init__(coordinator)
197 
198  self._attr_unique_id_attr_unique_id = (
199  f"{coordinator._ek_api.customer_number}" # noqa: SLF001
200  f"_{coordinator._ek_api.connection_id}_{description.key}" # noqa: SLF001
201  )
202  self.entity_descriptionentity_description = description
203 
204  @property
205  def native_value(self) -> datetime:
206  """Return the state of the sensor."""
207  return self.entity_descriptionentity_description.value_func(self.coordinator.data)
None __init__(self, ElectricKiwiAccountDataCoordinator coordinator, ElectricKiwiAccountSensorEntityDescription description)
Definition: sensor.py:165
None __init__(self, ElectricKiwiHOPDataCoordinator coordinator, ElectricKiwiHOPSensorEntityDescription description)
Definition: sensor.py:194
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:126
datetime _check_and_move_time(Hop hop, str time)
Definition: sensor.py:89
bool time(HomeAssistant hass, dt_time|str|None before=None, dt_time|str|None after=None, str|Container[str]|None weekday=None)
Definition: condition.py:802