core/homeassistant/components/ondilo_ico/sensor.py

194 lines
5.4 KiB
Python

"""Platform for sensor integration."""
from __future__ import annotations
from datetime import timedelta
import logging
from ondilo import OndiloError
from homeassistant.components.sensor import (
STATE_CLASS_MEASUREMENT,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.const import (
CONCENTRATION_PARTS_PER_MILLION,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_SIGNAL_STRENGTH,
DEVICE_CLASS_TEMPERATURE,
ELECTRIC_POTENTIAL_MILLIVOLT,
PERCENTAGE,
TEMP_CELSIUS,
)
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
UpdateFailed,
)
from .const import DOMAIN
SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
SensorEntityDescription(
key="temperature",
name="Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
icon=None,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key="orp",
name="Oxydo Reduction Potential",
native_unit_of_measurement=ELECTRIC_POTENTIAL_MILLIVOLT,
icon="mdi:pool",
device_class=None,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key="ph",
name="pH",
native_unit_of_measurement=None,
icon="mdi:pool",
device_class=None,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key="tds",
name="TDS",
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
icon="mdi:pool",
device_class=None,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key="battery",
name="Battery",
native_unit_of_measurement=PERCENTAGE,
icon=None,
device_class=DEVICE_CLASS_BATTERY,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key="rssi",
name="RSSI",
native_unit_of_measurement=PERCENTAGE,
icon=None,
device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
state_class=STATE_CLASS_MEASUREMENT,
),
SensorEntityDescription(
key="salt",
name="Salt",
native_unit_of_measurement="mg/L",
icon="mdi:pool",
device_class=None,
state_class=STATE_CLASS_MEASUREMENT,
),
)
SCAN_INTERVAL = timedelta(minutes=5)
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, entry, async_add_entities):
"""Set up the Ondilo ICO sensors."""
api = hass.data[DOMAIN][entry.entry_id]
async def async_update_data():
"""Fetch data from API endpoint.
This is the place to pre-process the data to lookup tables
so entities can quickly look up their data.
"""
try:
return await hass.async_add_executor_job(api.get_all_pools_data)
except OndiloError as err:
raise UpdateFailed(f"Error communicating with API: {err}") from err
coordinator = DataUpdateCoordinator(
hass,
_LOGGER,
# Name of the data. For logging purposes.
name="sensor",
update_method=async_update_data,
# Polling interval. Will only be polled if there are subscribers.
update_interval=SCAN_INTERVAL,
)
# Fetch initial data so we have data when entities subscribe
await coordinator.async_refresh()
entities = []
for poolidx, pool in enumerate(coordinator.data):
entities.extend(
[
OndiloICO(coordinator, poolidx, description)
for sensor in pool["sensors"]
for description in SENSOR_TYPES
if description.key == sensor["data_type"]
]
)
async_add_entities(entities)
class OndiloICO(CoordinatorEntity, SensorEntity):
"""Representation of a Sensor."""
def __init__(
self,
coordinator: DataUpdateCoordinator,
poolidx: int,
description: SensorEntityDescription,
) -> None:
"""Initialize sensor entity with data from coordinator."""
super().__init__(coordinator)
self.entity_description = description
self._poolid = self.coordinator.data[poolidx]["id"]
pooldata = self._pooldata()
self._attr_unique_id = f"{pooldata['ICO']['serial_number']}-{description.key}"
self._device_name = pooldata["name"]
self._attr_name = f"{self._device_name} {description.name}"
def _pooldata(self):
"""Get pool data dict."""
return next(
(pool for pool in self.coordinator.data if pool["id"] == self._poolid),
None,
)
def _devdata(self):
"""Get device data dict."""
return next(
(
data_type
for data_type in self._pooldata()["sensors"]
if data_type["data_type"] == self.entity_description.key
),
None,
)
@property
def native_value(self):
"""Last value of the sensor."""
return self._devdata()["value"]
@property
def device_info(self) -> DeviceInfo:
"""Return the device info for the sensor."""
pooldata = self._pooldata()
return DeviceInfo(
identifiers={(DOMAIN, pooldata["ICO"]["serial_number"])},
manufacturer="Ondilo",
model="ICO",
name=self._device_name,
sw_version=pooldata["ICO"]["sw_version"],
)