Add valve platform to SmartThings (#140195)

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* Refactor SmartThings

* fix

* fix

* Add AC tests

* Add thermostat tests

* Add cover tests

* Add device tests

* Add light tests

* Add rest of the tests

* Add valve

* Add oauth

* Add oauth tests

* Add oauth tests

* Add oauth tests

* Add oauth tests

* Bump version

* Add rest of the tests

* Finalize

* Finalize

* Finalize

* Finalize

* Finalize

* Finalize

* Finalize

* Finalize

* Finalize

* Finalize

* Finalize

* Fix

* Fix
This commit is contained in:
Joost Lekkerkerker 2025-03-15 20:28:51 +01:00 committed by GitHub
parent bff73ee5f8
commit 43898d7845
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 211 additions and 0 deletions

View File

@ -79,6 +79,7 @@ PLATFORMS = [
Platform.SCENE,
Platform.SENSOR,
Platform.SWITCH,
Platform.VALVE,
]

View File

@ -0,0 +1,73 @@
"""Support for valves through the SmartThings cloud API."""
from __future__ import annotations
from pysmartthings import Attribute, Capability, Category, Command, SmartThings
from homeassistant.components.valve import (
ValveDeviceClass,
ValveEntity,
ValveEntityFeature,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import FullDevice, SmartThingsConfigEntry
from .const import MAIN
from .entity import SmartThingsEntity
DEVICE_CLASS_MAP: dict[Category | str, ValveDeviceClass] = {
Category.WATER_VALVE: ValveDeviceClass.WATER,
Category.GAS_VALVE: ValveDeviceClass.GAS,
}
async def async_setup_entry(
hass: HomeAssistant,
entry: SmartThingsConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Add valves for a config entry."""
entry_data = entry.runtime_data
async_add_entities(
SmartThingsValve(entry_data.client, entry_data.rooms, device)
for device in entry_data.devices.values()
if Capability.VALVE in device.status[MAIN]
)
class SmartThingsValve(SmartThingsEntity, ValveEntity):
"""Define a SmartThings valve."""
_attr_supported_features = ValveEntityFeature.OPEN | ValveEntityFeature.CLOSE
_attr_reports_position = False
_attr_name = None
def __init__(
self, client: SmartThings, rooms: dict[str, str], device: FullDevice
) -> None:
"""Init the class."""
super().__init__(client, device, rooms, {Capability.VALVE})
self._attr_device_class = DEVICE_CLASS_MAP.get(
device.device.components[0].user_category
or device.device.components[0].manufacturer_category
)
async def async_open_valve(self) -> None:
"""Open the valve."""
await self.execute_device_command(
Capability.VALVE,
Command.OPEN,
)
async def async_close_valve(self) -> None:
"""Close the valve."""
await self.execute_device_command(
Capability.VALVE,
Command.CLOSE,
)
@property
def is_closed(self) -> bool:
"""Return if the valve is closed."""
return self.get_attribute_value(Capability.VALVE, Attribute.VALVE) == "closed"

View File

@ -0,0 +1,50 @@
# serializer version: 1
# name: test_all_entities[virtual_valve][valve.volvo-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'valve',
'entity_category': None,
'entity_id': 'valve.volvo',
'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': 'smartthings',
'previous_unique_id': None,
'supported_features': <ValveEntityFeature: 3>,
'translation_key': None,
'unique_id': '612ab3c2-3bb0-48f7-b2c0-15b169cb2fc3',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[virtual_valve][valve.volvo-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'water',
'friendly_name': 'volvo',
'supported_features': <ValveEntityFeature: 3>,
}),
'context': <ANY>,
'entity_id': 'valve.volvo',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'closed',
})
# ---

View File

@ -0,0 +1,87 @@
"""Test for the SmartThings valve platform."""
from unittest.mock import AsyncMock
from pysmartthings import Attribute, Capability, Command
import pytest
from syrupy import SnapshotAssertion
from homeassistant.components.smartthings import MAIN
from homeassistant.components.valve import DOMAIN as VALVE_DOMAIN, ValveState
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 . import setup_integration, snapshot_smartthings_entities, trigger_update
from tests.common import MockConfigEntry
async def test_all_entities(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
) -> None:
"""Test all entities."""
await setup_integration(hass, mock_config_entry)
snapshot_smartthings_entities(hass, entity_registry, snapshot, Platform.VALVE)
@pytest.mark.parametrize("device_fixture", ["virtual_valve"])
@pytest.mark.parametrize(
("action", "command"),
[
(SERVICE_OPEN_VALVE, Command.OPEN),
(SERVICE_CLOSE_VALVE, Command.CLOSE),
],
)
async def test_valve_open_close(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
action: str,
command: Command,
) -> None:
"""Test valve open and close command."""
await setup_integration(hass, mock_config_entry)
await hass.services.async_call(
VALVE_DOMAIN,
action,
{ATTR_ENTITY_ID: "valve.volvo"},
blocking=True,
)
devices.execute_device_command.assert_called_once_with(
"612ab3c2-3bb0-48f7-b2c0-15b169cb2fc3", Capability.VALVE, command, MAIN
)
@pytest.mark.parametrize("device_fixture", ["virtual_valve"])
async def test_state_update(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test state update."""
await setup_integration(hass, mock_config_entry)
assert hass.states.get("valve.volvo").state == ValveState.CLOSED
await trigger_update(
hass,
devices,
"612ab3c2-3bb0-48f7-b2c0-15b169cb2fc3",
Capability.VALVE,
Attribute.VALVE,
"open",
)
assert hass.states.get("valve.volvo").state == ValveState.OPEN