mirror of
https://github.com/home-assistant/core.git
synced 2026-09-10 23:51:49 +01:00
Move Rachio services to async_setup (#175479)
This commit is contained in:
@@ -10,9 +10,12 @@ from homeassistant.components import cloud
|
||||
from homeassistant.const import CONF_API_KEY, CONF_WEBHOOK_ID, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from .const import CONF_CLOUDHOOK_URL, CONF_MANUAL_RUN_MINS
|
||||
from .const import CONF_CLOUDHOOK_URL, CONF_MANUAL_RUN_MINS, DOMAIN
|
||||
from .device import RachioConfigEntry, RachioPerson
|
||||
from .services import async_setup_services
|
||||
from .webhooks import (
|
||||
async_get_or_create_registered_webhook_id_and_url,
|
||||
async_register_webhook,
|
||||
@@ -23,6 +26,14 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
PLATFORMS = [Platform.BINARY_SENSOR, Platform.CALENDAR, Platform.SWITCH]
|
||||
|
||||
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Set up the Rachio integration."""
|
||||
async_setup_services(hass)
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: RachioConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
|
||||
@@ -5,16 +5,13 @@ import logging
|
||||
from typing import Any, override
|
||||
|
||||
from rachiopy import Rachio
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.core import HomeAssistant, ServiceCall
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
KEY_BASE_STATIONS,
|
||||
KEY_DEVICES,
|
||||
KEY_ENABLED,
|
||||
@@ -30,31 +27,14 @@ from .const import (
|
||||
KEY_USERNAME,
|
||||
KEY_ZONES,
|
||||
LISTEN_EVENT_TYPES,
|
||||
MODEL_GENERATION_1,
|
||||
SERVICE_PAUSE_WATERING,
|
||||
SERVICE_RESUME_WATERING,
|
||||
SERVICE_STOP_WATERING,
|
||||
WEBHOOK_CONST_ID,
|
||||
)
|
||||
from .coordinator import RachioScheduleUpdateCoordinator, RachioUpdateCoordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ATTR_DEVICES = "devices"
|
||||
ATTR_DURATION = "duration"
|
||||
PERMISSION_ERROR = "7"
|
||||
|
||||
PAUSE_SERVICE_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Optional(ATTR_DEVICES): cv.string,
|
||||
vol.Optional(ATTR_DURATION, default=60): cv.positive_int,
|
||||
}
|
||||
)
|
||||
|
||||
RESUME_SERVICE_SCHEMA = vol.Schema({vol.Optional(ATTR_DEVICES): cv.string})
|
||||
|
||||
STOP_SERVICE_SCHEMA = vol.Schema({vol.Optional(ATTR_DEVICES): cv.string})
|
||||
|
||||
type RachioConfigEntry = ConfigEntry[RachioPerson]
|
||||
|
||||
|
||||
@@ -72,66 +52,8 @@ class RachioPerson:
|
||||
self._base_stations: list[RachioBaseStation] = []
|
||||
|
||||
async def async_setup(self, hass: HomeAssistant) -> None:
|
||||
"""Create rachio devices and services."""
|
||||
"""Create rachio devices."""
|
||||
await hass.async_add_executor_job(self._setup, hass)
|
||||
can_pause = False
|
||||
for rachio_iro in self._controllers:
|
||||
# Generation 1 controllers don't support pause or resume
|
||||
if rachio_iro.model.split("_")[0] != MODEL_GENERATION_1:
|
||||
can_pause = True
|
||||
break
|
||||
|
||||
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_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_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_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,
|
||||
stop_water,
|
||||
schema=STOP_SERVICE_SCHEMA,
|
||||
)
|
||||
|
||||
if not can_pause:
|
||||
return
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_PAUSE_WATERING,
|
||||
pause_water,
|
||||
schema=PAUSE_SERVICE_SCHEMA,
|
||||
)
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_RESUME_WATERING,
|
||||
resume_water,
|
||||
schema=RESUME_SERVICE_SCHEMA,
|
||||
)
|
||||
|
||||
def _setup(self, hass: HomeAssistant) -> None:
|
||||
"""Rachio device setup."""
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
"""Services for the Rachio integration."""
|
||||
|
||||
import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.const import ATTR_ENTITY_ID, ATTR_ID, Platform
|
||||
from homeassistant.core import HomeAssistant, ServiceCall, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import (
|
||||
config_validation as cv,
|
||||
entity_registry as er,
|
||||
service,
|
||||
)
|
||||
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
KEY_ID,
|
||||
MODEL_GENERATION_1,
|
||||
SERVICE_PAUSE_WATERING,
|
||||
SERVICE_RESUME_WATERING,
|
||||
SERVICE_START_MULTIPLE_ZONES,
|
||||
SERVICE_STOP_WATERING,
|
||||
)
|
||||
from .device import RachioConfigEntry
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ATTR_DEVICES = "devices"
|
||||
ATTR_DURATION = "duration"
|
||||
ATTR_SORT_ORDER = "sortOrder"
|
||||
|
||||
PAUSE_SERVICE_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Optional(ATTR_DEVICES): cv.string,
|
||||
vol.Optional(ATTR_DURATION, default=60): cv.positive_int,
|
||||
}
|
||||
)
|
||||
|
||||
RESUME_SERVICE_SCHEMA = vol.Schema({vol.Optional(ATTR_DEVICES): cv.string})
|
||||
|
||||
START_MULTIPLE_ZONES_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_ids,
|
||||
vol.Required(ATTR_DURATION): cv.ensure_list_csv,
|
||||
}
|
||||
)
|
||||
|
||||
STOP_SERVICE_SCHEMA = vol.Schema({vol.Optional(ATTR_DEVICES): cv.string})
|
||||
|
||||
|
||||
def _stop_water(call: ServiceCall) -> None:
|
||||
"""Stop watering on all or specific controllers."""
|
||||
entry: RachioConfigEntry = service.async_get_config_entry(call.hass, DOMAIN, None)
|
||||
person = entry.runtime_data
|
||||
devices = call.data.get(ATTR_DEVICES, [iro.name for iro in person.controllers])
|
||||
for iro in person.controllers:
|
||||
if iro.name in devices:
|
||||
iro.stop_watering()
|
||||
|
||||
|
||||
def _pause_water(call: ServiceCall) -> None:
|
||||
"""Pause watering on all or specific controllers."""
|
||||
entry: RachioConfigEntry = service.async_get_config_entry(call.hass, DOMAIN, None)
|
||||
person = entry.runtime_data
|
||||
devices = call.data.get(ATTR_DEVICES, [iro.name for iro in person.controllers])
|
||||
for iro in person.controllers:
|
||||
if iro.name in devices and iro.model.split("_")[0] != MODEL_GENERATION_1:
|
||||
iro.pause_watering(call.data[ATTR_DURATION])
|
||||
|
||||
|
||||
def _resume_water(call: ServiceCall) -> None:
|
||||
"""Resume watering on all or specific controllers."""
|
||||
entry: RachioConfigEntry = service.async_get_config_entry(call.hass, DOMAIN, None)
|
||||
person = entry.runtime_data
|
||||
devices = call.data.get(ATTR_DEVICES, [iro.name for iro in person.controllers])
|
||||
for iro in person.controllers:
|
||||
if iro.name in devices and iro.model.split("_")[0] != MODEL_GENERATION_1:
|
||||
iro.resume_watering()
|
||||
|
||||
|
||||
def _start_multiple(call: ServiceCall) -> None:
|
||||
"""Start multiple zones in sequence."""
|
||||
entry: RachioConfigEntry = service.async_get_config_entry(call.hass, DOMAIN, None)
|
||||
person = entry.runtime_data
|
||||
entity_reg = er.async_get(call.hass)
|
||||
duration = iter(call.data[ATTR_DURATION])
|
||||
default_time = call.data[ATTR_DURATION][0]
|
||||
|
||||
entity_to_zone_id = {
|
||||
entity_reg.async_get_entity_id(
|
||||
Platform.SWITCH,
|
||||
DOMAIN,
|
||||
f"{controller.controller_id}-zone-{zone[KEY_ID]}",
|
||||
): zone[KEY_ID]
|
||||
for controller in person.controllers
|
||||
for zone in controller.list_zones()
|
||||
}
|
||||
|
||||
zones_list = [
|
||||
{
|
||||
ATTR_ID: entity_to_zone_id[entity_id],
|
||||
ATTR_DURATION: int(next(duration, default_time)) * 60,
|
||||
ATTR_SORT_ORDER: count,
|
||||
}
|
||||
for count, entity_id in enumerate(call.data[ATTR_ENTITY_ID])
|
||||
if entity_id in entity_to_zone_id
|
||||
]
|
||||
|
||||
if not zones_list:
|
||||
raise HomeAssistantError("No matching zones found in given entity_ids")
|
||||
|
||||
person.start_multiple_zones(zones_list)
|
||||
_LOGGER.debug("Starting zone(s) %s", call.data[ATTR_ENTITY_ID])
|
||||
|
||||
|
||||
@callback
|
||||
def async_setup_services(hass: HomeAssistant) -> None:
|
||||
"""Register Rachio services."""
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_STOP_WATERING, _stop_water, schema=STOP_SERVICE_SCHEMA
|
||||
)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_PAUSE_WATERING, _pause_water, schema=PAUSE_SERVICE_SCHEMA
|
||||
)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_RESUME_WATERING, _resume_water, schema=RESUME_SERVICE_SCHEMA
|
||||
)
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_START_MULTIPLE_ZONES,
|
||||
_start_multiple,
|
||||
schema=START_MULTIPLE_ZONES_SCHEMA,
|
||||
)
|
||||
@@ -9,9 +9,7 @@ from typing import Any, override
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.const import ATTR_ENTITY_ID, ATTR_ID
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, ServiceCall, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
|
||||
from homeassistant.helpers import config_validation as cv, entity_platform
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity import Entity
|
||||
@@ -22,7 +20,6 @@ from homeassistant.util.dt import as_timestamp, now, parse_datetime, utc_from_ti
|
||||
from .const import (
|
||||
CONF_MANUAL_RUN_MINS,
|
||||
DEFAULT_MANUAL_RUN_MINS,
|
||||
DOMAIN,
|
||||
KEY_CURRENT_STATUS,
|
||||
KEY_CUSTOM_CROP,
|
||||
KEY_CUSTOM_SHADE,
|
||||
@@ -45,7 +42,6 @@ from .const import (
|
||||
SCHEDULE_TYPE_FIXED,
|
||||
SCHEDULE_TYPE_FLEX,
|
||||
SERVICE_SET_ZONE_MOISTURE,
|
||||
SERVICE_START_MULTIPLE_ZONES,
|
||||
SERVICE_START_WATERING,
|
||||
SIGNAL_RACHIO_CONTROLLER_UPDATE,
|
||||
SIGNAL_RACHIO_RAIN_DELAY_UPDATE,
|
||||
@@ -80,7 +76,6 @@ ATTR_SCHEDULE_SUMMARY = "Summary"
|
||||
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"
|
||||
@@ -88,13 +83,6 @@ ATTR_ZONE_SLOPE = "Slope"
|
||||
ATTR_ZONE_SUMMARY = "Summary"
|
||||
ATTR_ZONE_TYPE = "Type"
|
||||
|
||||
START_MULTIPLE_ZONES_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(ATTR_ENTITY_ID): cv.entity_ids,
|
||||
vol.Required(ATTR_DURATION): cv.ensure_list_csv,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
@@ -102,47 +90,14 @@ async def async_setup_entry(
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Rachio switches."""
|
||||
zone_entities = []
|
||||
has_flex_sched = False
|
||||
entities = await hass.async_add_executor_job(_create_entities, hass, config_entry)
|
||||
for entity in entities:
|
||||
if isinstance(entity, RachioZone):
|
||||
zone_entities.append(entity)
|
||||
if isinstance(entity, RachioSchedule) and entity.type == SCHEDULE_TYPE_FLEX:
|
||||
has_flex_sched = True
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
def start_multiple(service: ServiceCall) -> None:
|
||||
"""Service to start multiple zones in sequence."""
|
||||
zones_list = []
|
||||
person = config_entry.runtime_data
|
||||
entity_id = service.data[ATTR_ENTITY_ID]
|
||||
duration = iter(service.data[ATTR_DURATION])
|
||||
default_time = service.data[ATTR_DURATION][0]
|
||||
entity_to_zone_id = {
|
||||
entity.entity_id: entity.zone_id for entity in zone_entities
|
||||
}
|
||||
|
||||
for count, data in enumerate(entity_id):
|
||||
if data in entity_to_zone_id:
|
||||
# Time can be passed as a list per zone,
|
||||
# or one time for all zones
|
||||
time = int(next(duration, default_time)) * 60
|
||||
zones_list.append(
|
||||
{
|
||||
ATTR_ID: entity_to_zone_id.get(data),
|
||||
ATTR_DURATION: time,
|
||||
ATTR_SORT_ORDER: count,
|
||||
}
|
||||
)
|
||||
|
||||
if len(zones_list) != 0:
|
||||
person.start_multiple_zones(zones_list)
|
||||
_LOGGER.debug("Starting zone(s) %s", entity_id)
|
||||
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,
|
||||
@@ -152,18 +107,6 @@ async def async_setup_entry(
|
||||
"turn_on",
|
||||
)
|
||||
|
||||
# If only hose timers on account, none of these services apply
|
||||
if not zone_entities:
|
||||
return
|
||||
|
||||
# pylint: disable-next=home-assistant-service-registered-in-setup-entry
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_START_MULTIPLE_ZONES,
|
||||
start_multiple,
|
||||
schema=START_MULTIPLE_ZONES_SCHEMA,
|
||||
)
|
||||
|
||||
if has_flex_sched:
|
||||
platform = entity_platform.async_get_current_platform()
|
||||
platform.async_register_entity_service(
|
||||
|
||||
Reference in New Issue
Block a user