diff --git a/homeassistant/components/flipr/__init__.py b/homeassistant/components/flipr/__init__.py index 66ea93484f7..f1320dafda1 100644 --- a/homeassistant/components/flipr/__init__.py +++ b/homeassistant/components/flipr/__init__.py @@ -5,21 +5,22 @@ import logging from flipr_api import FliprAPIRestClient from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_EMAIL, CONF_PASSWORD +from homeassistant.const import ATTR_ATTRIBUTION, CONF_EMAIL, CONF_PASSWORD from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity import EntityDescription from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, DataUpdateCoordinator, ) -from .const import CONF_FLIPR_ID, DOMAIN, MANUFACTURER, NAME +from .const import ATTRIBUTION, CONF_FLIPR_ID, DOMAIN, MANUFACTURER, NAME _LOGGER = logging.getLogger(__name__) SCAN_INTERVAL = timedelta(minutes=60) -PLATFORMS = ["sensor"] +PLATFORMS = ["sensor", "binary_sensor"] async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: @@ -75,14 +76,22 @@ class FliprDataUpdateCoordinator(DataUpdateCoordinator): class FliprEntity(CoordinatorEntity): """Implements a common class elements representing the Flipr component.""" - def __init__(self, coordinator, flipr_id, info_type): + _attr_extra_state_attributes = {ATTR_ATTRIBUTION: ATTRIBUTION} + + def __init__( + self, coordinator: DataUpdateCoordinator, description: EntityDescription + ) -> None: """Initialize Flipr sensor.""" super().__init__(coordinator) - self._attr_unique_id = f"{flipr_id}-{info_type}" - self._attr_device_info = { - "identifiers": {(DOMAIN, flipr_id)}, - "name": NAME, - "manufacturer": MANUFACTURER, - } - self.info_type = info_type - self.flipr_id = flipr_id + self.entity_description = description + if coordinator.config_entry: + flipr_id = coordinator.config_entry.data[CONF_FLIPR_ID] + self._attr_unique_id = f"{flipr_id}-{description.key}" + + self._attr_device_info = { + "identifiers": {(DOMAIN, flipr_id)}, + "name": NAME, + "manufacturer": MANUFACTURER, + } + + self._attr_name = f"Flipr {flipr_id} {description.name}" diff --git a/homeassistant/components/flipr/binary_sensor.py b/homeassistant/components/flipr/binary_sensor.py new file mode 100644 index 00000000000..400c1562088 --- /dev/null +++ b/homeassistant/components/flipr/binary_sensor.py @@ -0,0 +1,46 @@ +"""Support for Flipr binary sensors.""" +from __future__ import annotations + +from homeassistant.components.binary_sensor import ( + DEVICE_CLASS_PROBLEM, + BinarySensorEntity, + BinarySensorEntityDescription, +) + +from . import FliprEntity +from .const import DOMAIN + +BINARY_SENSORS_TYPES: tuple[BinarySensorEntityDescription, ...] = ( + BinarySensorEntityDescription( + key="ph_status", + name="PH Status", + device_class=DEVICE_CLASS_PROBLEM, + ), + BinarySensorEntityDescription( + key="chlorine_status", + name="Chlorine Status", + device_class=DEVICE_CLASS_PROBLEM, + ), +) + + +async def async_setup_entry(hass, config_entry, async_add_entities): + """Defer sensor setup of flipr binary sensors.""" + coordinator = hass.data[DOMAIN][config_entry.entry_id] + + async_add_entities( + FliprBinarySensor(coordinator, description) + for description in BINARY_SENSORS_TYPES + ) + + +class FliprBinarySensor(FliprEntity, BinarySensorEntity): + """Representation of Flipr binary sensors.""" + + @property + def is_on(self): + """Return true if the binary sensor is on in case of a Problem is detected.""" + return ( + self.coordinator.data[self.entity_description.key] == "TooLow" + or self.coordinator.data[self.entity_description.key] == "TooHigh" + ) diff --git a/homeassistant/components/flipr/sensor.py b/homeassistant/components/flipr/sensor.py index 0d986114659..6466c58fae2 100644 --- a/homeassistant/components/flipr/sensor.py +++ b/homeassistant/components/flipr/sensor.py @@ -1,9 +1,10 @@ """Sensor platform for the Flipr's pool_sensor.""" +from __future__ import annotations + from datetime import datetime -from homeassistant.components.sensor import SensorEntity +from homeassistant.components.sensor import SensorEntity, SensorEntityDescription from homeassistant.const import ( - ATTR_ATTRIBUTION, DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_TIMESTAMP, ELECTRIC_POTENTIAL_MILLIVOLT, @@ -11,78 +12,55 @@ from homeassistant.const import ( ) from . import FliprEntity -from .const import ATTRIBUTION, CONF_FLIPR_ID, DOMAIN +from .const import DOMAIN -SENSORS = { - "chlorine": { - "unit": ELECTRIC_POTENTIAL_MILLIVOLT, - "icon": "mdi:pool", - "name": "Chlorine", - "device_class": None, - }, - "ph": {"unit": None, "icon": "mdi:pool", "name": "pH", "device_class": None}, - "temperature": { - "unit": TEMP_CELSIUS, - "icon": None, - "name": "Water Temp", - "device_class": DEVICE_CLASS_TEMPERATURE, - }, - "date_time": { - "unit": None, - "icon": None, - "name": "Last Measured", - "device_class": DEVICE_CLASS_TIMESTAMP, - }, - "red_ox": { - "unit": ELECTRIC_POTENTIAL_MILLIVOLT, - "icon": "mdi:pool", - "name": "Red OX", - "device_class": None, - }, -} +SENSOR_TYPES: tuple[SensorEntityDescription, ...] = ( + SensorEntityDescription( + key="chlorine", + name="Chlorine", + native_unit_of_measurement=ELECTRIC_POTENTIAL_MILLIVOLT, + icon="mdi:pool", + ), + SensorEntityDescription( + key="ph", + name="pH", + icon="mdi:pool", + ), + SensorEntityDescription( + key="temperature", + name="Water Temp", + device_class=DEVICE_CLASS_TEMPERATURE, + native_unit_of_measurement=TEMP_CELSIUS, + ), + SensorEntityDescription( + key="date_time", + name="Last Measured", + device_class=DEVICE_CLASS_TIMESTAMP, + ), + SensorEntityDescription( + key="red_ox", + name="Red OX", + native_unit_of_measurement=ELECTRIC_POTENTIAL_MILLIVOLT, + icon="mdi:pool", + ), +) async def async_setup_entry(hass, config_entry, async_add_entities): """Defer sensor setup to the shared sensor module.""" - flipr_id = config_entry.data[CONF_FLIPR_ID] coordinator = hass.data[DOMAIN][config_entry.entry_id] - sensors_list = [] - for sensor in SENSORS: - sensors_list.append(FliprSensor(coordinator, flipr_id, sensor)) - - async_add_entities(sensors_list, True) + sensors = [FliprSensor(coordinator, description) for description in SENSOR_TYPES] + async_add_entities(sensors, True) class FliprSensor(FliprEntity, SensorEntity): """Sensor representing FliprSensor data.""" - _attr_extra_state_attributes = {ATTR_ATTRIBUTION: ATTRIBUTION} - - @property - def name(self): - """Return the name of the particular component.""" - return f"Flipr {self.flipr_id} {SENSORS[self.info_type]['name']}" - @property def native_value(self): """State of the sensor.""" - state = self.coordinator.data[self.info_type] + state = self.coordinator.data[self.entity_description.key] if isinstance(state, datetime): return state.isoformat() return state - - @property - def device_class(self): - """Return the device class.""" - return SENSORS[self.info_type]["device_class"] - - @property - def icon(self): - """Return the icon.""" - return SENSORS[self.info_type]["icon"] - - @property - def native_unit_of_measurement(self): - """Return unit of measurement.""" - return SENSORS[self.info_type]["unit"] diff --git a/tests/components/flipr/test_sensors.py b/tests/components/flipr/test_sensors.py index 244ec61507c..7c4855dae0a 100644 --- a/tests/components/flipr/test_sensors.py +++ b/tests/components/flipr/test_sensors.py @@ -3,7 +3,6 @@ from datetime import datetime from unittest.mock import patch from homeassistant.components.flipr.const import CONF_FLIPR_ID, DOMAIN -from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.const import ( ATTR_ICON, ATTR_UNIT_OF_MEASUREMENT, @@ -45,15 +44,6 @@ async def test_sensors(hass: HomeAssistant) -> None: registry = await hass.helpers.entity_registry.async_get_registry() - # Pre-create registry entries for sensors - registry.async_get_or_create( - SENSOR_DOMAIN, - DOMAIN, - "my_random_entity_id", - suggested_object_id="sensor.flipr_myfliprid_chlorine", - disabled_by=None, - ) - with patch( "flipr_api.FliprAPIRestClient.get_pool_measure_latest", return_value=MOCK_FLIPR_MEASURE, @@ -61,6 +51,10 @@ async def test_sensors(hass: HomeAssistant) -> None: await hass.config_entries.async_setup(entry.entry_id) await hass.async_block_till_done() + # Check entity unique_id value that is generated in FliprEntity base class. + entity = registry.async_get("sensor.flipr_myfliprid_red_ox") + assert entity.unique_id == "myfliprid-red_ox" + state = hass.states.get("sensor.flipr_myfliprid_ph") assert state assert state.attributes.get(ATTR_ICON) == "mdi:pool" @@ -90,3 +84,11 @@ async def test_sensors(hass: HomeAssistant) -> None: assert state.attributes.get(ATTR_ICON) == "mdi:pool" assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "mV" assert state.state == "0.23654886" + + state = hass.states.get("binary_sensor.flipr_myfliprid_ph_status") + assert state + assert state.state == "on" # Alert is on for binary sensor + + state = hass.states.get("binary_sensor.flipr_myfliprid_chlorine_status") + assert state + assert state.state == "off"