mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 20:27:08 +00:00
Finish EntityDescription implementation for RainMachine (#55180)
This commit is contained in:
parent
53851cb1b4
commit
6bc5c1c9af
@ -845,6 +845,7 @@ omit =
|
|||||||
homeassistant/components/raincloud/*
|
homeassistant/components/raincloud/*
|
||||||
homeassistant/components/rainmachine/__init__.py
|
homeassistant/components/rainmachine/__init__.py
|
||||||
homeassistant/components/rainmachine/binary_sensor.py
|
homeassistant/components/rainmachine/binary_sensor.py
|
||||||
|
homeassistant/components/rainmachine/model.py
|
||||||
homeassistant/components/rainmachine/sensor.py
|
homeassistant/components/rainmachine/sensor.py
|
||||||
homeassistant/components/rainmachine/switch.py
|
homeassistant/components/rainmachine/switch.py
|
||||||
homeassistant/components/raspihats/*
|
homeassistant/components/raspihats/*
|
||||||
|
@ -22,6 +22,7 @@ from homeassistant.core import HomeAssistant, callback
|
|||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
from homeassistant.helpers import aiohttp_client, config_validation as cv
|
from homeassistant.helpers import aiohttp_client, config_validation as cv
|
||||||
import homeassistant.helpers.device_registry as dr
|
import homeassistant.helpers.device_registry as dr
|
||||||
|
from homeassistant.helpers.entity import EntityDescription
|
||||||
from homeassistant.helpers.update_coordinator import (
|
from homeassistant.helpers.update_coordinator import (
|
||||||
CoordinatorEntity,
|
CoordinatorEntity,
|
||||||
DataUpdateCoordinator,
|
DataUpdateCoordinator,
|
||||||
@ -180,7 +181,7 @@ class RainMachineEntity(CoordinatorEntity):
|
|||||||
self,
|
self,
|
||||||
coordinator: DataUpdateCoordinator,
|
coordinator: DataUpdateCoordinator,
|
||||||
controller: Controller,
|
controller: Controller,
|
||||||
entity_type: str,
|
description: EntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
super().__init__(coordinator)
|
super().__init__(coordinator)
|
||||||
@ -200,9 +201,9 @@ class RainMachineEntity(CoordinatorEntity):
|
|||||||
# The colons are removed from the device MAC simply because that value
|
# The colons are removed from the device MAC simply because that value
|
||||||
# (unnecessarily) makes up the existing unique ID formula and we want to avoid
|
# (unnecessarily) makes up the existing unique ID formula and we want to avoid
|
||||||
# a breaking change:
|
# a breaking change:
|
||||||
self._attr_unique_id = f"{controller.mac.replace(':', '')}_{entity_type}"
|
self._attr_unique_id = f"{controller.mac.replace(':', '')}_{description.key}"
|
||||||
self._controller = controller
|
self._controller = controller
|
||||||
self._entity_type = entity_type
|
self.entity_description = description
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _handle_coordinator_update(self) -> None:
|
def _handle_coordinator_update(self) -> None:
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
"""This platform provides binary sensors for key RainMachine data."""
|
"""This platform provides binary sensors for key RainMachine data."""
|
||||||
|
from dataclasses import dataclass
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from regenmaschine.controller import Controller
|
from homeassistant.components.binary_sensor import (
|
||||||
|
BinarySensorEntity,
|
||||||
from homeassistant.components.binary_sensor import BinarySensorEntity
|
BinarySensorEntityDescription,
|
||||||
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
|
||||||
|
|
||||||
from . import RainMachineEntity
|
from . import RainMachineEntity
|
||||||
from .const import (
|
from .const import (
|
||||||
@ -18,6 +19,7 @@ from .const import (
|
|||||||
DATA_RESTRICTIONS_UNIVERSAL,
|
DATA_RESTRICTIONS_UNIVERSAL,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
|
from .model import RainMachineSensorDescriptionMixin
|
||||||
|
|
||||||
TYPE_FLOW_SENSOR = "flow_sensor"
|
TYPE_FLOW_SENSOR = "flow_sensor"
|
||||||
TYPE_FREEZE = "freeze"
|
TYPE_FREEZE = "freeze"
|
||||||
@ -29,47 +31,75 @@ TYPE_RAINDELAY = "raindelay"
|
|||||||
TYPE_RAINSENSOR = "rainsensor"
|
TYPE_RAINSENSOR = "rainsensor"
|
||||||
TYPE_WEEKDAY = "weekday"
|
TYPE_WEEKDAY = "weekday"
|
||||||
|
|
||||||
BINARY_SENSORS = {
|
|
||||||
TYPE_FLOW_SENSOR: ("Flow Sensor", "mdi:water-pump", True, DATA_PROVISION_SETTINGS),
|
@dataclass
|
||||||
TYPE_FREEZE: ("Freeze Restrictions", "mdi:cancel", True, DATA_RESTRICTIONS_CURRENT),
|
class RainMachineBinarySensorDescription(
|
||||||
TYPE_FREEZE_PROTECTION: (
|
BinarySensorEntityDescription, RainMachineSensorDescriptionMixin
|
||||||
"Freeze Protection",
|
):
|
||||||
"mdi:weather-snowy",
|
"""Describe a RainMachine binary sensor."""
|
||||||
True,
|
|
||||||
DATA_RESTRICTIONS_UNIVERSAL,
|
|
||||||
|
BINARY_SENSOR_DESCRIPTIONS = (
|
||||||
|
RainMachineBinarySensorDescription(
|
||||||
|
key=TYPE_FLOW_SENSOR,
|
||||||
|
name="Flow Sensor",
|
||||||
|
icon="mdi:water-pump",
|
||||||
|
api_category=DATA_PROVISION_SETTINGS,
|
||||||
),
|
),
|
||||||
TYPE_HOT_DAYS: (
|
RainMachineBinarySensorDescription(
|
||||||
"Extra Water on Hot Days",
|
key=TYPE_FREEZE,
|
||||||
"mdi:thermometer-lines",
|
name="Freeze Restrictions",
|
||||||
True,
|
icon="mdi:cancel",
|
||||||
DATA_RESTRICTIONS_UNIVERSAL,
|
api_category=DATA_RESTRICTIONS_CURRENT,
|
||||||
),
|
),
|
||||||
TYPE_HOURLY: (
|
RainMachineBinarySensorDescription(
|
||||||
"Hourly Restrictions",
|
key=TYPE_FREEZE_PROTECTION,
|
||||||
"mdi:cancel",
|
name="Freeze Protection",
|
||||||
False,
|
icon="mdi:weather-snowy",
|
||||||
DATA_RESTRICTIONS_CURRENT,
|
api_category=DATA_RESTRICTIONS_UNIVERSAL,
|
||||||
),
|
),
|
||||||
TYPE_MONTH: ("Month Restrictions", "mdi:cancel", False, DATA_RESTRICTIONS_CURRENT),
|
RainMachineBinarySensorDescription(
|
||||||
TYPE_RAINDELAY: (
|
key=TYPE_HOT_DAYS,
|
||||||
"Rain Delay Restrictions",
|
name="Extra Water on Hot Days",
|
||||||
"mdi:cancel",
|
icon="mdi:thermometer-lines",
|
||||||
False,
|
api_category=DATA_RESTRICTIONS_UNIVERSAL,
|
||||||
DATA_RESTRICTIONS_CURRENT,
|
|
||||||
),
|
),
|
||||||
TYPE_RAINSENSOR: (
|
RainMachineBinarySensorDescription(
|
||||||
"Rain Sensor Restrictions",
|
key=TYPE_HOURLY,
|
||||||
"mdi:cancel",
|
name="Hourly Restrictions",
|
||||||
False,
|
icon="mdi:cancel",
|
||||||
DATA_RESTRICTIONS_CURRENT,
|
entity_registry_enabled_default=False,
|
||||||
|
api_category=DATA_RESTRICTIONS_CURRENT,
|
||||||
),
|
),
|
||||||
TYPE_WEEKDAY: (
|
RainMachineBinarySensorDescription(
|
||||||
"Weekday Restrictions",
|
key=TYPE_MONTH,
|
||||||
"mdi:cancel",
|
name="Month Restrictions",
|
||||||
False,
|
icon="mdi:cancel",
|
||||||
DATA_RESTRICTIONS_CURRENT,
|
entity_registry_enabled_default=False,
|
||||||
|
api_category=DATA_RESTRICTIONS_CURRENT,
|
||||||
),
|
),
|
||||||
}
|
RainMachineBinarySensorDescription(
|
||||||
|
key=TYPE_RAINDELAY,
|
||||||
|
name="Rain Delay Restrictions",
|
||||||
|
icon="mdi:cancel",
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
api_category=DATA_RESTRICTIONS_CURRENT,
|
||||||
|
),
|
||||||
|
RainMachineBinarySensorDescription(
|
||||||
|
key=TYPE_RAINSENSOR,
|
||||||
|
name="Rain Sensor Restrictions",
|
||||||
|
icon="mdi:cancel",
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
api_category=DATA_RESTRICTIONS_CURRENT,
|
||||||
|
),
|
||||||
|
RainMachineBinarySensorDescription(
|
||||||
|
key=TYPE_WEEKDAY,
|
||||||
|
name="Weekday Restrictions",
|
||||||
|
icon="mdi:cancel",
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
api_category=DATA_RESTRICTIONS_CURRENT,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
@ -101,74 +131,49 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
async_add_entities(
|
async_add_entities(
|
||||||
[
|
[
|
||||||
async_get_sensor(api_category)(
|
async_get_sensor(description.api_category)(controller, description)
|
||||||
controller, sensor_type, name, icon, enabled_by_default
|
for description in BINARY_SENSOR_DESCRIPTIONS
|
||||||
)
|
|
||||||
for (
|
|
||||||
sensor_type,
|
|
||||||
(name, icon, enabled_by_default, api_category),
|
|
||||||
) in BINARY_SENSORS.items()
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RainMachineBinarySensor(RainMachineEntity, BinarySensorEntity):
|
class CurrentRestrictionsBinarySensor(RainMachineEntity, BinarySensorEntity):
|
||||||
"""Define a general RainMachine binary sensor."""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
coordinator: DataUpdateCoordinator,
|
|
||||||
controller: Controller,
|
|
||||||
sensor_type: str,
|
|
||||||
name: str,
|
|
||||||
icon: str,
|
|
||||||
enabled_by_default: bool,
|
|
||||||
) -> None:
|
|
||||||
"""Initialize the sensor."""
|
|
||||||
super().__init__(coordinator, controller, sensor_type)
|
|
||||||
|
|
||||||
self._attr_entity_registry_enabled_default = enabled_by_default
|
|
||||||
self._attr_icon = icon
|
|
||||||
self._attr_name = name
|
|
||||||
|
|
||||||
|
|
||||||
class CurrentRestrictionsBinarySensor(RainMachineBinarySensor):
|
|
||||||
"""Define a binary sensor that handles current restrictions data."""
|
"""Define a binary sensor that handles current restrictions data."""
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def update_from_latest_data(self) -> None:
|
def update_from_latest_data(self) -> None:
|
||||||
"""Update the state."""
|
"""Update the state."""
|
||||||
if self._entity_type == TYPE_FREEZE:
|
if self.entity_description.key == TYPE_FREEZE:
|
||||||
self._attr_is_on = self.coordinator.data["freeze"]
|
self._attr_is_on = self.coordinator.data["freeze"]
|
||||||
elif self._entity_type == TYPE_HOURLY:
|
elif self.entity_description.key == TYPE_HOURLY:
|
||||||
self._attr_is_on = self.coordinator.data["hourly"]
|
self._attr_is_on = self.coordinator.data["hourly"]
|
||||||
elif self._entity_type == TYPE_MONTH:
|
elif self.entity_description.key == TYPE_MONTH:
|
||||||
self._attr_is_on = self.coordinator.data["month"]
|
self._attr_is_on = self.coordinator.data["month"]
|
||||||
elif self._entity_type == TYPE_RAINDELAY:
|
elif self.entity_description.key == TYPE_RAINDELAY:
|
||||||
self._attr_is_on = self.coordinator.data["rainDelay"]
|
self._attr_is_on = self.coordinator.data["rainDelay"]
|
||||||
elif self._entity_type == TYPE_RAINSENSOR:
|
elif self.entity_description.key == TYPE_RAINSENSOR:
|
||||||
self._attr_is_on = self.coordinator.data["rainSensor"]
|
self._attr_is_on = self.coordinator.data["rainSensor"]
|
||||||
elif self._entity_type == TYPE_WEEKDAY:
|
elif self.entity_description.key == TYPE_WEEKDAY:
|
||||||
self._attr_is_on = self.coordinator.data["weekDay"]
|
self._attr_is_on = self.coordinator.data["weekDay"]
|
||||||
|
|
||||||
|
|
||||||
class ProvisionSettingsBinarySensor(RainMachineBinarySensor):
|
class ProvisionSettingsBinarySensor(RainMachineEntity, BinarySensorEntity):
|
||||||
"""Define a binary sensor that handles provisioning data."""
|
"""Define a binary sensor that handles provisioning data."""
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def update_from_latest_data(self) -> None:
|
def update_from_latest_data(self) -> None:
|
||||||
"""Update the state."""
|
"""Update the state."""
|
||||||
if self._entity_type == TYPE_FLOW_SENSOR:
|
if self.entity_description.key == TYPE_FLOW_SENSOR:
|
||||||
self._attr_is_on = self.coordinator.data["system"].get("useFlowSensor")
|
self._attr_is_on = self.coordinator.data["system"].get("useFlowSensor")
|
||||||
|
|
||||||
|
|
||||||
class UniversalRestrictionsBinarySensor(RainMachineBinarySensor):
|
class UniversalRestrictionsBinarySensor(RainMachineEntity, BinarySensorEntity):
|
||||||
"""Define a binary sensor that handles universal restrictions data."""
|
"""Define a binary sensor that handles universal restrictions data."""
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def update_from_latest_data(self) -> None:
|
def update_from_latest_data(self) -> None:
|
||||||
"""Update the state."""
|
"""Update the state."""
|
||||||
if self._entity_type == TYPE_FREEZE_PROTECTION:
|
if self.entity_description.key == TYPE_FREEZE_PROTECTION:
|
||||||
self._attr_is_on = self.coordinator.data["freezeProtectEnabled"]
|
self._attr_is_on = self.coordinator.data["freezeProtectEnabled"]
|
||||||
elif self._entity_type == TYPE_HOT_DAYS:
|
elif self.entity_description.key == TYPE_HOT_DAYS:
|
||||||
self._attr_is_on = self.coordinator.data["hotDaysExtraWatering"]
|
self._attr_is_on = self.coordinator.data["hotDaysExtraWatering"]
|
||||||
|
9
homeassistant/components/rainmachine/model.py
Normal file
9
homeassistant/components/rainmachine/model.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
"""Define RainMachine data models."""
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RainMachineSensorDescriptionMixin:
|
||||||
|
"""Define an entity description mixin for binary and regular sensors."""
|
||||||
|
|
||||||
|
api_category: str
|
@ -4,8 +4,6 @@ from __future__ import annotations
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from regenmaschine.controller import Controller
|
|
||||||
|
|
||||||
from homeassistant.components.sensor import SensorEntity, SensorEntityDescription
|
from homeassistant.components.sensor import SensorEntity, SensorEntityDescription
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
@ -15,7 +13,6 @@ from homeassistant.const import (
|
|||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
|
||||||
|
|
||||||
from . import RainMachineEntity
|
from . import RainMachineEntity
|
||||||
from .const import (
|
from .const import (
|
||||||
@ -25,6 +22,7 @@ from .const import (
|
|||||||
DATA_RESTRICTIONS_UNIVERSAL,
|
DATA_RESTRICTIONS_UNIVERSAL,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
|
from .model import RainMachineSensorDescriptionMixin
|
||||||
|
|
||||||
TYPE_FLOW_SENSOR_CLICK_M3 = "flow_sensor_clicks_cubic_meter"
|
TYPE_FLOW_SENSOR_CLICK_M3 = "flow_sensor_clicks_cubic_meter"
|
||||||
TYPE_FLOW_SENSOR_CONSUMED_LITERS = "flow_sensor_consumed_liters"
|
TYPE_FLOW_SENSOR_CONSUMED_LITERS = "flow_sensor_consumed_liters"
|
||||||
@ -34,21 +32,14 @@ TYPE_FREEZE_TEMP = "freeze_protect_temp"
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class RainmachineRequiredKeysMixin:
|
class RainMachineSensorEntityDescription(
|
||||||
"""Mixin for required keys."""
|
SensorEntityDescription, RainMachineSensorDescriptionMixin
|
||||||
|
|
||||||
api_category: str
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class RainmachineSensorEntityDescription(
|
|
||||||
SensorEntityDescription, RainmachineRequiredKeysMixin
|
|
||||||
):
|
):
|
||||||
"""Describes Rainmachine sensor entity."""
|
"""Describe a RainMachine sensor."""
|
||||||
|
|
||||||
|
|
||||||
SENSOR_TYPES: tuple[RainmachineSensorEntityDescription, ...] = (
|
SENSOR_DESCRIPTIONS = (
|
||||||
RainmachineSensorEntityDescription(
|
RainMachineSensorEntityDescription(
|
||||||
key=TYPE_FLOW_SENSOR_CLICK_M3,
|
key=TYPE_FLOW_SENSOR_CLICK_M3,
|
||||||
name="Flow Sensor Clicks",
|
name="Flow Sensor Clicks",
|
||||||
icon="mdi:water-pump",
|
icon="mdi:water-pump",
|
||||||
@ -56,7 +47,7 @@ SENSOR_TYPES: tuple[RainmachineSensorEntityDescription, ...] = (
|
|||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
api_category=DATA_PROVISION_SETTINGS,
|
api_category=DATA_PROVISION_SETTINGS,
|
||||||
),
|
),
|
||||||
RainmachineSensorEntityDescription(
|
RainMachineSensorEntityDescription(
|
||||||
key=TYPE_FLOW_SENSOR_CONSUMED_LITERS,
|
key=TYPE_FLOW_SENSOR_CONSUMED_LITERS,
|
||||||
name="Flow Sensor Consumed Liters",
|
name="Flow Sensor Consumed Liters",
|
||||||
icon="mdi:water-pump",
|
icon="mdi:water-pump",
|
||||||
@ -64,7 +55,7 @@ SENSOR_TYPES: tuple[RainmachineSensorEntityDescription, ...] = (
|
|||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
api_category=DATA_PROVISION_SETTINGS,
|
api_category=DATA_PROVISION_SETTINGS,
|
||||||
),
|
),
|
||||||
RainmachineSensorEntityDescription(
|
RainMachineSensorEntityDescription(
|
||||||
key=TYPE_FLOW_SENSOR_START_INDEX,
|
key=TYPE_FLOW_SENSOR_START_INDEX,
|
||||||
name="Flow Sensor Start Index",
|
name="Flow Sensor Start Index",
|
||||||
icon="mdi:water-pump",
|
icon="mdi:water-pump",
|
||||||
@ -72,7 +63,7 @@ SENSOR_TYPES: tuple[RainmachineSensorEntityDescription, ...] = (
|
|||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
api_category=DATA_PROVISION_SETTINGS,
|
api_category=DATA_PROVISION_SETTINGS,
|
||||||
),
|
),
|
||||||
RainmachineSensorEntityDescription(
|
RainMachineSensorEntityDescription(
|
||||||
key=TYPE_FLOW_SENSOR_WATERING_CLICKS,
|
key=TYPE_FLOW_SENSOR_WATERING_CLICKS,
|
||||||
name="Flow Sensor Clicks",
|
name="Flow Sensor Clicks",
|
||||||
icon="mdi:water-pump",
|
icon="mdi:water-pump",
|
||||||
@ -80,13 +71,12 @@ SENSOR_TYPES: tuple[RainmachineSensorEntityDescription, ...] = (
|
|||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
api_category=DATA_PROVISION_SETTINGS,
|
api_category=DATA_PROVISION_SETTINGS,
|
||||||
),
|
),
|
||||||
RainmachineSensorEntityDescription(
|
RainMachineSensorEntityDescription(
|
||||||
key=TYPE_FREEZE_TEMP,
|
key=TYPE_FREEZE_TEMP,
|
||||||
name="Freeze Protect Temperature",
|
name="Freeze Protect Temperature",
|
||||||
icon="mdi:thermometer",
|
icon="mdi:thermometer",
|
||||||
native_unit_of_measurement=TEMP_CELSIUS,
|
native_unit_of_measurement=TEMP_CELSIUS,
|
||||||
device_class=DEVICE_CLASS_TEMPERATURE,
|
device_class=DEVICE_CLASS_TEMPERATURE,
|
||||||
entity_registry_enabled_default=True,
|
|
||||||
api_category=DATA_RESTRICTIONS_UNIVERSAL,
|
api_category=DATA_RESTRICTIONS_UNIVERSAL,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -116,38 +106,22 @@ async def async_setup_entry(
|
|||||||
async_add_entities(
|
async_add_entities(
|
||||||
[
|
[
|
||||||
async_get_sensor(description.api_category)(controller, description)
|
async_get_sensor(description.api_category)(controller, description)
|
||||||
for description in SENSOR_TYPES
|
for description in SENSOR_DESCRIPTIONS
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RainMachineSensor(RainMachineEntity, SensorEntity):
|
class ProvisionSettingsSensor(RainMachineEntity, SensorEntity):
|
||||||
"""Define a general RainMachine sensor."""
|
|
||||||
|
|
||||||
entity_description: RainmachineSensorEntityDescription
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
coordinator: DataUpdateCoordinator,
|
|
||||||
controller: Controller,
|
|
||||||
description: RainmachineSensorEntityDescription,
|
|
||||||
) -> None:
|
|
||||||
"""Initialize."""
|
|
||||||
super().__init__(coordinator, controller, description.key)
|
|
||||||
self.entity_description = description
|
|
||||||
|
|
||||||
|
|
||||||
class ProvisionSettingsSensor(RainMachineSensor):
|
|
||||||
"""Define a sensor that handles provisioning data."""
|
"""Define a sensor that handles provisioning data."""
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def update_from_latest_data(self) -> None:
|
def update_from_latest_data(self) -> None:
|
||||||
"""Update the state."""
|
"""Update the state."""
|
||||||
if self._entity_type == TYPE_FLOW_SENSOR_CLICK_M3:
|
if self.entity_description.key == TYPE_FLOW_SENSOR_CLICK_M3:
|
||||||
self._attr_native_value = self.coordinator.data["system"].get(
|
self._attr_native_value = self.coordinator.data["system"].get(
|
||||||
"flowSensorClicksPerCubicMeter"
|
"flowSensorClicksPerCubicMeter"
|
||||||
)
|
)
|
||||||
elif self._entity_type == TYPE_FLOW_SENSOR_CONSUMED_LITERS:
|
elif self.entity_description.key == TYPE_FLOW_SENSOR_CONSUMED_LITERS:
|
||||||
clicks = self.coordinator.data["system"].get("flowSensorWateringClicks")
|
clicks = self.coordinator.data["system"].get("flowSensorWateringClicks")
|
||||||
clicks_per_m3 = self.coordinator.data["system"].get(
|
clicks_per_m3 = self.coordinator.data["system"].get(
|
||||||
"flowSensorClicksPerCubicMeter"
|
"flowSensorClicksPerCubicMeter"
|
||||||
@ -157,21 +131,21 @@ class ProvisionSettingsSensor(RainMachineSensor):
|
|||||||
self._attr_native_value = (clicks * 1000) / clicks_per_m3
|
self._attr_native_value = (clicks * 1000) / clicks_per_m3
|
||||||
else:
|
else:
|
||||||
self._attr_native_value = None
|
self._attr_native_value = None
|
||||||
elif self._entity_type == TYPE_FLOW_SENSOR_START_INDEX:
|
elif self.entity_description.key == TYPE_FLOW_SENSOR_START_INDEX:
|
||||||
self._attr_native_value = self.coordinator.data["system"].get(
|
self._attr_native_value = self.coordinator.data["system"].get(
|
||||||
"flowSensorStartIndex"
|
"flowSensorStartIndex"
|
||||||
)
|
)
|
||||||
elif self._entity_type == TYPE_FLOW_SENSOR_WATERING_CLICKS:
|
elif self.entity_description.key == TYPE_FLOW_SENSOR_WATERING_CLICKS:
|
||||||
self._attr_native_value = self.coordinator.data["system"].get(
|
self._attr_native_value = self.coordinator.data["system"].get(
|
||||||
"flowSensorWateringClicks"
|
"flowSensorWateringClicks"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class UniversalRestrictionsSensor(RainMachineSensor):
|
class UniversalRestrictionsSensor(RainMachineEntity, SensorEntity):
|
||||||
"""Define a sensor that handles universal restrictions data."""
|
"""Define a sensor that handles universal restrictions data."""
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def update_from_latest_data(self) -> None:
|
def update_from_latest_data(self) -> None:
|
||||||
"""Update the state."""
|
"""Update the state."""
|
||||||
if self._entity_type == TYPE_FREEZE_TEMP:
|
if self.entity_description.key == TYPE_FREEZE_TEMP:
|
||||||
self._attr_native_value = self.coordinator.data["freezeProtectTemp"]
|
self._attr_native_value = self.coordinator.data["freezeProtectTemp"]
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import Coroutine
|
from collections.abc import Coroutine
|
||||||
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@ -9,7 +10,7 @@ from regenmaschine.controller import Controller
|
|||||||
from regenmaschine.errors import RequestError
|
from regenmaschine.errors import RequestError
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.switch import SwitchEntity
|
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import ATTR_ID
|
from homeassistant.const import ATTR_ID
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
@ -115,6 +116,20 @@ SWITCH_TYPE_PROGRAM = "program"
|
|||||||
SWITCH_TYPE_ZONE = "zone"
|
SWITCH_TYPE_ZONE = "zone"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RainMachineSwitchDescriptionMixin:
|
||||||
|
"""Define an entity description mixin for switches."""
|
||||||
|
|
||||||
|
uid: int
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RainMachineSwitchDescription(
|
||||||
|
SwitchEntityDescription, RainMachineSwitchDescriptionMixin
|
||||||
|
):
|
||||||
|
"""Describe a RainMachine switch."""
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -166,17 +181,33 @@ async def async_setup_entry(
|
|||||||
]
|
]
|
||||||
zones_coordinator = hass.data[DOMAIN][DATA_COORDINATOR][entry.entry_id][DATA_ZONES]
|
zones_coordinator = hass.data[DOMAIN][DATA_COORDINATOR][entry.entry_id][DATA_ZONES]
|
||||||
|
|
||||||
entities: list[RainMachineProgram | RainMachineZone] = []
|
entities: list[RainMachineProgram | RainMachineZone] = [
|
||||||
|
|
||||||
for uid, program in programs_coordinator.data.items():
|
|
||||||
entities.append(
|
|
||||||
RainMachineProgram(
|
RainMachineProgram(
|
||||||
programs_coordinator, controller, uid, program["name"], entry
|
programs_coordinator,
|
||||||
|
controller,
|
||||||
|
entry,
|
||||||
|
RainMachineSwitchDescription(
|
||||||
|
key=f"RainMachineProgram_{uid}",
|
||||||
|
name=program["name"],
|
||||||
|
uid=uid,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
for uid, program in programs_coordinator.data.items()
|
||||||
|
]
|
||||||
|
entities.extend(
|
||||||
|
[
|
||||||
|
RainMachineZone(
|
||||||
|
zones_coordinator,
|
||||||
|
controller,
|
||||||
|
entry,
|
||||||
|
RainMachineSwitchDescription(
|
||||||
|
key=f"RainMachineZone_{uid}",
|
||||||
|
name=zone["name"],
|
||||||
|
uid=uid,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
for uid, zone in zones_coordinator.data.items():
|
for uid, zone in zones_coordinator.data.items()
|
||||||
entities.append(
|
]
|
||||||
RainMachineZone(zones_coordinator, controller, uid, zone["name"], entry)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
@ -186,35 +217,28 @@ class RainMachineSwitch(RainMachineEntity, SwitchEntity):
|
|||||||
"""A class to represent a generic RainMachine switch."""
|
"""A class to represent a generic RainMachine switch."""
|
||||||
|
|
||||||
_attr_icon = DEFAULT_ICON
|
_attr_icon = DEFAULT_ICON
|
||||||
|
entity_description: RainMachineSwitchDescription
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
coordinator: DataUpdateCoordinator,
|
coordinator: DataUpdateCoordinator,
|
||||||
controller: Controller,
|
controller: Controller,
|
||||||
uid: int,
|
|
||||||
name: str,
|
|
||||||
entry: ConfigEntry,
|
entry: ConfigEntry,
|
||||||
|
description: RainMachineSwitchDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize a generic RainMachine switch."""
|
"""Initialize a generic RainMachine switch."""
|
||||||
super().__init__(coordinator, controller, type(self).__name__)
|
super().__init__(coordinator, controller, description)
|
||||||
|
|
||||||
self._attr_is_on = False
|
self._attr_is_on = False
|
||||||
self._attr_name = name
|
self._data = coordinator.data[self.entity_description.uid]
|
||||||
self._data = coordinator.data[uid]
|
|
||||||
self._entry = entry
|
self._entry = entry
|
||||||
self._is_active = True
|
self._is_active = True
|
||||||
self._uid = uid
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self) -> bool:
|
def available(self) -> bool:
|
||||||
"""Return True if entity is available."""
|
"""Return True if entity is available."""
|
||||||
return super().available and self._is_active
|
return super().available and self._is_active
|
||||||
|
|
||||||
@property
|
|
||||||
def unique_id(self) -> str:
|
|
||||||
"""Return a unique, Home Assistant friendly identifier for this entity."""
|
|
||||||
return f"{super().unique_id}_{self._uid}"
|
|
||||||
|
|
||||||
async def _async_run_switch_coroutine(self, api_coro: Coroutine) -> None:
|
async def _async_run_switch_coroutine(self, api_coro: Coroutine) -> None:
|
||||||
"""Run a coroutine to toggle the switch."""
|
"""Run a coroutine to toggle the switch."""
|
||||||
try:
|
try:
|
||||||
@ -222,7 +246,7 @@ class RainMachineSwitch(RainMachineEntity, SwitchEntity):
|
|||||||
except RequestError as err:
|
except RequestError as err:
|
||||||
LOGGER.error(
|
LOGGER.error(
|
||||||
'Error while toggling %s "%s": %s',
|
'Error while toggling %s "%s": %s',
|
||||||
self._entity_type,
|
self.entity_description.key,
|
||||||
self.unique_id,
|
self.unique_id,
|
||||||
err,
|
err,
|
||||||
)
|
)
|
||||||
@ -231,7 +255,7 @@ class RainMachineSwitch(RainMachineEntity, SwitchEntity):
|
|||||||
if resp["statusCode"] != 0:
|
if resp["statusCode"] != 0:
|
||||||
LOGGER.error(
|
LOGGER.error(
|
||||||
'Error while toggling %s "%s": %s',
|
'Error while toggling %s "%s": %s',
|
||||||
self._entity_type,
|
self.entity_description.key,
|
||||||
self.unique_id,
|
self.unique_id,
|
||||||
resp["message"],
|
resp["message"],
|
||||||
)
|
)
|
||||||
@ -301,7 +325,7 @@ class RainMachineSwitch(RainMachineEntity, SwitchEntity):
|
|||||||
@callback
|
@callback
|
||||||
def update_from_latest_data(self) -> None:
|
def update_from_latest_data(self) -> None:
|
||||||
"""Update the state."""
|
"""Update the state."""
|
||||||
self._data = self.coordinator.data[self._uid]
|
self._data = self.coordinator.data[self.entity_description.uid]
|
||||||
self._is_active = self._data["active"]
|
self._is_active = self._data["active"]
|
||||||
|
|
||||||
|
|
||||||
@ -316,13 +340,13 @@ class RainMachineProgram(RainMachineSwitch):
|
|||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn the program off."""
|
"""Turn the program off."""
|
||||||
await self._async_run_switch_coroutine(
|
await self._async_run_switch_coroutine(
|
||||||
self._controller.programs.stop(self._uid)
|
self._controller.programs.stop(self.entity_description.uid)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn the program on."""
|
"""Turn the program on."""
|
||||||
await self._async_run_switch_coroutine(
|
await self._async_run_switch_coroutine(
|
||||||
self._controller.programs.start(self._uid)
|
self._controller.programs.start(self.entity_description.uid)
|
||||||
)
|
)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@ -341,10 +365,14 @@ class RainMachineProgram(RainMachineSwitch):
|
|||||||
|
|
||||||
self._attr_extra_state_attributes.update(
|
self._attr_extra_state_attributes.update(
|
||||||
{
|
{
|
||||||
ATTR_ID: self._uid,
|
ATTR_ID: self.entity_description.uid,
|
||||||
ATTR_NEXT_RUN: next_run,
|
ATTR_NEXT_RUN: next_run,
|
||||||
ATTR_SOAK: self.coordinator.data[self._uid].get("soak"),
|
ATTR_SOAK: self.coordinator.data[self.entity_description.uid].get(
|
||||||
ATTR_STATUS: RUN_STATUS_MAP[self.coordinator.data[self._uid]["status"]],
|
"soak"
|
||||||
|
),
|
||||||
|
ATTR_STATUS: RUN_STATUS_MAP[
|
||||||
|
self.coordinator.data[self.entity_description.uid]["status"]
|
||||||
|
],
|
||||||
ATTR_ZONES: ", ".join(z["name"] for z in self.zones),
|
ATTR_ZONES: ", ".join(z["name"] for z in self.zones),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -355,13 +383,15 @@ class RainMachineZone(RainMachineSwitch):
|
|||||||
|
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn the zone off."""
|
"""Turn the zone off."""
|
||||||
await self._async_run_switch_coroutine(self._controller.zones.stop(self._uid))
|
await self._async_run_switch_coroutine(
|
||||||
|
self._controller.zones.stop(self.entity_description.uid)
|
||||||
|
)
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
"""Turn the zone on."""
|
"""Turn the zone on."""
|
||||||
await self._async_run_switch_coroutine(
|
await self._async_run_switch_coroutine(
|
||||||
self._controller.zones.start(
|
self._controller.zones.start(
|
||||||
self._uid,
|
self.entity_description.uid,
|
||||||
self._entry.options[CONF_ZONE_RUN_TIME],
|
self._entry.options[CONF_ZONE_RUN_TIME],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user