diff --git a/homeassistant/components/fyta/const.py b/homeassistant/components/fyta/const.py index bf4636a713a..9e1898f5ae6 100644 --- a/homeassistant/components/fyta/const.py +++ b/homeassistant/components/fyta/const.py @@ -2,3 +2,8 @@ DOMAIN = "fyta" CONF_EXPIRATION = "expiration" + +CONF_MAX_ACCEPTABLE = "max_acceptable" +CONF_MAX_GOOD = "max_good" +CONF_MIN_ACCEPTABLE = "min_acceptable" +CONF_MIN_GOOD = "min_good" diff --git a/homeassistant/components/fyta/sensor.py b/homeassistant/components/fyta/sensor.py index 622945ae102..d16a3eccfff 100644 --- a/homeassistant/components/fyta/sensor.py +++ b/homeassistant/components/fyta/sensor.py @@ -25,6 +25,12 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.typing import StateType +from .const import ( + CONF_MAX_ACCEPTABLE, + CONF_MAX_GOOD, + CONF_MIN_ACCEPTABLE, + CONF_MIN_GOOD, +) from .coordinator import FytaConfigEntry, FytaCoordinator from .entity import FytaPlantEntity @@ -36,6 +42,13 @@ class FytaSensorEntityDescription(SensorEntityDescription): value_fn: Callable[[Plant], StateType | datetime] +@dataclass(frozen=True, kw_only=True) +class FytaMeasurementSensorEntityDescription(FytaSensorEntityDescription): + """Describes Fyta sensor entity.""" + + attribute_fn: Callable[[Plant], dict[str, float | None]] + + PLANT_STATUS_LIST: list[str] = ["deleted", "doing_great", "need_attention", "no_sensor"] PLANT_MEASUREMENT_STATUS_LIST: list[str] = [ "no_data", @@ -95,35 +108,6 @@ SENSORS: Final[list[FytaSensorEntityDescription]] = [ options=PLANT_MEASUREMENT_STATUS_LIST, value_fn=lambda plant: plant.salinity_status.name.lower(), ), - FytaSensorEntityDescription( - key="temperature", - native_unit_of_measurement=UnitOfTemperature.CELSIUS, - device_class=SensorDeviceClass.TEMPERATURE, - state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda plant: plant.temperature, - ), - FytaSensorEntityDescription( - key="light", - translation_key="light", - native_unit_of_measurement="μmol/s⋅m²", - state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda plant: plant.light, - ), - FytaSensorEntityDescription( - key="moisture", - native_unit_of_measurement=PERCENTAGE, - device_class=SensorDeviceClass.MOISTURE, - state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda plant: plant.moisture, - ), - FytaSensorEntityDescription( - key="salinity", - translation_key="salinity", - native_unit_of_measurement=UnitOfConductivity.MILLISIEMENS_PER_CM, - device_class=SensorDeviceClass.CONDUCTIVITY, - state_class=SensorStateClass.MEASUREMENT, - value_fn=lambda plant: plant.salinity, - ), FytaSensorEntityDescription( key="ph", device_class=SensorDeviceClass.PH, @@ -152,6 +136,62 @@ SENSORS: Final[list[FytaSensorEntityDescription]] = [ ), ] +MEASUREMENT_SENSORS: Final[list[FytaMeasurementSensorEntityDescription]] = [ + FytaMeasurementSensorEntityDescription( + key="temperature", + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + device_class=SensorDeviceClass.TEMPERATURE, + state_class=SensorStateClass.MEASUREMENT, + attribute_fn=lambda plant: { + CONF_MAX_ACCEPTABLE: plant.temperature_max_acceptable, + CONF_MAX_GOOD: plant.temperature_max_good, + CONF_MIN_ACCEPTABLE: plant.temperature_min_acceptable, + CONF_MIN_GOOD: plant.temperature_min_good, + }, + value_fn=lambda plant: plant.temperature, + ), + FytaMeasurementSensorEntityDescription( + key="light", + translation_key="light", + native_unit_of_measurement="μmol/s⋅m²", + state_class=SensorStateClass.MEASUREMENT, + attribute_fn=lambda plant: { + CONF_MAX_ACCEPTABLE: plant.light_max_acceptable, + CONF_MAX_GOOD: plant.light_max_good, + CONF_MIN_ACCEPTABLE: plant.light_min_acceptable, + CONF_MIN_GOOD: plant.light_min_good, + }, + value_fn=lambda plant: plant.light, + ), + FytaMeasurementSensorEntityDescription( + key="moisture", + native_unit_of_measurement=PERCENTAGE, + device_class=SensorDeviceClass.MOISTURE, + state_class=SensorStateClass.MEASUREMENT, + attribute_fn=lambda plant: { + CONF_MAX_ACCEPTABLE: plant.moisture_max_acceptable, + CONF_MAX_GOOD: plant.moisture_max_good, + CONF_MIN_ACCEPTABLE: plant.moisture_min_acceptable, + CONF_MIN_GOOD: plant.moisture_min_good, + }, + value_fn=lambda plant: plant.moisture, + ), + FytaMeasurementSensorEntityDescription( + key="salinity", + translation_key="salinity", + native_unit_of_measurement=UnitOfConductivity.MILLISIEMENS_PER_CM, + device_class=SensorDeviceClass.CONDUCTIVITY, + state_class=SensorStateClass.MEASUREMENT, + attribute_fn=lambda plant: { + CONF_MAX_ACCEPTABLE: plant.salinity_max_acceptable, + CONF_MAX_GOOD: plant.salinity_max_good, + CONF_MIN_ACCEPTABLE: plant.salinity_min_acceptable, + CONF_MIN_GOOD: plant.salinity_min_good, + }, + value_fn=lambda plant: plant.salinity, + ), +] + async def async_setup_entry( hass: HomeAssistant, @@ -168,14 +208,28 @@ async def async_setup_entry( if sensor.key in dir(coordinator.data.get(plant_id)) ] + plant_entities.extend( + FytaPlantMeasurementSensor(coordinator, entry, sensor, plant_id) + for plant_id in coordinator.fyta.plant_list + for sensor in MEASUREMENT_SENSORS + if sensor.key in dir(coordinator.data.get(plant_id)) + ) + async_add_entities(plant_entities) def _async_add_new_device(plant_id: int) -> None: - async_add_entities( + plant_entities = [ FytaPlantSensor(coordinator, entry, sensor, plant_id) for sensor in SENSORS if sensor.key in dir(coordinator.data.get(plant_id)) + ] + + plant_entities.extend( + FytaPlantMeasurementSensor(coordinator, entry, sensor, plant_id) + for sensor in MEASUREMENT_SENSORS + if sensor.key in dir(coordinator.data.get(plant_id)) ) + async_add_entities(plant_entities) coordinator.new_device_callbacks.append(_async_add_new_device) @@ -190,3 +244,15 @@ class FytaPlantSensor(FytaPlantEntity, SensorEntity): """Return the state for this sensor.""" return self.entity_description.value_fn(self.plant) + + +class FytaPlantMeasurementSensor(FytaPlantSensor): + """Represents a Fyta measurement sensor.""" + + entity_description: FytaMeasurementSensorEntityDescription + + @property + def extra_state_attributes(self) -> dict[str, float | None]: + """Return the device state attributes.""" + + return self.entity_description.attribute_fn(self.plant) diff --git a/homeassistant/components/fyta/strings.json b/homeassistant/components/fyta/strings.json index 67bb991a437..b0c14e0d4c1 100644 --- a/homeassistant/components/fyta/strings.json +++ b/homeassistant/components/fyta/strings.json @@ -138,10 +138,64 @@ } }, "light": { - "name": "Light" + "name": "Light", + "state_attributes": { + "max_acceptable": { "name": "Maximum acceptable" }, + "max_good": { "name": "Maximum good" }, + "min_acceptable": { "name": "Minimum acceptable" }, + "min_good": { "name": "Minimum good" } + } + }, + "moisture": { + "name": "[%key:component::sensor::entity_component::moisture::name%]", + "state_attributes": { + "max_acceptable": { + "name": "[%key:component::fyta::entity::sensor::light::state_attributes::max_acceptable::name%]" + }, + "max_good": { + "name": "[%key:component::fyta::entity::sensor::light::state_attributes::max_good::name%]" + }, + "min_acceptable": { + "name": "[%key:component::fyta::entity::sensor::light::state_attributes::min_acceptable::name%]" + }, + "min_good": { + "name": "[%key:component::fyta::entity::sensor::light::state_attributes::min_good::name%]" + } + } }, "salinity": { - "name": "Salinity" + "name": "Salinity", + "state_attributes": { + "max_acceptable": { + "name": "[%key:component::fyta::entity::sensor::light::state_attributes::max_acceptable::name%]" + }, + "max_good": { + "name": "[%key:component::fyta::entity::sensor::light::state_attributes::max_good::name%]" + }, + "min_acceptable": { + "name": "[%key:component::fyta::entity::sensor::light::state_attributes::min_acceptable::name%]" + }, + "min_good": { + "name": "[%key:component::fyta::entity::sensor::light::state_attributes::min_good::name%]" + } + } + }, + "temperature": { + "name": "[%key:component::sensor::entity_component::temperature::name%]", + "state_attributes": { + "max_acceptable": { + "name": "[%key:component::fyta::entity::sensor::light::state_attributes::max_acceptable::name%]" + }, + "max_good": { + "name": "[%key:component::fyta::entity::sensor::light::state_attributes::max_good::name%]" + }, + "min_acceptable": { + "name": "[%key:component::fyta::entity::sensor::light::state_attributes::min_acceptable::name%]" + }, + "min_good": { + "name": "[%key:component::fyta::entity::sensor::light::state_attributes::min_good::name%]" + } + } }, "last_fertilised": { "name": "Last fertilized" diff --git a/tests/components/fyta/snapshots/test_sensor.ambr b/tests/components/fyta/snapshots/test_sensor.ambr index 5227755d852..289927a587b 100644 --- a/tests/components/fyta/snapshots/test_sensor.ambr +++ b/tests/components/fyta/snapshots/test_sensor.ambr @@ -142,6 +142,10 @@ StateSnapshot({ 'attributes': ReadOnlyDict({ 'friendly_name': 'Gummibaum Light', + 'max_acceptable': 675.0, + 'max_good': 450.0, + 'min_acceptable': 18.0, + 'min_good': 20.0, 'state_class': , 'unit_of_measurement': 'μmol/s⋅m²', }), @@ -261,6 +265,10 @@ 'attributes': ReadOnlyDict({ 'device_class': 'moisture', 'friendly_name': 'Gummibaum Moisture', + 'max_acceptable': 80.0, + 'max_good': 70.0, + 'min_acceptable': 25.0, + 'min_good': 35.0, 'state_class': , 'unit_of_measurement': '%', }), @@ -612,6 +620,10 @@ 'attributes': ReadOnlyDict({ 'device_class': 'conductivity', 'friendly_name': 'Gummibaum Salinity', + 'max_acceptable': 1.2, + 'max_good': 1.0, + 'min_acceptable': 0.4, + 'min_good': 0.6, 'state_class': , 'unit_of_measurement': , }), @@ -782,6 +794,10 @@ 'attributes': ReadOnlyDict({ 'device_class': 'temperature', 'friendly_name': 'Gummibaum Temperature', + 'max_acceptable': 42.0, + 'max_good': 36.0, + 'min_acceptable': 10.0, + 'min_good': 17.0, 'state_class': , 'unit_of_measurement': , }), @@ -1002,6 +1018,10 @@ StateSnapshot({ 'attributes': ReadOnlyDict({ 'friendly_name': 'Kakaobaum Light', + 'max_acceptable': 675.0, + 'max_good': 450.0, + 'min_acceptable': 18.0, + 'min_good': 20.0, 'state_class': , 'unit_of_measurement': 'μmol/s⋅m²', }), @@ -1121,6 +1141,10 @@ 'attributes': ReadOnlyDict({ 'device_class': 'moisture', 'friendly_name': 'Kakaobaum Moisture', + 'max_acceptable': 80.0, + 'max_good': 70.0, + 'min_acceptable': 25.0, + 'min_good': 35.0, 'state_class': , 'unit_of_measurement': '%', }), @@ -1472,6 +1496,10 @@ 'attributes': ReadOnlyDict({ 'device_class': 'conductivity', 'friendly_name': 'Kakaobaum Salinity', + 'max_acceptable': 1.2, + 'max_good': 1.0, + 'min_acceptable': 0.4, + 'min_good': 0.6, 'state_class': , 'unit_of_measurement': , }), @@ -1642,6 +1670,10 @@ 'attributes': ReadOnlyDict({ 'device_class': 'temperature', 'friendly_name': 'Kakaobaum Temperature', + 'max_acceptable': 42.0, + 'max_good': 36.0, + 'min_acceptable': 10.0, + 'min_good': 17.0, 'state_class': , 'unit_of_measurement': , }),