Add valve support to Hydrawise (#116302)

This commit is contained in:
David Knowles 2024-07-07 14:42:45 -04:00 committed by GitHub
parent 12228d8a00
commit 72458d143d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 230 additions and 1 deletions

View File

@ -10,7 +10,12 @@ from homeassistant.exceptions import ConfigEntryAuthFailed
from .const import DOMAIN, SCAN_INTERVAL from .const import DOMAIN, SCAN_INTERVAL
from .coordinator import HydrawiseDataUpdateCoordinator from .coordinator import HydrawiseDataUpdateCoordinator
PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR, Platform.SWITCH] PLATFORMS: list[Platform] = [
Platform.BINARY_SENSOR,
Platform.SENSOR,
Platform.SWITCH,
Platform.VALVE,
]
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:

View File

@ -0,0 +1,66 @@
"""Support for Hydrawise sprinkler valves."""
from __future__ import annotations
from typing import Any
from pydrawise.schema import Zone
from homeassistant.components.valve import (
ValveDeviceClass,
ValveEntity,
ValveEntityDescription,
ValveEntityFeature,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN
from .coordinator import HydrawiseDataUpdateCoordinator
from .entity import HydrawiseEntity
VALVE_TYPES: tuple[ValveEntityDescription, ...] = (
ValveEntityDescription(
key="zone",
device_class=ValveDeviceClass.WATER,
),
)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the Hydrawise valve platform."""
coordinator: HydrawiseDataUpdateCoordinator = hass.data[DOMAIN][
config_entry.entry_id
]
async_add_entities(
HydrawiseValve(coordinator, description, controller, zone_id=zone.id)
for controller in coordinator.data.controllers.values()
for zone in controller.zones
for description in VALVE_TYPES
)
class HydrawiseValve(HydrawiseEntity, ValveEntity):
"""A Hydrawise valve."""
_attr_name = None
_attr_reports_position = False
_attr_supported_features = ValveEntityFeature.OPEN | ValveEntityFeature.CLOSE
zone: Zone
async def async_open_valve(self, **kwargs: Any) -> None:
"""Open the valve."""
await self.coordinator.api.start_zone(self.zone)
async def async_close_valve(self) -> None:
"""Close the valve."""
await self.coordinator.api.stop_zone(self.zone)
def _update_attrs(self) -> None:
"""Update state attributes."""
self._attr_is_closed = self.zone.scheduled_runs.current_run is None

View File

@ -0,0 +1,99 @@
# serializer version: 1
# name: test_all_valves[valve.zone_one-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'valve',
'entity_category': None,
'entity_id': 'valve.zone_one',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <ValveDeviceClass.WATER: 'water'>,
'original_icon': None,
'original_name': None,
'platform': 'hydrawise',
'previous_unique_id': None,
'supported_features': <ValveEntityFeature: 3>,
'translation_key': None,
'unique_id': '5965394_zone',
'unit_of_measurement': None,
})
# ---
# name: test_all_valves[valve.zone_one-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by hydrawise.com',
'device_class': 'water',
'friendly_name': 'Zone One',
'supported_features': <ValveEntityFeature: 3>,
}),
'context': <ANY>,
'entity_id': 'valve.zone_one',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'closed',
})
# ---
# name: test_all_valves[valve.zone_two-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'valve',
'entity_category': None,
'entity_id': 'valve.zone_two',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <ValveDeviceClass.WATER: 'water'>,
'original_icon': None,
'original_name': None,
'platform': 'hydrawise',
'previous_unique_id': None,
'supported_features': <ValveEntityFeature: 3>,
'translation_key': None,
'unique_id': '5965395_zone',
'unit_of_measurement': None,
})
# ---
# name: test_all_valves[valve.zone_two-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by hydrawise.com',
'device_class': 'water',
'friendly_name': 'Zone Two',
'supported_features': <ValveEntityFeature: 3>,
}),
'context': <ANY>,
'entity_id': 'valve.zone_two',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'open',
})
# ---

View File

@ -0,0 +1,59 @@
"""Test Hydrawise valve."""
from collections.abc import Awaitable, Callable
from unittest.mock import AsyncMock, patch
from pydrawise.schema import Zone
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.valve import DOMAIN
from homeassistant.const import (
ATTR_ENTITY_ID,
SERVICE_CLOSE_VALVE,
SERVICE_OPEN_VALVE,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from tests.common import MockConfigEntry, snapshot_platform
async def test_all_valves(
hass: HomeAssistant,
mock_add_config_entry: Callable[[], Awaitable[MockConfigEntry]],
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Test that all valves are working."""
with patch(
"homeassistant.components.hydrawise.PLATFORMS",
[Platform.VALVE],
):
config_entry = await mock_add_config_entry()
await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id)
async def test_services(
hass: HomeAssistant,
mock_added_config_entry: MockConfigEntry,
mock_pydrawise: AsyncMock,
zones: list[Zone],
) -> None:
"""Test valve services."""
await hass.services.async_call(
DOMAIN,
SERVICE_OPEN_VALVE,
service_data={ATTR_ENTITY_ID: "valve.zone_one"},
blocking=True,
)
mock_pydrawise.start_zone.assert_called_once_with(zones[0])
mock_pydrawise.reset_mock()
await hass.services.async_call(
DOMAIN,
SERVICE_CLOSE_VALVE,
service_data={ATTR_ENTITY_ID: "valve.zone_one"},
blocking=True,
)
mock_pydrawise.stop_zone.assert_called_once_with(zones[0])