234 lines
8.0 KiB
Python
234 lines
8.0 KiB
Python
"""Support for Hydrawise sprinkler sensors."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Callable
|
|
from dataclasses import dataclass
|
|
from datetime import datetime, timedelta
|
|
from typing import Any
|
|
|
|
from homeassistant.components.sensor import (
|
|
SensorDeviceClass,
|
|
SensorEntity,
|
|
SensorEntityDescription,
|
|
)
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.const import UnitOfTime, UnitOfVolume
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
from homeassistant.util import dt as dt_util
|
|
|
|
from .const import DOMAIN
|
|
from .coordinator import HydrawiseDataUpdateCoordinator
|
|
from .entity import HydrawiseEntity
|
|
|
|
|
|
@dataclass(frozen=True, kw_only=True)
|
|
class HydrawiseSensorEntityDescription(SensorEntityDescription):
|
|
"""Describes Hydrawise binary sensor."""
|
|
|
|
value_fn: Callable[[HydrawiseSensor], Any]
|
|
|
|
|
|
def _get_zone_watering_time(sensor: HydrawiseSensor) -> int:
|
|
if (current_run := sensor.zone.scheduled_runs.current_run) is not None:
|
|
return int(current_run.remaining_time.total_seconds() / 60)
|
|
return 0
|
|
|
|
|
|
def _get_zone_next_cycle(sensor: HydrawiseSensor) -> datetime | None:
|
|
if (next_run := sensor.zone.scheduled_runs.next_run) is not None:
|
|
return dt_util.as_utc(next_run.start_time)
|
|
return None
|
|
|
|
|
|
def _get_zone_daily_active_water_use(sensor: HydrawiseSensor) -> float:
|
|
"""Get active water use for the zone."""
|
|
daily_water_summary = sensor.coordinator.data.daily_water_summary[
|
|
sensor.controller.id
|
|
]
|
|
return float(daily_water_summary.active_use_by_zone_id.get(sensor.zone.id, 0.0))
|
|
|
|
|
|
def _get_zone_daily_active_water_time(sensor: HydrawiseSensor) -> float | None:
|
|
"""Get active water time for the zone."""
|
|
daily_water_summary = sensor.coordinator.data.daily_water_summary[
|
|
sensor.controller.id
|
|
]
|
|
return daily_water_summary.active_time_by_zone_id.get(
|
|
sensor.zone.id, timedelta()
|
|
).total_seconds()
|
|
|
|
|
|
def _get_controller_daily_active_water_use(sensor: HydrawiseSensor) -> float | None:
|
|
"""Get active water use for the controller."""
|
|
daily_water_summary = sensor.coordinator.data.daily_water_summary[
|
|
sensor.controller.id
|
|
]
|
|
return daily_water_summary.total_active_use
|
|
|
|
|
|
def _get_controller_daily_inactive_water_use(sensor: HydrawiseSensor) -> float | None:
|
|
"""Get inactive water use for the controller."""
|
|
daily_water_summary = sensor.coordinator.data.daily_water_summary[
|
|
sensor.controller.id
|
|
]
|
|
return daily_water_summary.total_inactive_use
|
|
|
|
|
|
def _get_controller_daily_active_water_time(sensor: HydrawiseSensor) -> float:
|
|
"""Get active water time for the controller."""
|
|
daily_water_summary = sensor.coordinator.data.daily_water_summary[
|
|
sensor.controller.id
|
|
]
|
|
return daily_water_summary.total_active_time.total_seconds()
|
|
|
|
|
|
def _get_controller_daily_total_water_use(sensor: HydrawiseSensor) -> float | None:
|
|
"""Get inactive water use for the controller."""
|
|
daily_water_summary = sensor.coordinator.data.daily_water_summary[
|
|
sensor.controller.id
|
|
]
|
|
return daily_water_summary.total_use
|
|
|
|
|
|
CONTROLLER_SENSORS: tuple[HydrawiseSensorEntityDescription, ...] = (
|
|
HydrawiseSensorEntityDescription(
|
|
key="daily_active_water_time",
|
|
translation_key="daily_active_water_time",
|
|
device_class=SensorDeviceClass.DURATION,
|
|
native_unit_of_measurement=UnitOfTime.SECONDS,
|
|
value_fn=_get_controller_daily_active_water_time,
|
|
),
|
|
)
|
|
|
|
|
|
FLOW_CONTROLLER_SENSORS: tuple[HydrawiseSensorEntityDescription, ...] = (
|
|
HydrawiseSensorEntityDescription(
|
|
key="daily_total_water_use",
|
|
translation_key="daily_total_water_use",
|
|
device_class=SensorDeviceClass.VOLUME,
|
|
suggested_display_precision=1,
|
|
value_fn=_get_controller_daily_total_water_use,
|
|
),
|
|
HydrawiseSensorEntityDescription(
|
|
key="daily_active_water_use",
|
|
translation_key="daily_active_water_use",
|
|
device_class=SensorDeviceClass.VOLUME,
|
|
suggested_display_precision=1,
|
|
value_fn=_get_controller_daily_active_water_use,
|
|
),
|
|
HydrawiseSensorEntityDescription(
|
|
key="daily_inactive_water_use",
|
|
translation_key="daily_inactive_water_use",
|
|
device_class=SensorDeviceClass.VOLUME,
|
|
suggested_display_precision=1,
|
|
value_fn=_get_controller_daily_inactive_water_use,
|
|
),
|
|
)
|
|
|
|
FLOW_ZONE_SENSORS: tuple[SensorEntityDescription, ...] = (
|
|
HydrawiseSensorEntityDescription(
|
|
key="daily_active_water_use",
|
|
translation_key="daily_active_water_use",
|
|
device_class=SensorDeviceClass.VOLUME,
|
|
suggested_display_precision=1,
|
|
value_fn=_get_zone_daily_active_water_use,
|
|
),
|
|
)
|
|
|
|
ZONE_SENSORS: tuple[HydrawiseSensorEntityDescription, ...] = (
|
|
HydrawiseSensorEntityDescription(
|
|
key="next_cycle",
|
|
translation_key="next_cycle",
|
|
device_class=SensorDeviceClass.TIMESTAMP,
|
|
value_fn=_get_zone_next_cycle,
|
|
),
|
|
HydrawiseSensorEntityDescription(
|
|
key="watering_time",
|
|
translation_key="watering_time",
|
|
native_unit_of_measurement=UnitOfTime.MINUTES,
|
|
value_fn=_get_zone_watering_time,
|
|
),
|
|
HydrawiseSensorEntityDescription(
|
|
key="daily_active_water_time",
|
|
translation_key="daily_active_water_time",
|
|
device_class=SensorDeviceClass.DURATION,
|
|
native_unit_of_measurement=UnitOfTime.SECONDS,
|
|
value_fn=_get_zone_daily_active_water_time,
|
|
),
|
|
)
|
|
|
|
FLOW_MEASUREMENT_KEYS = [x.key for x in FLOW_CONTROLLER_SENSORS]
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
config_entry: ConfigEntry,
|
|
async_add_entities: AddEntitiesCallback,
|
|
) -> None:
|
|
"""Set up the Hydrawise sensor platform."""
|
|
coordinator: HydrawiseDataUpdateCoordinator = hass.data[DOMAIN][
|
|
config_entry.entry_id
|
|
]
|
|
entities: list[HydrawiseSensor] = []
|
|
for controller in coordinator.data.controllers.values():
|
|
entities.extend(
|
|
HydrawiseSensor(coordinator, description, controller)
|
|
for description in CONTROLLER_SENSORS
|
|
)
|
|
entities.extend(
|
|
HydrawiseSensor(coordinator, description, controller, zone_id=zone.id)
|
|
for zone in controller.zones
|
|
for description in ZONE_SENSORS
|
|
)
|
|
if coordinator.data.daily_water_summary[controller.id].total_use is not None:
|
|
# we have a flow sensor for this controller
|
|
entities.extend(
|
|
HydrawiseSensor(coordinator, description, controller)
|
|
for description in FLOW_CONTROLLER_SENSORS
|
|
)
|
|
entities.extend(
|
|
HydrawiseSensor(
|
|
coordinator,
|
|
description,
|
|
controller,
|
|
zone_id=zone.id,
|
|
)
|
|
for zone in controller.zones
|
|
for description in FLOW_ZONE_SENSORS
|
|
)
|
|
async_add_entities(entities)
|
|
|
|
|
|
class HydrawiseSensor(HydrawiseEntity, SensorEntity):
|
|
"""A sensor implementation for Hydrawise device."""
|
|
|
|
entity_description: HydrawiseSensorEntityDescription
|
|
|
|
@property
|
|
def native_unit_of_measurement(self) -> str | None:
|
|
"""Return the unit_of_measurement of the sensor."""
|
|
if self.entity_description.device_class != SensorDeviceClass.VOLUME:
|
|
return self.entity_description.native_unit_of_measurement
|
|
return (
|
|
UnitOfVolume.GALLONS
|
|
if self.coordinator.data.user.units.units_name == "imperial"
|
|
else UnitOfVolume.LITERS
|
|
)
|
|
|
|
@property
|
|
def icon(self) -> str | None:
|
|
"""Icon of the entity based on the value."""
|
|
if (
|
|
self.entity_description.key in FLOW_MEASUREMENT_KEYS
|
|
and self.entity_description.device_class == SensorDeviceClass.VOLUME
|
|
and round(self.state, 2) == 0.0
|
|
):
|
|
return "mdi:water-outline"
|
|
return None
|
|
|
|
def _update_attrs(self) -> None:
|
|
"""Update state attributes."""
|
|
self._attr_native_value = self.entity_description.value_fn(self)
|