Add Rachio smart hose timer support (#107901)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
3c13a28357
commit
dbb4cf0ee7
9 changed files with 263 additions and 17 deletions
|
@ -1062,6 +1062,7 @@ omit =
|
|||
homeassistant/components/rabbitair/fan.py
|
||||
homeassistant/components/rachio/__init__.py
|
||||
homeassistant/components/rachio/binary_sensor.py
|
||||
homeassistant/components/rachio/coordinator.py
|
||||
homeassistant/components/rachio/device.py
|
||||
homeassistant/components/rachio/entity.py
|
||||
homeassistant/components/rachio/switch.py
|
||||
|
|
|
@ -83,7 +83,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
raise ConfigEntryNotReady from error
|
||||
|
||||
# Check for Rachio controller devices
|
||||
if not person.controllers:
|
||||
if not person.controllers and not person.base_stations:
|
||||
_LOGGER.error("No Rachio devices found in account %s", person.username)
|
||||
return False
|
||||
_LOGGER.info(
|
||||
|
@ -91,10 +91,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
"%d Rachio device(s) found; The url %s must be accessible from the internet"
|
||||
" in order to receive updates"
|
||||
),
|
||||
len(person.controllers),
|
||||
len(person.controllers) + len(person.base_stations),
|
||||
webhook_url,
|
||||
)
|
||||
|
||||
for base in person.base_stations:
|
||||
await base.coordinator.async_config_entry_first_refresh()
|
||||
|
||||
# Enable platform
|
||||
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = person
|
||||
async_register_webhook(hass, entry)
|
||||
|
|
|
@ -26,6 +26,7 @@ KEY_NAME = "name"
|
|||
KEY_MODEL = "model"
|
||||
KEY_ON = "on"
|
||||
KEY_DURATION = "totalDuration"
|
||||
KEY_DURATION_MINUTES = "duration"
|
||||
KEY_RAIN_DELAY = "rainDelayExpirationDate"
|
||||
KEY_RAIN_DELAY_END = "endTime"
|
||||
KEY_RAIN_SENSOR_TRIPPED = "rainSensorTripped"
|
||||
|
@ -47,6 +48,21 @@ KEY_CUSTOM_SHADE = "customShade"
|
|||
KEY_CUSTOM_CROP = "customCrop"
|
||||
KEY_CUSTOM_SLOPE = "customSlope"
|
||||
|
||||
# Smart Hose timer
|
||||
KEY_BASE_STATIONS = "baseStations"
|
||||
KEY_VALVES = "valves"
|
||||
KEY_REPORTED_STATE = "reportedState"
|
||||
KEY_STATE = "state"
|
||||
KEY_CONNECTED = "connected"
|
||||
KEY_CURRENT_STATUS = "lastWateringAction"
|
||||
KEY_DETECT_FLOW = "detectFlow"
|
||||
KEY_BATTERY_STATUS = "batteryStatus"
|
||||
KEY_REASON = "reason"
|
||||
KEY_DEFAULT_RUNTIME = "defaultRuntimeSeconds"
|
||||
KEY_DURATION_SECONDS = "durationSeconds"
|
||||
KEY_FLOW_DETECTED = "flowDetected"
|
||||
KEY_START_TIME = "start"
|
||||
|
||||
STATUS_ONLINE = "ONLINE"
|
||||
|
||||
MODEL_GENERATION_1 = "GENERATION1"
|
||||
|
@ -56,6 +72,7 @@ SERVICE_PAUSE_WATERING = "pause_watering"
|
|||
SERVICE_RESUME_WATERING = "resume_watering"
|
||||
SERVICE_STOP_WATERING = "stop_watering"
|
||||
SERVICE_SET_ZONE_MOISTURE = "set_zone_moisture_percent"
|
||||
SERVICE_START_WATERING = "start_watering"
|
||||
SERVICE_START_MULTIPLE_ZONES = "start_multiple_zone_schedule"
|
||||
|
||||
SIGNAL_RACHIO_UPDATE = f"{DOMAIN}_update"
|
||||
|
|
56
homeassistant/components/rachio/coordinator.py
Normal file
56
homeassistant/components/rachio/coordinator.py
Normal file
|
@ -0,0 +1,56 @@
|
|||
"""Coordinator object for the Rachio integration."""
|
||||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from rachiopy import Rachio
|
||||
from requests.exceptions import Timeout
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.debounce import Debouncer
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .const import DOMAIN, KEY_ID, KEY_VALVES
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
UPDATE_DELAY_TIME = 8
|
||||
|
||||
|
||||
class RachioUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
"""Coordinator Class for Rachio Hose Timers."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
rachio: Rachio,
|
||||
base_station,
|
||||
base_count: int,
|
||||
) -> None:
|
||||
"""Initialize the Rachio Update Coordinator."""
|
||||
self.hass = hass
|
||||
self.rachio = rachio
|
||||
self.base_station = base_station
|
||||
super().__init__(
|
||||
hass,
|
||||
_LOGGER,
|
||||
name=f"{DOMAIN} update coordinator",
|
||||
# To avoid exceeding the rate limit, increase polling interval for
|
||||
# each additional base station on the account
|
||||
update_interval=timedelta(minutes=(base_count + 1)),
|
||||
# Debouncer used because the API takes a bit to update state changes
|
||||
request_refresh_debouncer=Debouncer(
|
||||
hass, _LOGGER, cooldown=UPDATE_DELAY_TIME, immediate=False
|
||||
),
|
||||
)
|
||||
|
||||
async def _async_update_data(self) -> dict[str, Any]:
|
||||
"""Update smart hose timer data."""
|
||||
try:
|
||||
data = await self.hass.async_add_executor_job(
|
||||
self.rachio.valve.list_valves, self.base_station[KEY_ID]
|
||||
)
|
||||
except Timeout as err:
|
||||
raise UpdateFailed(f"Could not connect to the Rachio API: {err}") from err
|
||||
return {valve[KEY_ID]: valve for valve in data[1][KEY_VALVES]}
|
|
@ -17,6 +17,7 @@ from homeassistant.helpers import config_validation as cv
|
|||
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
KEY_BASE_STATIONS,
|
||||
KEY_DEVICES,
|
||||
KEY_ENABLED,
|
||||
KEY_EXTERNAL_ID,
|
||||
|
@ -37,6 +38,7 @@ from .const import (
|
|||
SERVICE_STOP_WATERING,
|
||||
WEBHOOK_CONST_ID,
|
||||
)
|
||||
from .coordinator import RachioUpdateCoordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -67,6 +69,7 @@ class RachioPerson:
|
|||
self.username = None
|
||||
self._id: str | None = None
|
||||
self._controllers: list[RachioIro] = []
|
||||
self._base_stations: list[RachioBaseStation] = []
|
||||
|
||||
async def async_setup(self, hass: HomeAssistant) -> None:
|
||||
"""Create rachio devices and services."""
|
||||
|
@ -78,30 +81,34 @@ class RachioPerson:
|
|||
can_pause = True
|
||||
break
|
||||
|
||||
all_devices = [rachio_iro.name for rachio_iro in self._controllers]
|
||||
all_controllers = [rachio_iro.name for rachio_iro in self._controllers]
|
||||
|
||||
def pause_water(service: ServiceCall) -> None:
|
||||
"""Service to pause watering on all or specific controllers."""
|
||||
duration = service.data[ATTR_DURATION]
|
||||
devices = service.data.get(ATTR_DEVICES, all_devices)
|
||||
devices = service.data.get(ATTR_DEVICES, all_controllers)
|
||||
for iro in self._controllers:
|
||||
if iro.name in devices:
|
||||
iro.pause_watering(duration)
|
||||
|
||||
def resume_water(service: ServiceCall) -> None:
|
||||
"""Service to resume watering on all or specific controllers."""
|
||||
devices = service.data.get(ATTR_DEVICES, all_devices)
|
||||
devices = service.data.get(ATTR_DEVICES, all_controllers)
|
||||
for iro in self._controllers:
|
||||
if iro.name in devices:
|
||||
iro.resume_watering()
|
||||
|
||||
def stop_water(service: ServiceCall) -> None:
|
||||
"""Service to stop watering on all or specific controllers."""
|
||||
devices = service.data.get(ATTR_DEVICES, all_devices)
|
||||
devices = service.data.get(ATTR_DEVICES, all_controllers)
|
||||
for iro in self._controllers:
|
||||
if iro.name in devices:
|
||||
iro.stop_watering()
|
||||
|
||||
# If only hose timers on account, none of these services apply
|
||||
if not all_controllers:
|
||||
return
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_STOP_WATERING,
|
||||
|
@ -145,6 +152,9 @@ class RachioPerson:
|
|||
raise ConfigEntryNotReady(f"API Error: {data}")
|
||||
self.username = data[1][KEY_USERNAME]
|
||||
devices: list[dict[str, Any]] = data[1][KEY_DEVICES]
|
||||
base_station_data = rachio.valve.list_base_stations(self._id)
|
||||
base_stations: list[dict[str, Any]] = base_station_data[1][KEY_BASE_STATIONS]
|
||||
|
||||
for controller in devices:
|
||||
webhooks = rachio.notification.get_device_webhook(controller[KEY_ID])[1]
|
||||
# The API does not provide a way to tell if a controller is shared
|
||||
|
@ -174,6 +184,14 @@ class RachioPerson:
|
|||
rachio_iro.setup()
|
||||
self._controllers.append(rachio_iro)
|
||||
|
||||
base_count = len(base_stations)
|
||||
self._base_stations.extend(
|
||||
RachioBaseStation(
|
||||
rachio, base, RachioUpdateCoordinator(hass, rachio, base, base_count)
|
||||
)
|
||||
for base in base_stations
|
||||
)
|
||||
|
||||
_LOGGER.info('Using Rachio API as user "%s"', self.username)
|
||||
|
||||
@property
|
||||
|
@ -186,6 +204,11 @@ class RachioPerson:
|
|||
"""Get a list of controllers managed by this account."""
|
||||
return self._controllers
|
||||
|
||||
@property
|
||||
def base_stations(self) -> list[RachioBaseStation]:
|
||||
"""List of smart hose timer base stations."""
|
||||
return self._base_stations
|
||||
|
||||
def start_multiple_zones(self, zones) -> None:
|
||||
"""Start multiple zones."""
|
||||
self.rachio.zone.start_multiple(zones)
|
||||
|
@ -321,6 +344,28 @@ class RachioIro:
|
|||
_LOGGER.debug("Resuming watering on %s", self)
|
||||
|
||||
|
||||
class RachioBaseStation:
|
||||
"""Represent a smart hose timer base station."""
|
||||
|
||||
def __init__(
|
||||
self, rachio: Rachio, data: dict[str, Any], coordinator: RachioUpdateCoordinator
|
||||
) -> None:
|
||||
"""Initialize a hose time base station."""
|
||||
self.rachio = rachio
|
||||
self._id = data[KEY_ID]
|
||||
self.serial_number = data[KEY_SERIAL_NUMBER]
|
||||
self.mac_address = data[KEY_MAC_ADDRESS]
|
||||
self.coordinator = coordinator
|
||||
|
||||
def start_watering(self, valve_id: str, duration: int) -> None:
|
||||
"""Start watering on this valve."""
|
||||
self.rachio.valve.start_watering(valve_id, duration)
|
||||
|
||||
def stop_watering(self, valve_id: str) -> None:
|
||||
"""Stop watering on this valve."""
|
||||
self.rachio.valve.stop_watering(valve_id)
|
||||
|
||||
|
||||
def is_invalid_auth_code(http_status_code: int) -> bool:
|
||||
"""HTTP status codes that mean invalid auth."""
|
||||
return http_status_code in (HTTPStatus.UNAUTHORIZED, HTTPStatus.FORBIDDEN)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"start_multiple_zone_schedule": "mdi:play",
|
||||
"pause_watering": "mdi:pause",
|
||||
"resume_watering": "mdi:play",
|
||||
"stop_watering": "mdi:stop"
|
||||
"stop_watering": "mdi:stop",
|
||||
"start_watering": "mdi:water"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,17 @@ set_zone_moisture_percent:
|
|||
min: 0
|
||||
max: 100
|
||||
unit_of_measurement: "%"
|
||||
start_watering:
|
||||
target:
|
||||
entity:
|
||||
integration: rachio
|
||||
domain: switch
|
||||
fields:
|
||||
duration:
|
||||
example: 15
|
||||
required: false
|
||||
selector:
|
||||
object:
|
||||
start_multiple_zone_schedule:
|
||||
target:
|
||||
entity:
|
||||
|
|
|
@ -63,6 +63,16 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"start_watering": {
|
||||
"name": "Start watering",
|
||||
"description": "Start a single zone, a schedule or any number of smart hose timers.",
|
||||
"fields": {
|
||||
"duration": {
|
||||
"name": "Duration",
|
||||
"description": "Number of minutes to run. For sprinkler zones the maximum duration is 3 hours, or 24 hours for smart hose timers. Leave empty for schedules."
|
||||
}
|
||||
}
|
||||
},
|
||||
"pause_watering": {
|
||||
"name": "Pause watering",
|
||||
"description": "Pause any currently running zones or schedules.",
|
||||
|
|
|
@ -11,19 +11,28 @@ import voluptuous as vol
|
|||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import ATTR_ENTITY_ID, ATTR_ID
|
||||
from homeassistant.core import HomeAssistant, ServiceCall, callback
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, ServiceCall, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import config_validation as cv, entity_platform
|
||||
from homeassistant.helpers import (
|
||||
config_validation as cv,
|
||||
device_registry as dr,
|
||||
entity_platform,
|
||||
)
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.event import async_track_point_in_utc_time
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
from homeassistant.util.dt import as_timestamp, now, parse_datetime, utc_from_timestamp
|
||||
|
||||
from .const import (
|
||||
CONF_MANUAL_RUN_MINS,
|
||||
DEFAULT_MANUAL_RUN_MINS,
|
||||
DEFAULT_NAME,
|
||||
DOMAIN as DOMAIN_RACHIO,
|
||||
KEY_CONNECTED,
|
||||
KEY_CURRENT_STATUS,
|
||||
KEY_CUSTOM_CROP,
|
||||
KEY_CUSTOM_SHADE,
|
||||
KEY_CUSTOM_SLOPE,
|
||||
|
@ -36,7 +45,9 @@ from .const import (
|
|||
KEY_ON,
|
||||
KEY_RAIN_DELAY,
|
||||
KEY_RAIN_DELAY_END,
|
||||
KEY_REPORTED_STATE,
|
||||
KEY_SCHEDULE_ID,
|
||||
KEY_STATE,
|
||||
KEY_SUBTYPE,
|
||||
KEY_SUMMARY,
|
||||
KEY_TYPE,
|
||||
|
@ -46,6 +57,7 @@ from .const import (
|
|||
SCHEDULE_TYPE_FLEX,
|
||||
SERVICE_SET_ZONE_MOISTURE,
|
||||
SERVICE_START_MULTIPLE_ZONES,
|
||||
SERVICE_START_WATERING,
|
||||
SIGNAL_RACHIO_CONTROLLER_UPDATE,
|
||||
SIGNAL_RACHIO_RAIN_DELAY_UPDATE,
|
||||
SIGNAL_RACHIO_SCHEDULE_UPDATE,
|
||||
|
@ -55,6 +67,7 @@ from .const import (
|
|||
SLOPE_SLIGHT,
|
||||
SLOPE_STEEP,
|
||||
)
|
||||
from .coordinator import RachioUpdateCoordinator
|
||||
from .device import RachioPerson
|
||||
from .entity import RachioDevice
|
||||
from .webhooks import (
|
||||
|
@ -80,6 +93,7 @@ ATTR_SCHEDULE_ENABLED = "Enabled"
|
|||
ATTR_SCHEDULE_DURATION = "Duration"
|
||||
ATTR_SCHEDULE_TYPE = "Type"
|
||||
ATTR_SORT_ORDER = "sortOrder"
|
||||
ATTR_WATERING_DURATION = "Watering Duration seconds"
|
||||
ATTR_ZONE_NUMBER = "Zone number"
|
||||
ATTR_ZONE_SHADE = "Shade"
|
||||
ATTR_ZONE_SLOPE = "Slope"
|
||||
|
@ -141,6 +155,19 @@ async def async_setup_entry(
|
|||
else:
|
||||
raise HomeAssistantError("No matching zones found in given entity_ids")
|
||||
|
||||
platform = entity_platform.async_get_current_platform()
|
||||
platform.async_register_entity_service(
|
||||
SERVICE_START_WATERING,
|
||||
{
|
||||
vol.Optional(ATTR_DURATION): cv.positive_int,
|
||||
},
|
||||
"turn_on",
|
||||
)
|
||||
|
||||
# If only hose timers on account, none of these services apply
|
||||
if not zone_entities:
|
||||
return
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN_RACHIO,
|
||||
SERVICE_START_MULTIPLE_ZONES,
|
||||
|
@ -176,6 +203,11 @@ def _create_entities(hass: HomeAssistant, config_entry: ConfigEntry) -> list[Ent
|
|||
RachioSchedule(person, controller, schedule, current_schedule)
|
||||
for schedule in schedules + flex_schedules
|
||||
)
|
||||
entities.extend(
|
||||
RachioValve(person, base_station, valve, base_station.coordinator)
|
||||
for base_station in person.base_stations
|
||||
for valve in base_station.coordinator.data.values()
|
||||
)
|
||||
return entities
|
||||
|
||||
|
||||
|
@ -246,9 +278,9 @@ class RachioRainDelay(RachioSwitch):
|
|||
_attr_has_entity_name = True
|
||||
_attr_translation_key = "rain_delay"
|
||||
|
||||
def __init__(self, controller):
|
||||
def __init__(self, controller) -> None:
|
||||
"""Set up a Rachio rain delay switch."""
|
||||
self._cancel_update = None
|
||||
self._cancel_update: CALLBACK_TYPE | None = None
|
||||
super().__init__(controller)
|
||||
|
||||
@property
|
||||
|
@ -324,7 +356,7 @@ class RachioZone(RachioSwitch):
|
|||
|
||||
_attr_icon = "mdi:water"
|
||||
|
||||
def __init__(self, person, controller, data, current_schedule):
|
||||
def __init__(self, person, controller, data, current_schedule) -> None:
|
||||
"""Initialize a new Rachio Zone."""
|
||||
self.id = data[KEY_ID]
|
||||
self._attr_name = data[KEY_NAME]
|
||||
|
@ -379,11 +411,14 @@ class RachioZone(RachioSwitch):
|
|||
self.turn_off()
|
||||
|
||||
# Start this zone
|
||||
manual_run_time = timedelta(
|
||||
minutes=self._person.config_entry.options.get(
|
||||
CONF_MANUAL_RUN_MINS, DEFAULT_MANUAL_RUN_MINS
|
||||
if ATTR_DURATION in kwargs:
|
||||
manual_run_time = timedelta(minutes=kwargs[ATTR_DURATION])
|
||||
else:
|
||||
manual_run_time = timedelta(
|
||||
minutes=self._person.config_entry.options.get(
|
||||
CONF_MANUAL_RUN_MINS, DEFAULT_MANUAL_RUN_MINS
|
||||
)
|
||||
)
|
||||
)
|
||||
# The API limit is 3 hours, and requires an int be passed
|
||||
self._controller.rachio.zone.start(self.zone_id, manual_run_time.seconds)
|
||||
_LOGGER.debug(
|
||||
|
@ -435,7 +470,7 @@ class RachioZone(RachioSwitch):
|
|||
class RachioSchedule(RachioSwitch):
|
||||
"""Representation of one fixed schedule on the Rachio Iro."""
|
||||
|
||||
def __init__(self, person, controller, data, current_schedule):
|
||||
def __init__(self, person, controller, data, current_schedule) -> None:
|
||||
"""Initialize a new Rachio Schedule."""
|
||||
self._schedule_id = data[KEY_ID]
|
||||
self._duration = data[KEY_DURATION]
|
||||
|
@ -509,3 +544,70 @@ class RachioSchedule(RachioSwitch):
|
|||
self.hass, SIGNAL_RACHIO_SCHEDULE_UPDATE, self._async_handle_update
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class RachioValve(CoordinatorEntity[RachioUpdateCoordinator], SwitchEntity):
|
||||
"""Representation of one smart hose timer valve."""
|
||||
|
||||
def __init__(
|
||||
self, person, base, data, coordinator: RachioUpdateCoordinator
|
||||
) -> None:
|
||||
"""Initialize a new smart hose valve."""
|
||||
super().__init__(coordinator)
|
||||
self._person = person
|
||||
self._base = base
|
||||
self.id = data[KEY_ID]
|
||||
self._attr_name = data[KEY_NAME]
|
||||
self._attr_unique_id = f"{self.id}-valve"
|
||||
self._static_attrs = data[KEY_STATE][KEY_REPORTED_STATE]
|
||||
self._attr_is_on = KEY_CURRENT_STATUS in self._static_attrs
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={
|
||||
(
|
||||
DOMAIN_RACHIO,
|
||||
self.id,
|
||||
)
|
||||
},
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, self._base.mac_address)},
|
||||
manufacturer=DEFAULT_NAME,
|
||||
model="Smart Hose Timer",
|
||||
name=self._attr_name,
|
||||
configuration_url="https://app.rach.io",
|
||||
)
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return if the valve is available."""
|
||||
return super().available and self._static_attrs[KEY_CONNECTED]
|
||||
|
||||
def turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn on this valve."""
|
||||
if ATTR_DURATION in kwargs:
|
||||
manual_run_time = timedelta(minutes=kwargs[ATTR_DURATION])
|
||||
else:
|
||||
manual_run_time = timedelta(
|
||||
minutes=self._person.config_entry.options.get(
|
||||
CONF_MANUAL_RUN_MINS, DEFAULT_MANUAL_RUN_MINS
|
||||
)
|
||||
)
|
||||
|
||||
self._base.start_watering(self.id, manual_run_time.seconds)
|
||||
self._attr_is_on = True
|
||||
self.schedule_update_ha_state(force_refresh=True)
|
||||
_LOGGER.debug("Starting valve %s for %s", self.name, str(manual_run_time))
|
||||
|
||||
def turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn off this valve."""
|
||||
self._base.stop_watering(self.id)
|
||||
self._attr_is_on = False
|
||||
self.schedule_update_ha_state(force_refresh=True)
|
||||
_LOGGER.debug("Stopping watering on valve %s", self.name)
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
"""Handle updated coordinator data."""
|
||||
data = self.coordinator.data[self.id]
|
||||
|
||||
self._static_attrs = data[KEY_STATE][KEY_REPORTED_STATE]
|
||||
self._attr_is_on = KEY_CURRENT_STATUS in self._static_attrs
|
||||
super()._handle_coordinator_update()
|
||||
|
|
Loading…
Add table
Reference in a new issue