Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add valve support to Hydrawise #116302

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion homeassistant/components/hydrawise/__init__.py
Expand Up @@ -10,7 +10,12 @@
from .const import DOMAIN, SCAN_INTERVAL
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:
Expand Down
66 changes: 66 additions & 0 deletions homeassistant/components/hydrawise/valve.py
@@ -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
99 changes: 99 additions & 0 deletions tests/components/hydrawise/snapshots/test_valve.ambr
@@ -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',
})
# ---
59 changes: 59 additions & 0 deletions tests/components/hydrawise/test_valve.py
@@ -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])