1 """Support for Start.ca Bandwidth Monitor."""
3 from __future__
import annotations
6 from datetime
import timedelta
7 from http
import HTTPStatus
9 from xml.parsers.expat
import ExpatError
11 import voluptuous
as vol
15 PLATFORM_SCHEMA
as SENSOR_PLATFORM_SCHEMA,
18 SensorEntityDescription,
22 CONF_MONITORED_VARIABLES,
34 _LOGGER = logging.getLogger(__name__)
36 DEFAULT_NAME =
"Start.ca"
37 CONF_TOTAL_BANDWIDTH =
"total_bandwidth"
42 SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
46 native_unit_of_measurement=PERCENTAGE,
52 native_unit_of_measurement=UnitOfInformation.GIGABYTES,
53 device_class=SensorDeviceClass.DATA_SIZE,
59 native_unit_of_measurement=UnitOfInformation.GIGABYTES,
60 device_class=SensorDeviceClass.DATA_SIZE,
66 native_unit_of_measurement=UnitOfInformation.GIGABYTES,
67 device_class=SensorDeviceClass.DATA_SIZE,
73 native_unit_of_measurement=UnitOfInformation.GIGABYTES,
74 device_class=SensorDeviceClass.DATA_SIZE,
80 native_unit_of_measurement=UnitOfInformation.GIGABYTES,
81 device_class=SensorDeviceClass.DATA_SIZE,
86 name=
"Grace Download",
87 native_unit_of_measurement=UnitOfInformation.GIGABYTES,
88 device_class=SensorDeviceClass.DATA_SIZE,
94 native_unit_of_measurement=UnitOfInformation.GIGABYTES,
95 device_class=SensorDeviceClass.DATA_SIZE,
101 native_unit_of_measurement=UnitOfInformation.GIGABYTES,
102 device_class=SensorDeviceClass.DATA_SIZE,
106 key=
"total_download",
107 name=
"Total Download",
108 native_unit_of_measurement=UnitOfInformation.GIGABYTES,
109 device_class=SensorDeviceClass.DATA_SIZE,
115 native_unit_of_measurement=UnitOfInformation.GIGABYTES,
116 device_class=SensorDeviceClass.DATA_SIZE,
120 key=
"used_remaining",
122 native_unit_of_measurement=UnitOfInformation.GIGABYTES,
123 device_class=SensorDeviceClass.DATA_SIZE,
128 SENSOR_KEYS: list[str] = [desc.key
for desc
in SENSOR_TYPES]
130 PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(
132 vol.Required(CONF_MONITORED_VARIABLES): vol.All(
133 cv.ensure_list, [vol.In(SENSOR_KEYS)]
135 vol.Required(CONF_API_KEY): cv.string,
136 vol.Required(CONF_TOTAL_BANDWIDTH): cv.positive_int,
137 vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
145 async_add_entities: AddEntitiesCallback,
146 discovery_info: DiscoveryInfoType |
None =
None,
148 """Set up the sensor platform."""
150 apikey = config[CONF_API_KEY]
151 bandwidthcap = config[CONF_TOTAL_BANDWIDTH]
153 ts_data =
StartcaData(hass.loop, websession, apikey, bandwidthcap)
154 ret = await ts_data.async_update()
156 _LOGGER.error(
"Invalid Start.ca API key: %s", apikey)
159 name = config[CONF_NAME]
160 monitored_variables = config[CONF_MONITORED_VARIABLES]
161 if bandwidthcap <= 0:
162 monitored_variables =
list(
164 lambda itm: itm
not in {
"limit",
"usage",
"used_remaining"},
170 for description
in SENSOR_TYPES
171 if description.key
in monitored_variables
177 """Representation of Start.ca Bandwidth sensor."""
179 def __init__(self, startcadata, name, description: SensorEntityDescription) ->
None:
180 """Initialize the sensor."""
187 """Get the latest data from Start.ca and update the state."""
190 if sensor_type
in self.
startcadatastartcadata.data:
195 """Get data from Start.ca API."""
197 def __init__(self, loop, websession, api_key, bandwidth_cap):
198 """Initialize the data object."""
210 """Convert from bytes to GB.
212 :param value: The value in bytes to convert to GB.
213 :return: Converted GB value
215 return float(value) * 10**-9
217 @Throttle(MIN_TIME_BETWEEN_UPDATES)
219 """Get the Start.ca bandwidth data from the web service."""
220 _LOGGER.debug(
"Updating Start.ca usage data")
221 url = f
"https://www.start.ca/support/usage/api?key={self.api_key}"
222 async
with asyncio.timeout(REQUEST_TIMEOUT):
224 if req.status != HTTPStatus.OK:
225 _LOGGER.error(
"Request failed with status: %u", req.status)
228 data = await req.text()
230 xml_data = xmltodict.parse(data)
234 used_dl = self.
bytes_to_gbbytes_to_gb(xml_data[
"usage"][
"used"][
"download"])
235 used_ul = self.
bytes_to_gbbytes_to_gb(xml_data[
"usage"][
"used"][
"upload"])
236 grace_dl = self.
bytes_to_gbbytes_to_gb(xml_data[
"usage"][
"grace"][
"download"])
237 grace_ul = self.
bytes_to_gbbytes_to_gb(xml_data[
"usage"][
"grace"][
"upload"])
238 total_dl = self.
bytes_to_gbbytes_to_gb(xml_data[
"usage"][
"total"][
"download"])
239 total_ul = self.
bytes_to_gbbytes_to_gb(xml_data[
"usage"][
"total"][
"upload"])
243 self.
datadata[
"used_remaining"] = self.
datadata[
"limit"] - used_dl
244 self.
datadata[
"usage_gb"] = used_dl
245 self.
datadata[
"used_download"] = used_dl
246 self.
datadata[
"used_upload"] = used_ul
247 self.
datadata[
"used_total"] = used_dl + used_ul
248 self.
datadata[
"grace_download"] = grace_dl
249 self.
datadata[
"grace_upload"] = grace_ul
250 self.
datadata[
"grace_total"] = grace_dl + grace_ul
251 self.
datadata[
"total_download"] = total_dl
252 self.
datadata[
"total_upload"] = total_ul
def __init__(self, loop, websession, api_key, bandwidth_cap)
None __init__(self, startcadata, name, SensorEntityDescription description)
web.Response get(self, web.Request request, str config_key)
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
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)