Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for EBox.
2 
3 Get data from 'My Usage Page' page: https://client.ebox.ca/myusage
4 """
5 
6 from __future__ import annotations
7 
8 from datetime import timedelta
9 import logging
10 
11 from pyebox import EboxClient
12 from pyebox.client import PyEboxError
13 import voluptuous as vol
14 
16  PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA,
17  SensorDeviceClass,
18  SensorEntity,
19  SensorEntityDescription,
20 )
21 from homeassistant.const import (
22  CONF_MONITORED_VARIABLES,
23  CONF_NAME,
24  CONF_PASSWORD,
25  CONF_USERNAME,
26  PERCENTAGE,
27  UnitOfInformation,
28  UnitOfTime,
29 )
30 from homeassistant.core import HomeAssistant
31 from homeassistant.exceptions import PlatformNotReady
32 from homeassistant.helpers.aiohttp_client import async_get_clientsession
34 from homeassistant.helpers.entity_platform import AddEntitiesCallback
35 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
36 from homeassistant.util import Throttle
37 
38 _LOGGER = logging.getLogger(__name__)
39 
40 PRICE = "CAD"
41 
42 DEFAULT_NAME = "EBox"
43 
44 REQUESTS_TIMEOUT = 15
45 SCAN_INTERVAL = timedelta(minutes=15)
46 MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=15)
47 
48 
49 SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
51  key="usage",
52  name="Usage",
53  native_unit_of_measurement=PERCENTAGE,
54  icon="mdi:percent",
55  ),
57  key="balance",
58  name="Balance",
59  native_unit_of_measurement=PRICE,
60  icon="mdi:cash",
61  ),
63  key="limit",
64  name="Data limit",
65  native_unit_of_measurement=UnitOfInformation.GIGABITS,
66  device_class=SensorDeviceClass.DATA_SIZE,
67  icon="mdi:download",
68  ),
70  key="days_left",
71  name="Days left",
72  native_unit_of_measurement=UnitOfTime.DAYS,
73  icon="mdi:calendar-today",
74  ),
76  key="before_offpeak_download",
77  name="Download before offpeak",
78  native_unit_of_measurement=UnitOfInformation.GIGABITS,
79  device_class=SensorDeviceClass.DATA_SIZE,
80  icon="mdi:download",
81  ),
83  key="before_offpeak_upload",
84  name="Upload before offpeak",
85  native_unit_of_measurement=UnitOfInformation.GIGABITS,
86  device_class=SensorDeviceClass.DATA_SIZE,
87  icon="mdi:upload",
88  ),
90  key="before_offpeak_total",
91  name="Total before offpeak",
92  native_unit_of_measurement=UnitOfInformation.GIGABITS,
93  device_class=SensorDeviceClass.DATA_SIZE,
94  icon="mdi:download",
95  ),
97  key="offpeak_download",
98  name="Offpeak download",
99  native_unit_of_measurement=UnitOfInformation.GIGABITS,
100  device_class=SensorDeviceClass.DATA_SIZE,
101  icon="mdi:download",
102  ),
104  key="offpeak_upload",
105  name="Offpeak Upload",
106  native_unit_of_measurement=UnitOfInformation.GIGABITS,
107  device_class=SensorDeviceClass.DATA_SIZE,
108  icon="mdi:upload",
109  ),
111  key="offpeak_total",
112  name="Offpeak Total",
113  native_unit_of_measurement=UnitOfInformation.GIGABITS,
114  device_class=SensorDeviceClass.DATA_SIZE,
115  icon="mdi:download",
116  ),
118  key="download",
119  name="Download",
120  native_unit_of_measurement=UnitOfInformation.GIGABITS,
121  device_class=SensorDeviceClass.DATA_SIZE,
122  icon="mdi:download",
123  ),
125  key="upload",
126  name="Upload",
127  native_unit_of_measurement=UnitOfInformation.GIGABITS,
128  device_class=SensorDeviceClass.DATA_SIZE,
129  icon="mdi:upload",
130  ),
132  key="total",
133  name="Total",
134  native_unit_of_measurement=UnitOfInformation.GIGABITS,
135  device_class=SensorDeviceClass.DATA_SIZE,
136  icon="mdi:download",
137  ),
138 )
139 
140 SENSOR_TYPE_KEYS: list[str] = [desc.key for desc in SENSOR_TYPES]
141 
142 PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(
143  {
144  vol.Required(CONF_MONITORED_VARIABLES): vol.All(
145  cv.ensure_list, [vol.In(SENSOR_TYPE_KEYS)]
146  ),
147  vol.Required(CONF_USERNAME): cv.string,
148  vol.Required(CONF_PASSWORD): cv.string,
149  vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
150  }
151 )
152 
153 
155  hass: HomeAssistant,
156  config: ConfigType,
157  async_add_entities: AddEntitiesCallback,
158  discovery_info: DiscoveryInfoType | None = None,
159 ) -> None:
160  """Set up the EBox sensor."""
161  username = config.get(CONF_USERNAME)
162  password = config.get(CONF_PASSWORD)
163 
164  httpsession = async_get_clientsession(hass)
165  ebox_data = EBoxData(username, password, httpsession)
166 
167  name = config.get(CONF_NAME)
168 
169  try:
170  await ebox_data.async_update()
171  except PyEboxError as exp:
172  _LOGGER.error("Failed login: %s", exp)
173  raise PlatformNotReady from exp
174 
175  sensors = [
176  EBoxSensor(ebox_data, description, name)
177  for description in SENSOR_TYPES
178  if description.key in config[CONF_MONITORED_VARIABLES]
179  ]
180 
181  async_add_entities(sensors, True)
182 
183 
185  """Implementation of a EBox sensor."""
186 
187  def __init__(
188  self,
189  ebox_data,
190  description: SensorEntityDescription,
191  name,
192  ) -> None:
193  """Initialize the sensor."""
194  self.entity_descriptionentity_description = description
195  self._attr_name_attr_name = f"{name} {description.name}"
196  self.ebox_dataebox_data = ebox_data
197 
198  async def async_update(self) -> None:
199  """Get the latest data from EBox and update the state."""
200  await self.ebox_dataebox_data.async_update()
201  if self.entity_descriptionentity_description.key in self.ebox_dataebox_data.data:
202  self._attr_native_value_attr_native_value = round(
203  self.ebox_dataebox_data.data[self.entity_descriptionentity_description.key], 2
204  )
205 
206 
207 class EBoxData:
208  """Get data from Ebox."""
209 
210  def __init__(self, username, password, httpsession):
211  """Initialize the data object."""
212  self.clientclient = EboxClient(username, password, REQUESTS_TIMEOUT, httpsession)
213  self.datadata = {}
214 
215  @Throttle(MIN_TIME_BETWEEN_UPDATES)
216  async def async_update(self):
217  """Get the latest data from Ebox."""
218  try:
219  await self.clientclient.fetch_data()
220  except PyEboxError as exp:
221  _LOGGER.error("Error on receive last EBox data: %s", exp)
222  return
223  # Update data
224  self.datadata = self.clientclient.get_data()
def __init__(self, username, password, httpsession)
Definition: sensor.py:210
None __init__(self, ebox_data, SensorEntityDescription description, name)
Definition: sensor.py:192
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: sensor.py:159
MetOfficeData fetch_data(datapoint.Manager connection, Site site, str mode)
Definition: helpers.py:32
aiohttp.ClientSession async_get_clientsession(HomeAssistant hass, bool verify_ssl=True, socket.AddressFamily family=socket.AF_UNSPEC, ssl_util.SSLCipherList ssl_cipher=ssl_util.SSLCipherList.PYTHON_DEFAULT)