Add water heater support to SmartThings (#144927)

* Add another EHS SmartThings fixture

* Add another EHS

* Add water heater support to SmartThings

* Add water heater support to SmartThings

* Add water heater support to SmartThings

* Add water heater support to SmartThings

* Fix

* Fix

* Fix

* Fix

* Fix

* Fix

* Fix

* Fix

* Fix

* Add more tests

* Make target temp setting conditional

* Make target temp setting conditional

* Finish tests

* Fix
This commit is contained in:
Joost Lekkerkerker 2025-05-15 17:42:38 +02:00 committed by GitHub
parent d24a60777b
commit d33a0f75fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 1001 additions and 2 deletions

View File

@ -102,6 +102,7 @@ PLATFORMS = [
Platform.SWITCH,
Platform.UPDATE,
Platform.VALVE,
Platform.WATER_HEATER,
]

View File

@ -26,7 +26,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from . import FullDevice, SmartThingsConfigEntry
from .const import MAIN
from .const import MAIN, UNIT_MAP
from .entity import SmartThingsEntity
ATTR_OPERATION_STATE = "operation_state"
@ -90,7 +90,6 @@ FAN_OSCILLATION_TO_SWING = {
WIND = "wind"
WINDFREE = "windFree"
UNIT_MAP = {"C": UnitOfTemperature.CELSIUS, "F": UnitOfTemperature.FAHRENHEIT}
_LOGGER = logging.getLogger(__name__)

View File

@ -2,6 +2,8 @@
from pysmartthings import Attribute, Capability, Category
from homeassistant.const import UnitOfTemperature
DOMAIN = "smartthings"
SCOPES = [
@ -118,3 +120,5 @@ INVALID_SWITCH_CATEGORIES = {
Category.MICROWAVE,
Category.DISHWASHER,
}
UNIT_MAP = {"C": UnitOfTemperature.CELSIUS, "F": UnitOfTemperature.FAHRENHEIT}

View File

@ -530,6 +530,15 @@
"sabbath_mode": {
"name": "Sabbath mode"
}
},
"water_heater": {
"water_heater": {
"state": {
"standard": "Standard",
"force": "Forced",
"power": "Power"
}
}
}
},
"issues": {

View File

@ -0,0 +1,226 @@
"""Support for water heaters through the SmartThings cloud API."""
from __future__ import annotations
from typing import Any
from pysmartthings import Attribute, Capability, Command, SmartThings
from homeassistant.components.water_heater import (
DEFAULT_MAX_TEMP,
DEFAULT_MIN_TEMP,
STATE_ECO,
WaterHeaterEntity,
WaterHeaterEntityFeature,
)
from homeassistant.const import ATTR_TEMPERATURE, STATE_OFF, UnitOfTemperature
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.util.unit_conversion import TemperatureConverter
from . import FullDevice, SmartThingsConfigEntry
from .const import MAIN, UNIT_MAP
from .entity import SmartThingsEntity
OPERATION_MAP_TO_HA: dict[str, str] = {
"eco": STATE_ECO,
"std": "standard",
"force": "force",
"power": "power",
}
HA_TO_OPERATION_MAP = {v: k for k, v in OPERATION_MAP_TO_HA.items()}
async def async_setup_entry(
hass: HomeAssistant,
entry: SmartThingsConfigEntry,
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Add water heaters for a config entry."""
entry_data = entry.runtime_data
async_add_entities(
SmartThingsWaterHeater(entry_data.client, device)
for device in entry_data.devices.values()
if all(
capability in device.status[MAIN]
for capability in (
Capability.SWITCH,
Capability.AIR_CONDITIONER_MODE,
Capability.TEMPERATURE_MEASUREMENT,
Capability.CUSTOM_THERMOSTAT_SETPOINT_CONTROL,
Capability.THERMOSTAT_COOLING_SETPOINT,
Capability.SAMSUNG_CE_EHS_THERMOSTAT,
Capability.CUSTOM_OUTING_MODE,
)
)
)
class SmartThingsWaterHeater(SmartThingsEntity, WaterHeaterEntity):
"""Define a SmartThings Water Heater."""
_attr_name = None
_attr_translation_key = "water_heater"
def __init__(self, client: SmartThings, device: FullDevice) -> None:
"""Init the class."""
super().__init__(
client,
device,
{
Capability.SWITCH,
Capability.AIR_CONDITIONER_MODE,
Capability.TEMPERATURE_MEASUREMENT,
Capability.CUSTOM_THERMOSTAT_SETPOINT_CONTROL,
Capability.THERMOSTAT_COOLING_SETPOINT,
Capability.CUSTOM_OUTING_MODE,
},
)
unit = self._internal_state[Capability.TEMPERATURE_MEASUREMENT][
Attribute.TEMPERATURE
].unit
assert unit is not None
self._attr_temperature_unit = UNIT_MAP[unit]
@property
def supported_features(self) -> WaterHeaterEntityFeature:
"""Return the supported features."""
features = (
WaterHeaterEntityFeature.OPERATION_MODE
| WaterHeaterEntityFeature.AWAY_MODE
| WaterHeaterEntityFeature.ON_OFF
)
if self.get_attribute_value(Capability.SWITCH, Attribute.SWITCH) == "on":
features |= WaterHeaterEntityFeature.TARGET_TEMPERATURE
return features
@property
def min_temp(self) -> float:
"""Return the minimum temperature."""
min_temperature = TemperatureConverter.convert(
DEFAULT_MIN_TEMP, UnitOfTemperature.FAHRENHEIT, self._attr_temperature_unit
)
return min(min_temperature, self.target_temperature_low)
@property
def max_temp(self) -> float:
"""Return the maximum temperature."""
max_temperature = TemperatureConverter.convert(
DEFAULT_MAX_TEMP, UnitOfTemperature.FAHRENHEIT, self._attr_temperature_unit
)
return max(max_temperature, self.target_temperature_high)
@property
def operation_list(self) -> list[str]:
"""Return the list of available operation modes."""
return [
STATE_OFF,
*(
OPERATION_MAP_TO_HA[mode]
for mode in self.get_attribute_value(
Capability.AIR_CONDITIONER_MODE, Attribute.SUPPORTED_AC_MODES
)
if mode in OPERATION_MAP_TO_HA
),
]
@property
def current_operation(self) -> str | None:
"""Return the current operation mode."""
if self.get_attribute_value(Capability.SWITCH, Attribute.SWITCH) == "off":
return STATE_OFF
return OPERATION_MAP_TO_HA.get(
self.get_attribute_value(
Capability.AIR_CONDITIONER_MODE, Attribute.AIR_CONDITIONER_MODE
)
)
@property
def current_temperature(self) -> float | None:
"""Return the current temperature."""
return self.get_attribute_value(
Capability.TEMPERATURE_MEASUREMENT, Attribute.TEMPERATURE
)
@property
def target_temperature(self) -> float | None:
"""Return the target temperature."""
return self.get_attribute_value(
Capability.THERMOSTAT_COOLING_SETPOINT, Attribute.COOLING_SETPOINT
)
@property
def target_temperature_low(self) -> float:
"""Return the minimum temperature."""
return self.get_attribute_value(
Capability.CUSTOM_THERMOSTAT_SETPOINT_CONTROL, Attribute.MINIMUM_SETPOINT
)
@property
def target_temperature_high(self) -> float:
"""Return the maximum temperature."""
return self.get_attribute_value(
Capability.CUSTOM_THERMOSTAT_SETPOINT_CONTROL, Attribute.MAXIMUM_SETPOINT
)
@property
def is_away_mode_on(self) -> bool:
"""Return if away mode is on."""
return (
self.get_attribute_value(
Capability.CUSTOM_OUTING_MODE, Attribute.OUTING_MODE
)
== "on"
)
async def async_set_operation_mode(self, operation_mode: str) -> None:
"""Set new target operation mode."""
if operation_mode == STATE_OFF:
await self.async_turn_off()
return
if self.current_operation == STATE_OFF:
await self.async_turn_on()
await self.execute_device_command(
Capability.AIR_CONDITIONER_MODE,
Command.SET_AIR_CONDITIONER_MODE,
argument=HA_TO_OPERATION_MAP[operation_mode],
)
async def async_set_temperature(self, **kwargs: Any) -> None:
"""Set new target temperature."""
await self.execute_device_command(
Capability.THERMOSTAT_COOLING_SETPOINT,
Command.SET_COOLING_SETPOINT,
argument=kwargs[ATTR_TEMPERATURE],
)
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the water heater on."""
await self.execute_device_command(
Capability.SWITCH,
Command.ON,
)
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the water heater off."""
await self.execute_device_command(
Capability.SWITCH,
Command.OFF,
)
async def async_turn_away_mode_on(self) -> None:
"""Turn away mode on."""
await self.execute_device_command(
Capability.CUSTOM_OUTING_MODE,
Command.SET_OUTING_MODE,
argument="on",
)
async def async_turn_away_mode_off(self) -> None:
"""Turn away mode off."""
await self.execute_device_command(
Capability.CUSTOM_OUTING_MODE,
Command.SET_OUTING_MODE,
argument="off",
)

View File

@ -0,0 +1,218 @@
# serializer version: 1
# name: test_all_entities[da_ac_ehs_01001][water_heater.heat_pump-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'max_temp': 69,
'min_temp': 38,
'operation_list': list([
'off',
'eco',
'standard',
'power',
'force',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'water_heater',
'entity_category': None,
'entity_id': 'water_heater.heat_pump',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': None,
'platform': 'smartthings',
'previous_unique_id': None,
'supported_features': <WaterHeaterEntityFeature: 14>,
'translation_key': 'water_heater',
'unique_id': '4165c51e-bf6b-c5b6-fd53-127d6248754b_main',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[da_ac_ehs_01001][water_heater.heat_pump-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'away_mode': 'off',
'current_temperature': 57,
'friendly_name': 'Heat pump',
'max_temp': 69,
'min_temp': 38,
'operation_list': list([
'off',
'eco',
'standard',
'power',
'force',
]),
'operation_mode': 'off',
'supported_features': <WaterHeaterEntityFeature: 14>,
'target_temp_high': 69,
'target_temp_low': 38,
'temperature': 56,
}),
'context': <ANY>,
'entity_id': 'water_heater.heat_pump',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_all_entities[da_sac_ehs_000001_sub][water_heater.eco_heating_system-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'max_temp': 60.0,
'min_temp': 40,
'operation_list': list([
'off',
'eco',
'standard',
'force',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'water_heater',
'entity_category': None,
'entity_id': 'water_heater.eco_heating_system',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': None,
'platform': 'smartthings',
'previous_unique_id': None,
'supported_features': <WaterHeaterEntityFeature: 14>,
'translation_key': 'water_heater',
'unique_id': '1f98ebd0-ac48-d802-7f62-000001200100_main',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[da_sac_ehs_000001_sub][water_heater.eco_heating_system-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'away_mode': 'off',
'current_temperature': 54.3,
'friendly_name': 'Eco Heating System',
'max_temp': 60.0,
'min_temp': 40,
'operation_list': list([
'off',
'eco',
'standard',
'force',
]),
'operation_mode': 'off',
'supported_features': <WaterHeaterEntityFeature: 14>,
'target_temp_high': 55,
'target_temp_low': 40,
'temperature': 48,
}),
'context': <ANY>,
'entity_id': 'water_heater.eco_heating_system',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_all_entities[da_sac_ehs_000002_sub][water_heater.warmepumpe-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'max_temp': 60.0,
'min_temp': 40,
'operation_list': list([
'off',
'eco',
'standard',
'power',
'force',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'water_heater',
'entity_category': None,
'entity_id': 'water_heater.warmepumpe',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': None,
'platform': 'smartthings',
'previous_unique_id': None,
'supported_features': <WaterHeaterEntityFeature: 15>,
'translation_key': 'water_heater',
'unique_id': '3810e5ad-5351-d9f9-12ff-000001200000_main',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[da_sac_ehs_000002_sub][water_heater.warmepumpe-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'away_mode': 'off',
'current_temperature': 49.6,
'friendly_name': 'Wärmepumpe',
'max_temp': 60.0,
'min_temp': 40,
'operation_list': list([
'off',
'eco',
'standard',
'power',
'force',
]),
'operation_mode': 'standard',
'supported_features': <WaterHeaterEntityFeature: 15>,
'target_temp_high': 57,
'target_temp_low': 40,
'temperature': 52,
}),
'context': <ANY>,
'entity_id': 'water_heater.warmepumpe',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'standard',
})
# ---

View File

@ -0,0 +1,542 @@
"""Test for the SmartThings water heater platform."""
from unittest.mock import AsyncMock, call
from pysmartthings import Attribute, Capability, Command
from pysmartthings.models import HealthStatus
import pytest
from syrupy import SnapshotAssertion
from homeassistant.components.smartthings import MAIN
from homeassistant.components.water_heater import (
ATTR_AWAY_MODE,
ATTR_CURRENT_TEMPERATURE,
ATTR_OPERATION_LIST,
ATTR_OPERATION_MODE,
ATTR_TARGET_TEMP_HIGH,
ATTR_TARGET_TEMP_LOW,
DOMAIN as WATER_HEATER_DOMAIN,
SERVICE_SET_AWAY_MODE,
SERVICE_SET_OPERATION_MODE,
SERVICE_SET_TEMPERATURE,
STATE_ECO,
WaterHeaterEntityFeature,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
ATTR_TEMPERATURE,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
STATE_OFF,
STATE_ON,
STATE_UNAVAILABLE,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from . import (
setup_integration,
snapshot_smartthings_entities,
trigger_health_update,
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.WATER_HEATER
)
@pytest.mark.parametrize("device_fixture", ["da_sac_ehs_000002_sub"])
@pytest.mark.parametrize(
("operation_mode", "argument"),
[
(STATE_ECO, "eco"),
("standard", "std"),
("force", "force"),
("power", "power"),
],
)
async def test_set_operation_mode(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
operation_mode: str,
argument: str,
) -> None:
"""Test set operation mode."""
await setup_integration(hass, mock_config_entry)
await hass.services.async_call(
WATER_HEATER_DOMAIN,
SERVICE_SET_OPERATION_MODE,
{
ATTR_ENTITY_ID: "water_heater.warmepumpe",
ATTR_OPERATION_MODE: operation_mode,
},
blocking=True,
)
devices.execute_device_command.assert_called_once_with(
"3810e5ad-5351-d9f9-12ff-000001200000",
Capability.AIR_CONDITIONER_MODE,
Command.SET_AIR_CONDITIONER_MODE,
MAIN,
argument=argument,
)
@pytest.mark.parametrize("device_fixture", ["da_sac_ehs_000002_sub"])
async def test_set_operation_mode_off(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test set operation mode to off."""
await setup_integration(hass, mock_config_entry)
await hass.services.async_call(
WATER_HEATER_DOMAIN,
SERVICE_SET_OPERATION_MODE,
{
ATTR_ENTITY_ID: "water_heater.warmepumpe",
ATTR_OPERATION_MODE: STATE_OFF,
},
blocking=True,
)
devices.execute_device_command.assert_called_once_with(
"3810e5ad-5351-d9f9-12ff-000001200000",
Capability.SWITCH,
Command.OFF,
MAIN,
)
@pytest.mark.parametrize("device_fixture", ["da_sac_ehs_000001_sub"])
async def test_set_operation_mode_from_off(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test set operation mode."""
await setup_integration(hass, mock_config_entry)
assert hass.states.get("water_heater.eco_heating_system").state == STATE_OFF
await hass.services.async_call(
WATER_HEATER_DOMAIN,
SERVICE_SET_OPERATION_MODE,
{
ATTR_ENTITY_ID: "water_heater.eco_heating_system",
ATTR_OPERATION_MODE: STATE_ECO,
},
blocking=True,
)
assert devices.execute_device_command.mock_calls == [
call(
"1f98ebd0-ac48-d802-7f62-000001200100",
Capability.SWITCH,
Command.ON,
MAIN,
),
call(
"1f98ebd0-ac48-d802-7f62-000001200100",
Capability.AIR_CONDITIONER_MODE,
Command.SET_AIR_CONDITIONER_MODE,
MAIN,
argument="eco",
),
]
@pytest.mark.parametrize("device_fixture", ["da_sac_ehs_000002_sub"])
async def test_set_operation_to_off(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test set operation mode to off."""
await setup_integration(hass, mock_config_entry)
await hass.services.async_call(
WATER_HEATER_DOMAIN,
SERVICE_SET_OPERATION_MODE,
{
ATTR_ENTITY_ID: "water_heater.warmepumpe",
ATTR_OPERATION_MODE: STATE_OFF,
},
blocking=True,
)
devices.execute_device_command.assert_called_once_with(
"3810e5ad-5351-d9f9-12ff-000001200000",
Capability.SWITCH,
Command.OFF,
MAIN,
)
@pytest.mark.parametrize("device_fixture", ["da_sac_ehs_000002_sub"])
@pytest.mark.parametrize(
("service", "command"),
[
(SERVICE_TURN_ON, Command.ON),
(SERVICE_TURN_OFF, Command.OFF),
],
)
async def test_turn_on_off(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
service: str,
command: Command,
) -> None:
"""Test turn on and off."""
await setup_integration(hass, mock_config_entry)
await hass.services.async_call(
WATER_HEATER_DOMAIN,
service,
{
ATTR_ENTITY_ID: "water_heater.warmepumpe",
},
blocking=True,
)
devices.execute_device_command.assert_called_once_with(
"3810e5ad-5351-d9f9-12ff-000001200000",
Capability.SWITCH,
command,
MAIN,
)
@pytest.mark.parametrize("device_fixture", ["da_sac_ehs_000002_sub"])
async def test_set_temperature(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test set operation mode."""
await setup_integration(hass, mock_config_entry)
await hass.services.async_call(
WATER_HEATER_DOMAIN,
SERVICE_SET_TEMPERATURE,
{
ATTR_ENTITY_ID: "water_heater.warmepumpe",
ATTR_TEMPERATURE: 56,
},
blocking=True,
)
devices.execute_device_command.assert_called_once_with(
"3810e5ad-5351-d9f9-12ff-000001200000",
Capability.THERMOSTAT_COOLING_SETPOINT,
Command.SET_COOLING_SETPOINT,
MAIN,
argument=56,
)
@pytest.mark.parametrize("device_fixture", ["da_sac_ehs_000002_sub"])
@pytest.mark.parametrize(
("on", "argument"),
[
(True, "on"),
(False, "off"),
],
)
async def test_away_mode(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
on: bool,
argument: str,
) -> None:
"""Test set away mode."""
await setup_integration(hass, mock_config_entry)
await hass.services.async_call(
WATER_HEATER_DOMAIN,
SERVICE_SET_AWAY_MODE,
{
ATTR_ENTITY_ID: "water_heater.warmepumpe",
ATTR_AWAY_MODE: on,
},
blocking=True,
)
devices.execute_device_command.assert_called_once_with(
"3810e5ad-5351-d9f9-12ff-000001200000",
Capability.CUSTOM_OUTING_MODE,
Command.SET_OUTING_MODE,
MAIN,
argument=argument,
)
@pytest.mark.parametrize("device_fixture", ["da_sac_ehs_000002_sub"])
async def test_operation_list_update(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test state update."""
await setup_integration(hass, mock_config_entry)
assert hass.states.get("water_heater.warmepumpe").attributes[
ATTR_OPERATION_LIST
] == [
STATE_OFF,
STATE_ECO,
"standard",
"power",
"force",
]
await trigger_update(
hass,
devices,
"3810e5ad-5351-d9f9-12ff-000001200000",
Capability.AIR_CONDITIONER_MODE,
Attribute.SUPPORTED_AC_MODES,
["eco", "force", "power"],
)
assert hass.states.get("water_heater.warmepumpe").attributes[
ATTR_OPERATION_LIST
] == [
STATE_OFF,
STATE_ECO,
"force",
"power",
]
@pytest.mark.parametrize("device_fixture", ["da_sac_ehs_000002_sub"])
async def test_current_operation_update(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test state update."""
await setup_integration(hass, mock_config_entry)
assert hass.states.get("water_heater.warmepumpe").state == "standard"
await trigger_update(
hass,
devices,
"3810e5ad-5351-d9f9-12ff-000001200000",
Capability.AIR_CONDITIONER_MODE,
Attribute.AIR_CONDITIONER_MODE,
"eco",
)
assert hass.states.get("water_heater.warmepumpe").state == STATE_ECO
@pytest.mark.parametrize("device_fixture", ["da_sac_ehs_000002_sub"])
async def test_switch_update(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test state update."""
await setup_integration(hass, mock_config_entry)
state = hass.states.get("water_heater.warmepumpe")
assert state.state == "standard"
assert (
state.attributes[ATTR_SUPPORTED_FEATURES]
== WaterHeaterEntityFeature.ON_OFF
| WaterHeaterEntityFeature.TARGET_TEMPERATURE
| WaterHeaterEntityFeature.OPERATION_MODE
| WaterHeaterEntityFeature.AWAY_MODE
)
await trigger_update(
hass,
devices,
"3810e5ad-5351-d9f9-12ff-000001200000",
Capability.SWITCH,
Attribute.SWITCH,
"off",
)
state = hass.states.get("water_heater.warmepumpe")
assert state.state == STATE_OFF
assert (
state.attributes[ATTR_SUPPORTED_FEATURES]
== WaterHeaterEntityFeature.ON_OFF
| WaterHeaterEntityFeature.OPERATION_MODE
| WaterHeaterEntityFeature.AWAY_MODE
)
@pytest.mark.parametrize("device_fixture", ["da_sac_ehs_000002_sub"])
async def test_current_temperature_update(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test state update."""
await setup_integration(hass, mock_config_entry)
assert (
hass.states.get("water_heater.warmepumpe").attributes[ATTR_CURRENT_TEMPERATURE]
== 49.6
)
await trigger_update(
hass,
devices,
"3810e5ad-5351-d9f9-12ff-000001200000",
Capability.TEMPERATURE_MEASUREMENT,
Attribute.TEMPERATURE,
50.0,
)
assert (
hass.states.get("water_heater.warmepumpe").attributes[ATTR_CURRENT_TEMPERATURE]
== 50.0
)
@pytest.mark.parametrize("device_fixture", ["da_sac_ehs_000002_sub"])
async def test_target_temperature_update(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test state update."""
await setup_integration(hass, mock_config_entry)
assert (
hass.states.get("water_heater.warmepumpe").attributes[ATTR_TEMPERATURE] == 52.0
)
await trigger_update(
hass,
devices,
"3810e5ad-5351-d9f9-12ff-000001200000",
Capability.THERMOSTAT_COOLING_SETPOINT,
Attribute.COOLING_SETPOINT,
50.0,
)
assert (
hass.states.get("water_heater.warmepumpe").attributes[ATTR_TEMPERATURE] == 50.0
)
@pytest.mark.parametrize("device_fixture", ["da_sac_ehs_000002_sub"])
@pytest.mark.parametrize(
("attribute", "old_value", "state_attribute"),
[
(Attribute.MINIMUM_SETPOINT, 40, ATTR_TARGET_TEMP_LOW),
(Attribute.MAXIMUM_SETPOINT, 57, ATTR_TARGET_TEMP_HIGH),
],
)
async def test_target_temperature_bound_update(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
attribute: Attribute,
old_value: float,
state_attribute: str,
) -> None:
"""Test state update."""
await setup_integration(hass, mock_config_entry)
assert (
hass.states.get("water_heater.warmepumpe").attributes[state_attribute]
== old_value
)
await trigger_update(
hass,
devices,
"3810e5ad-5351-d9f9-12ff-000001200000",
Capability.CUSTOM_THERMOSTAT_SETPOINT_CONTROL,
attribute,
50.0,
)
assert (
hass.states.get("water_heater.warmepumpe").attributes[state_attribute] == 50.0
)
@pytest.mark.parametrize("device_fixture", ["da_sac_ehs_000002_sub"])
async def test_away_mode_update(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test state update."""
await setup_integration(hass, mock_config_entry)
assert (
hass.states.get("water_heater.warmepumpe").attributes[ATTR_AWAY_MODE]
== STATE_OFF
)
await trigger_update(
hass,
devices,
"3810e5ad-5351-d9f9-12ff-000001200000",
Capability.CUSTOM_OUTING_MODE,
Attribute.OUTING_MODE,
"on",
)
assert (
hass.states.get("water_heater.warmepumpe").attributes[ATTR_AWAY_MODE]
== STATE_ON
)
@pytest.mark.parametrize("device_fixture", ["da_sac_ehs_000002_sub"])
async def test_availability(
hass: HomeAssistant,
devices: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test availability."""
await setup_integration(hass, mock_config_entry)
assert hass.states.get("water_heater.warmepumpe").state == "standard"
await trigger_health_update(
hass, devices, "3810e5ad-5351-d9f9-12ff-000001200000", HealthStatus.OFFLINE
)
assert hass.states.get("water_heater.warmepumpe").state == STATE_UNAVAILABLE
await trigger_health_update(
hass, devices, "3810e5ad-5351-d9f9-12ff-000001200000", HealthStatus.ONLINE
)
assert hass.states.get("water_heater.warmepumpe").state == "standard"
@pytest.mark.parametrize("device_fixture", ["da_sac_ehs_000002_sub"])
async def test_availability_at_start(
hass: HomeAssistant,
unavailable_device: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test unavailable at boot."""
await setup_integration(hass, mock_config_entry)
assert hass.states.get("water_heater.warmepumpe").state == STATE_UNAVAILABLE