Implement mode validation in Climate entity component (#105745)
* Implement mode validation in Climate entity component * Fix some tests * more tests * Fix translations * fix deconz tests * Fix switcher_kis tests * not None * Fix homematicip_cloud test * Always validate * Fix shelly * reverse logic in validation * modes_str --------- Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
e04fda3fad
commit
83f4d3af5c
21 changed files with 342 additions and 77 deletions
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import functools as ft
|
import functools as ft
|
||||||
import logging
|
import logging
|
||||||
from typing import TYPE_CHECKING, Any, final
|
from typing import TYPE_CHECKING, Any, Literal, final
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
|
@ -19,7 +19,8 @@ from homeassistant.const import (
|
||||||
STATE_ON,
|
STATE_ON,
|
||||||
UnitOfTemperature,
|
UnitOfTemperature,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, ServiceCall
|
from homeassistant.core import HomeAssistant, ServiceCall, callback
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.config_validation import ( # noqa: F401
|
from homeassistant.helpers.config_validation import ( # noqa: F401
|
||||||
PLATFORM_SCHEMA,
|
PLATFORM_SCHEMA,
|
||||||
|
@ -166,7 +167,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
component.async_register_entity_service(
|
component.async_register_entity_service(
|
||||||
SERVICE_SET_PRESET_MODE,
|
SERVICE_SET_PRESET_MODE,
|
||||||
{vol.Required(ATTR_PRESET_MODE): cv.string},
|
{vol.Required(ATTR_PRESET_MODE): cv.string},
|
||||||
"async_set_preset_mode",
|
"async_handle_set_preset_mode_service",
|
||||||
[ClimateEntityFeature.PRESET_MODE],
|
[ClimateEntityFeature.PRESET_MODE],
|
||||||
)
|
)
|
||||||
component.async_register_entity_service(
|
component.async_register_entity_service(
|
||||||
|
@ -193,13 +194,13 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||||
component.async_register_entity_service(
|
component.async_register_entity_service(
|
||||||
SERVICE_SET_FAN_MODE,
|
SERVICE_SET_FAN_MODE,
|
||||||
{vol.Required(ATTR_FAN_MODE): cv.string},
|
{vol.Required(ATTR_FAN_MODE): cv.string},
|
||||||
"async_set_fan_mode",
|
"async_handle_set_fan_mode_service",
|
||||||
[ClimateEntityFeature.FAN_MODE],
|
[ClimateEntityFeature.FAN_MODE],
|
||||||
)
|
)
|
||||||
component.async_register_entity_service(
|
component.async_register_entity_service(
|
||||||
SERVICE_SET_SWING_MODE,
|
SERVICE_SET_SWING_MODE,
|
||||||
{vol.Required(ATTR_SWING_MODE): cv.string},
|
{vol.Required(ATTR_SWING_MODE): cv.string},
|
||||||
"async_set_swing_mode",
|
"async_handle_set_swing_mode_service",
|
||||||
[ClimateEntityFeature.SWING_MODE],
|
[ClimateEntityFeature.SWING_MODE],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -515,6 +516,35 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
||||||
"""
|
"""
|
||||||
return self._attr_swing_modes
|
return self._attr_swing_modes
|
||||||
|
|
||||||
|
@final
|
||||||
|
@callback
|
||||||
|
def _valid_mode_or_raise(
|
||||||
|
self,
|
||||||
|
mode_type: Literal["preset", "swing", "fan"],
|
||||||
|
mode: str,
|
||||||
|
modes: list[str] | None,
|
||||||
|
) -> None:
|
||||||
|
"""Raise ServiceValidationError on invalid modes."""
|
||||||
|
if modes and mode in modes:
|
||||||
|
return
|
||||||
|
modes_str: str = ", ".join(modes) if modes else ""
|
||||||
|
if mode_type == "preset":
|
||||||
|
translation_key = "not_valid_preset_mode"
|
||||||
|
elif mode_type == "swing":
|
||||||
|
translation_key = "not_valid_swing_mode"
|
||||||
|
elif mode_type == "fan":
|
||||||
|
translation_key = "not_valid_fan_mode"
|
||||||
|
raise ServiceValidationError(
|
||||||
|
f"The {mode_type}_mode {mode} is not a valid {mode_type}_mode:"
|
||||||
|
f" {modes_str}",
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key=translation_key,
|
||||||
|
translation_placeholders={
|
||||||
|
"mode": mode,
|
||||||
|
"modes": modes_str,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
def set_temperature(self, **kwargs: Any) -> None:
|
def set_temperature(self, **kwargs: Any) -> None:
|
||||||
"""Set new target temperature."""
|
"""Set new target temperature."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -533,6 +563,12 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
||||||
"""Set new target humidity."""
|
"""Set new target humidity."""
|
||||||
await self.hass.async_add_executor_job(self.set_humidity, humidity)
|
await self.hass.async_add_executor_job(self.set_humidity, humidity)
|
||||||
|
|
||||||
|
@final
|
||||||
|
async def async_handle_set_fan_mode_service(self, fan_mode: str) -> None:
|
||||||
|
"""Validate and set new preset mode."""
|
||||||
|
self._valid_mode_or_raise("fan", fan_mode, self.fan_modes)
|
||||||
|
await self.async_set_fan_mode(fan_mode)
|
||||||
|
|
||||||
def set_fan_mode(self, fan_mode: str) -> None:
|
def set_fan_mode(self, fan_mode: str) -> None:
|
||||||
"""Set new target fan mode."""
|
"""Set new target fan mode."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -549,6 +585,12 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
||||||
"""Set new target hvac mode."""
|
"""Set new target hvac mode."""
|
||||||
await self.hass.async_add_executor_job(self.set_hvac_mode, hvac_mode)
|
await self.hass.async_add_executor_job(self.set_hvac_mode, hvac_mode)
|
||||||
|
|
||||||
|
@final
|
||||||
|
async def async_handle_set_swing_mode_service(self, swing_mode: str) -> None:
|
||||||
|
"""Validate and set new preset mode."""
|
||||||
|
self._valid_mode_or_raise("swing", swing_mode, self.swing_modes)
|
||||||
|
await self.async_set_swing_mode(swing_mode)
|
||||||
|
|
||||||
def set_swing_mode(self, swing_mode: str) -> None:
|
def set_swing_mode(self, swing_mode: str) -> None:
|
||||||
"""Set new target swing operation."""
|
"""Set new target swing operation."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
@ -557,6 +599,12 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
||||||
"""Set new target swing operation."""
|
"""Set new target swing operation."""
|
||||||
await self.hass.async_add_executor_job(self.set_swing_mode, swing_mode)
|
await self.hass.async_add_executor_job(self.set_swing_mode, swing_mode)
|
||||||
|
|
||||||
|
@final
|
||||||
|
async def async_handle_set_preset_mode_service(self, preset_mode: str) -> None:
|
||||||
|
"""Validate and set new preset mode."""
|
||||||
|
self._valid_mode_or_raise("preset", preset_mode, self.preset_modes)
|
||||||
|
await self.async_set_preset_mode(preset_mode)
|
||||||
|
|
||||||
def set_preset_mode(self, preset_mode: str) -> None:
|
def set_preset_mode(self, preset_mode: str) -> None:
|
||||||
"""Set new preset mode."""
|
"""Set new preset mode."""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
|
@ -233,5 +233,16 @@
|
||||||
"heat": "Heat"
|
"heat": "Heat"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"exceptions": {
|
||||||
|
"not_valid_preset_mode": {
|
||||||
|
"message": "Preset mode {mode} is not valid. Valid preset modes are: {modes}."
|
||||||
|
},
|
||||||
|
"not_valid_swing_mode": {
|
||||||
|
"message": "Swing mode {mode} is not valid. Valid swing modes are: {modes}."
|
||||||
|
},
|
||||||
|
"not_valid_fan_mode": {
|
||||||
|
"message": "Fan mode {mode} is not valid. Valid fan modes are: {modes}."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,7 @@ async def async_setup_entry(
|
||||||
target_temperature=None,
|
target_temperature=None,
|
||||||
unit_of_measurement=UnitOfTemperature.CELSIUS,
|
unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||||
preset="home",
|
preset="home",
|
||||||
preset_modes=["home", "eco"],
|
preset_modes=["home", "eco", "away"],
|
||||||
current_temperature=23,
|
current_temperature=23,
|
||||||
fan_mode="Auto Low",
|
fan_mode="Auto Low",
|
||||||
target_humidity=None,
|
target_humidity=None,
|
||||||
|
|
|
@ -26,6 +26,7 @@ from homeassistant.components.climate import (
|
||||||
)
|
)
|
||||||
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
|
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
|
||||||
from homeassistant.core import HomeAssistant, State
|
from homeassistant.core import HomeAssistant, State
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
|
|
||||||
from . import init_integration
|
from . import init_integration
|
||||||
|
|
||||||
|
@ -146,7 +147,7 @@ async def test_spa_preset_modes(
|
||||||
assert state
|
assert state
|
||||||
assert state.attributes[ATTR_PRESET_MODE] == mode
|
assert state.attributes[ATTR_PRESET_MODE] == mode
|
||||||
|
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(ServiceValidationError):
|
||||||
await common.async_set_preset_mode(hass, 2, ENTITY_CLIMATE)
|
await common.async_set_preset_mode(hass, 2, ENTITY_CLIMATE)
|
||||||
|
|
||||||
# put it in RNR and test assertion
|
# put it in RNR and test assertion
|
||||||
|
|
22
tests/components/climate/conftest.py
Normal file
22
tests/components/climate/conftest.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
"""Fixtures for Climate platform tests."""
|
||||||
|
from collections.abc import Generator
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.config_entries import ConfigFlow
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
from tests.common import mock_config_flow, mock_platform
|
||||||
|
|
||||||
|
|
||||||
|
class MockFlow(ConfigFlow):
|
||||||
|
"""Test flow."""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def config_flow_fixture(hass: HomeAssistant) -> Generator[None, None, None]:
|
||||||
|
"""Mock config flow."""
|
||||||
|
mock_platform(hass, "test.config_flow")
|
||||||
|
|
||||||
|
with mock_config_flow("test", MockFlow):
|
||||||
|
yield
|
|
@ -10,16 +10,36 @@ import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components import climate
|
from homeassistant.components import climate
|
||||||
from homeassistant.components.climate import (
|
from homeassistant.components.climate import (
|
||||||
|
DOMAIN,
|
||||||
SET_TEMPERATURE_SCHEMA,
|
SET_TEMPERATURE_SCHEMA,
|
||||||
ClimateEntity,
|
ClimateEntity,
|
||||||
HVACMode,
|
HVACMode,
|
||||||
)
|
)
|
||||||
|
from homeassistant.components.climate.const import (
|
||||||
|
ATTR_FAN_MODE,
|
||||||
|
ATTR_PRESET_MODE,
|
||||||
|
ATTR_SWING_MODE,
|
||||||
|
SERVICE_SET_FAN_MODE,
|
||||||
|
SERVICE_SET_PRESET_MODE,
|
||||||
|
SERVICE_SET_SWING_MODE,
|
||||||
|
ClimateEntityFeature,
|
||||||
|
)
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.const import UnitOfTemperature
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from tests.common import (
|
from tests.common import (
|
||||||
|
MockConfigEntry,
|
||||||
|
MockEntity,
|
||||||
|
MockModule,
|
||||||
|
MockPlatform,
|
||||||
async_mock_service,
|
async_mock_service,
|
||||||
import_and_test_deprecated_constant,
|
import_and_test_deprecated_constant,
|
||||||
import_and_test_deprecated_constant_enum,
|
import_and_test_deprecated_constant_enum,
|
||||||
|
mock_integration,
|
||||||
|
mock_platform,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,9 +77,22 @@ async def test_set_temp_schema(
|
||||||
assert calls[-1].data == data
|
assert calls[-1].data == data
|
||||||
|
|
||||||
|
|
||||||
class MockClimateEntity(ClimateEntity):
|
class MockClimateEntity(MockEntity, ClimateEntity):
|
||||||
"""Mock Climate device to use in tests."""
|
"""Mock Climate device to use in tests."""
|
||||||
|
|
||||||
|
_attr_supported_features = (
|
||||||
|
ClimateEntityFeature.FAN_MODE
|
||||||
|
| ClimateEntityFeature.PRESET_MODE
|
||||||
|
| ClimateEntityFeature.SWING_MODE
|
||||||
|
)
|
||||||
|
_attr_preset_mode = "home"
|
||||||
|
_attr_preset_modes = ["home", "away"]
|
||||||
|
_attr_fan_mode = "auto"
|
||||||
|
_attr_fan_modes = ["auto", "off"]
|
||||||
|
_attr_swing_mode = "auto"
|
||||||
|
_attr_swing_modes = ["auto", "off"]
|
||||||
|
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hvac_mode(self) -> HVACMode:
|
def hvac_mode(self) -> HVACMode:
|
||||||
"""Return hvac operation ie. heat, cool mode.
|
"""Return hvac operation ie. heat, cool mode.
|
||||||
|
@ -82,6 +115,18 @@ class MockClimateEntity(ClimateEntity):
|
||||||
def turn_off(self) -> None:
|
def turn_off(self) -> None:
|
||||||
"""Turn off."""
|
"""Turn off."""
|
||||||
|
|
||||||
|
def set_preset_mode(self, preset_mode: str) -> None:
|
||||||
|
"""Set preset mode."""
|
||||||
|
self._attr_preset_mode = preset_mode
|
||||||
|
|
||||||
|
def set_fan_mode(self, fan_mode: str) -> None:
|
||||||
|
"""Set fan mode."""
|
||||||
|
self._attr_fan_mode = fan_mode
|
||||||
|
|
||||||
|
def set_swing_mode(self, swing_mode: str) -> None:
|
||||||
|
"""Set swing mode."""
|
||||||
|
self._attr_swing_mode = swing_mode
|
||||||
|
|
||||||
|
|
||||||
async def test_sync_turn_on(hass: HomeAssistant) -> None:
|
async def test_sync_turn_on(hass: HomeAssistant) -> None:
|
||||||
"""Test if async turn_on calls sync turn_on."""
|
"""Test if async turn_on calls sync turn_on."""
|
||||||
|
@ -158,3 +203,133 @@ def test_deprecated_current_constants(
|
||||||
enum,
|
enum,
|
||||||
"2025.1",
|
"2025.1",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_preset_mode_validation(
|
||||||
|
hass: HomeAssistant, config_flow_fixture: None
|
||||||
|
) -> None:
|
||||||
|
"""Test mode validation for fan, swing and preset."""
|
||||||
|
|
||||||
|
async def async_setup_entry_init(
|
||||||
|
hass: HomeAssistant, config_entry: ConfigEntry
|
||||||
|
) -> bool:
|
||||||
|
"""Set up test config entry."""
|
||||||
|
await hass.config_entries.async_forward_entry_setups(config_entry, [DOMAIN])
|
||||||
|
return True
|
||||||
|
|
||||||
|
async def async_setup_entry_climate_platform(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up test climate platform via config entry."""
|
||||||
|
async_add_entities([MockClimateEntity(name="test", entity_id="climate.test")])
|
||||||
|
|
||||||
|
mock_integration(
|
||||||
|
hass,
|
||||||
|
MockModule(
|
||||||
|
"test",
|
||||||
|
async_setup_entry=async_setup_entry_init,
|
||||||
|
),
|
||||||
|
built_in=False,
|
||||||
|
)
|
||||||
|
mock_platform(
|
||||||
|
hass,
|
||||||
|
"test.climate",
|
||||||
|
MockPlatform(async_setup_entry=async_setup_entry_climate_platform),
|
||||||
|
)
|
||||||
|
|
||||||
|
config_entry = MockConfigEntry(domain="test")
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("climate.test")
|
||||||
|
assert state.attributes.get(ATTR_PRESET_MODE) == "home"
|
||||||
|
assert state.attributes.get(ATTR_FAN_MODE) == "auto"
|
||||||
|
assert state.attributes.get(ATTR_SWING_MODE) == "auto"
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SET_PRESET_MODE,
|
||||||
|
{
|
||||||
|
"entity_id": "climate.test",
|
||||||
|
"preset_mode": "away",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SET_SWING_MODE,
|
||||||
|
{
|
||||||
|
"entity_id": "climate.test",
|
||||||
|
"swing_mode": "off",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SET_FAN_MODE,
|
||||||
|
{
|
||||||
|
"entity_id": "climate.test",
|
||||||
|
"fan_mode": "off",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
state = hass.states.get("climate.test")
|
||||||
|
assert state.attributes.get(ATTR_PRESET_MODE) == "away"
|
||||||
|
assert state.attributes.get(ATTR_FAN_MODE) == "off"
|
||||||
|
assert state.attributes.get(ATTR_SWING_MODE) == "off"
|
||||||
|
|
||||||
|
with pytest.raises(
|
||||||
|
ServiceValidationError,
|
||||||
|
match="The preset_mode invalid is not a valid preset_mode: home, away",
|
||||||
|
) as exc:
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SET_PRESET_MODE,
|
||||||
|
{
|
||||||
|
"entity_id": "climate.test",
|
||||||
|
"preset_mode": "invalid",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
str(exc.value)
|
||||||
|
== "The preset_mode invalid is not a valid preset_mode: home, away"
|
||||||
|
)
|
||||||
|
assert exc.value.translation_key == "not_valid_preset_mode"
|
||||||
|
|
||||||
|
with pytest.raises(
|
||||||
|
ServiceValidationError,
|
||||||
|
match="The swing_mode invalid is not a valid swing_mode: auto, off",
|
||||||
|
) as exc:
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SET_SWING_MODE,
|
||||||
|
{
|
||||||
|
"entity_id": "climate.test",
|
||||||
|
"swing_mode": "invalid",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
str(exc.value) == "The swing_mode invalid is not a valid swing_mode: auto, off"
|
||||||
|
)
|
||||||
|
assert exc.value.translation_key == "not_valid_swing_mode"
|
||||||
|
|
||||||
|
with pytest.raises(
|
||||||
|
ServiceValidationError,
|
||||||
|
match="The fan_mode invalid is not a valid fan_mode: auto, off",
|
||||||
|
) as exc:
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_SET_FAN_MODE,
|
||||||
|
{
|
||||||
|
"entity_id": "climate.test",
|
||||||
|
"fan_mode": "invalid",
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert str(exc.value) == "The fan_mode invalid is not a valid fan_mode: auto, off"
|
||||||
|
assert exc.value.translation_key == "not_valid_fan_mode"
|
||||||
|
|
|
@ -41,6 +41,7 @@ from homeassistant.const import (
|
||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
|
|
||||||
from .test_gateway import (
|
from .test_gateway import (
|
||||||
DECONZ_WEB_REQUEST,
|
DECONZ_WEB_REQUEST,
|
||||||
|
@ -602,7 +603,7 @@ async def test_climate_device_with_fan_support(
|
||||||
|
|
||||||
# Service set fan mode to unsupported value
|
# Service set fan mode to unsupported value
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ServiceValidationError):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_FAN_MODE,
|
SERVICE_SET_FAN_MODE,
|
||||||
|
@ -725,7 +726,7 @@ async def test_climate_device_with_preset(
|
||||||
|
|
||||||
# Service set preset to unsupported value
|
# Service set preset to unsupported value
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ServiceValidationError):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_PRESET_MODE,
|
SERVICE_SET_PRESET_MODE,
|
||||||
|
|
|
@ -278,12 +278,12 @@ async def test_set_fan_mode(hass: HomeAssistant) -> None:
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_SET_FAN_MODE,
|
SERVICE_SET_FAN_MODE,
|
||||||
{ATTR_ENTITY_ID: ENTITY_CLIMATE, ATTR_FAN_MODE: "On Low"},
|
{ATTR_ENTITY_ID: ENTITY_CLIMATE, ATTR_FAN_MODE: "on_low"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
state = hass.states.get(ENTITY_CLIMATE)
|
state = hass.states.get(ENTITY_CLIMATE)
|
||||||
assert state.attributes.get(ATTR_FAN_MODE) == "On Low"
|
assert state.attributes.get(ATTR_FAN_MODE) == "on_low"
|
||||||
|
|
||||||
|
|
||||||
async def test_set_swing_mode_bad_attr(hass: HomeAssistant) -> None:
|
async def test_set_swing_mode_bad_attr(hass: HomeAssistant) -> None:
|
||||||
|
@ -311,12 +311,12 @@ async def test_set_swing(hass: HomeAssistant) -> None:
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_SET_SWING_MODE,
|
SERVICE_SET_SWING_MODE,
|
||||||
{ATTR_ENTITY_ID: ENTITY_CLIMATE, ATTR_SWING_MODE: "Auto"},
|
{ATTR_ENTITY_ID: ENTITY_CLIMATE, ATTR_SWING_MODE: "auto"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
state = hass.states.get(ENTITY_CLIMATE)
|
state = hass.states.get(ENTITY_CLIMATE)
|
||||||
assert state.attributes.get(ATTR_SWING_MODE) == "Auto"
|
assert state.attributes.get(ATTR_SWING_MODE) == "auto"
|
||||||
|
|
||||||
|
|
||||||
async def test_set_hvac_bad_attr_and_state(hass: HomeAssistant) -> None:
|
async def test_set_hvac_bad_attr_and_state(hass: HomeAssistant) -> None:
|
||||||
|
|
|
@ -41,6 +41,7 @@ from homeassistant.core import (
|
||||||
State,
|
State,
|
||||||
callback,
|
callback,
|
||||||
)
|
)
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
@ -388,7 +389,7 @@ async def test_set_preset_mode_invalid(hass: HomeAssistant, setup_comp_2) -> Non
|
||||||
await common.async_set_preset_mode(hass, "none")
|
await common.async_set_preset_mode(hass, "none")
|
||||||
state = hass.states.get(ENTITY)
|
state = hass.states.get(ENTITY)
|
||||||
assert state.attributes.get("preset_mode") == "none"
|
assert state.attributes.get("preset_mode") == "none"
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ServiceValidationError):
|
||||||
await common.async_set_preset_mode(hass, "Sleep")
|
await common.async_set_preset_mode(hass, "Sleep")
|
||||||
state = hass.states.get(ENTITY)
|
state = hass.states.get(ENTITY)
|
||||||
assert state.attributes.get("preset_mode") == "none"
|
assert state.attributes.get("preset_mode") == "none"
|
||||||
|
|
|
@ -50,6 +50,7 @@ from homeassistant.const import (
|
||||||
UnitOfTemperature,
|
UnitOfTemperature,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
|
@ -538,7 +539,7 @@ async def test_send_invalid_preset_mode(
|
||||||
"""Test for sending preset mode command to the device."""
|
"""Test for sending preset mode command to the device."""
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass)
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ServiceValidationError):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_SET_PRESET_MODE,
|
SERVICE_SET_PRESET_MODE,
|
||||||
|
@ -699,7 +700,7 @@ async def test_send_invalid_fan_mode(
|
||||||
"""Test for sending fan mode command to the device."""
|
"""Test for sending fan mode command to the device."""
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass)
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ServiceValidationError):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_SET_FAN_MODE,
|
SERVICE_SET_FAN_MODE,
|
||||||
|
@ -780,7 +781,7 @@ async def test_send_invalid_swing_mode(
|
||||||
"""Test for sending swing mode command to the device."""
|
"""Test for sending swing mode command to the device."""
|
||||||
await async_setup_gree(hass)
|
await async_setup_gree(hass)
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ServiceValidationError):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
SERVICE_SET_SWING_MODE,
|
SERVICE_SET_SWING_MODE,
|
||||||
|
|
|
@ -3,6 +3,7 @@ import datetime
|
||||||
|
|
||||||
from homematicip.base.enums import AbsenceType
|
from homematicip.base.enums import AbsenceType
|
||||||
from homematicip.functionalHomes import IndoorClimateHome
|
from homematicip.functionalHomes import IndoorClimateHome
|
||||||
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.climate import (
|
from homeassistant.components.climate import (
|
||||||
ATTR_CURRENT_TEMPERATURE,
|
ATTR_CURRENT_TEMPERATURE,
|
||||||
|
@ -23,6 +24,7 @@ from homeassistant.components.homematicip_cloud.climate import (
|
||||||
PERMANENT_END_TIME,
|
PERMANENT_END_TIME,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from .helper import HAPID, async_manipulate_test_data, get_and_check_entity_basics
|
from .helper import HAPID, async_manipulate_test_data, get_and_check_entity_basics
|
||||||
|
@ -340,12 +342,13 @@ async def test_hmip_heating_group_cool(
|
||||||
assert ha_state.attributes[ATTR_PRESET_MODE] == "none"
|
assert ha_state.attributes[ATTR_PRESET_MODE] == "none"
|
||||||
assert ha_state.attributes[ATTR_PRESET_MODES] == []
|
assert ha_state.attributes[ATTR_PRESET_MODES] == []
|
||||||
|
|
||||||
await hass.services.async_call(
|
with pytest.raises(ServiceValidationError):
|
||||||
"climate",
|
await hass.services.async_call(
|
||||||
"set_preset_mode",
|
"climate",
|
||||||
{"entity_id": entity_id, "preset_mode": "Cool2"},
|
"set_preset_mode",
|
||||||
blocking=True,
|
{"entity_id": entity_id, "preset_mode": "Cool2"},
|
||||||
)
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
assert len(hmip_device.mock_calls) == service_call_counter + 12
|
assert len(hmip_device.mock_calls) == service_call_counter + 12
|
||||||
# fire_update_event shows that set_active_profile has not been called.
|
# fire_update_event shows that set_active_profile has not been called.
|
||||||
|
|
|
@ -50,6 +50,7 @@ from homeassistant.const import (
|
||||||
ATTR_TEMPERATURE,
|
ATTR_TEMPERATURE,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
from homeassistant.util import utcnow
|
from homeassistant.util import utcnow
|
||||||
|
|
||||||
|
@ -370,7 +371,7 @@ async def test_thermostat_set_invalid_preset(
|
||||||
hass: HomeAssistant, cube: MaxCube, thermostat: MaxThermostat
|
hass: HomeAssistant, cube: MaxCube, thermostat: MaxThermostat
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set hvac mode to heat."""
|
"""Set hvac mode to heat."""
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ServiceValidationError):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_PRESET_MODE,
|
SERVICE_SET_PRESET_MODE,
|
||||||
|
|
|
@ -33,6 +33,7 @@ from homeassistant.components.mqtt.climate import (
|
||||||
)
|
)
|
||||||
from homeassistant.const import ATTR_TEMPERATURE, Platform, UnitOfTemperature
|
from homeassistant.const import ATTR_TEMPERATURE, Platform, UnitOfTemperature
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
|
|
||||||
from .test_common import (
|
from .test_common import (
|
||||||
help_custom_config,
|
help_custom_config,
|
||||||
|
@ -1130,8 +1131,9 @@ async def test_set_preset_mode_optimistic(
|
||||||
state = hass.states.get(ENTITY_CLIMATE)
|
state = hass.states.get(ENTITY_CLIMATE)
|
||||||
assert state.attributes.get("preset_mode") == "comfort"
|
assert state.attributes.get("preset_mode") == "comfort"
|
||||||
|
|
||||||
await common.async_set_preset_mode(hass, "invalid", ENTITY_CLIMATE)
|
with pytest.raises(ServiceValidationError):
|
||||||
assert "'invalid' is not a valid preset mode" in caplog.text
|
await common.async_set_preset_mode(hass, "invalid", ENTITY_CLIMATE)
|
||||||
|
assert "'invalid' is not a valid preset mode" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
@ -1187,8 +1189,9 @@ async def test_set_preset_mode_explicit_optimistic(
|
||||||
state = hass.states.get(ENTITY_CLIMATE)
|
state = hass.states.get(ENTITY_CLIMATE)
|
||||||
assert state.attributes.get("preset_mode") == "comfort"
|
assert state.attributes.get("preset_mode") == "comfort"
|
||||||
|
|
||||||
await common.async_set_preset_mode(hass, "invalid", ENTITY_CLIMATE)
|
with pytest.raises(ServiceValidationError):
|
||||||
assert "'invalid' is not a valid preset mode" in caplog.text
|
await common.async_set_preset_mode(hass, "invalid", ENTITY_CLIMATE)
|
||||||
|
assert "'invalid' is not a valid preset mode" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
|
|
@ -39,7 +39,7 @@ from homeassistant.const import (
|
||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||||
|
|
||||||
from .common import (
|
from .common import (
|
||||||
DEVICE_COMMAND,
|
DEVICE_COMMAND,
|
||||||
|
@ -1192,7 +1192,7 @@ async def test_thermostat_invalid_fan_mode(
|
||||||
assert thermostat.attributes[ATTR_FAN_MODE] == FAN_ON
|
assert thermostat.attributes[ATTR_FAN_MODE] == FAN_ON
|
||||||
assert thermostat.attributes[ATTR_FAN_MODES] == [FAN_ON, FAN_OFF]
|
assert thermostat.attributes[ATTR_FAN_MODES] == [FAN_ON, FAN_OFF]
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ServiceValidationError):
|
||||||
await common.async_set_fan_mode(hass, FAN_LOW)
|
await common.async_set_fan_mode(hass, FAN_LOW)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
@ -1474,7 +1474,7 @@ async def test_thermostat_invalid_set_preset_mode(
|
||||||
assert thermostat.attributes[ATTR_PRESET_MODES] == [PRESET_ECO, PRESET_NONE]
|
assert thermostat.attributes[ATTR_PRESET_MODES] == [PRESET_ECO, PRESET_NONE]
|
||||||
|
|
||||||
# Set preset mode that is invalid
|
# Set preset mode that is invalid
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ServiceValidationError):
|
||||||
await common.async_set_preset_mode(hass, PRESET_SLEEP)
|
await common.async_set_preset_mode(hass, PRESET_SLEEP)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ from homeassistant.components.netatmo.const import (
|
||||||
)
|
)
|
||||||
from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE, CONF_WEBHOOK_ID
|
from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE, CONF_WEBHOOK_ID
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from .common import selected_platforms, simulate_webhook
|
from .common import selected_platforms, simulate_webhook
|
||||||
|
@ -879,15 +880,14 @@ async def test_service_preset_mode_invalid(
|
||||||
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
await hass.services.async_call(
|
with pytest.raises(ServiceValidationError):
|
||||||
CLIMATE_DOMAIN,
|
await hass.services.async_call(
|
||||||
SERVICE_SET_PRESET_MODE,
|
CLIMATE_DOMAIN,
|
||||||
{ATTR_ENTITY_ID: "climate.cocina", ATTR_PRESET_MODE: "invalid"},
|
SERVICE_SET_PRESET_MODE,
|
||||||
blocking=True,
|
{ATTR_ENTITY_ID: "climate.cocina", ATTR_PRESET_MODE: "invalid"},
|
||||||
)
|
blocking=True,
|
||||||
await hass.async_block_till_done()
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
assert "Preset mode 'invalid' not available" in caplog.text
|
|
||||||
|
|
||||||
|
|
||||||
async def test_valves_service_turn_off(
|
async def test_valves_service_turn_off(
|
||||||
|
|
|
@ -1330,10 +1330,7 @@ async def test_climate_fan_mode_and_swing_mode_not_supported(
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
|
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
|
||||||
), pytest.raises(
|
), pytest.raises(ServiceValidationError):
|
||||||
HomeAssistantError,
|
|
||||||
match="Climate swing mode faulty_swing_mode is not supported by the integration, please open an issue",
|
|
||||||
):
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_SWING_MODE,
|
SERVICE_SET_SWING_MODE,
|
||||||
|
@ -1343,10 +1340,7 @@ async def test_climate_fan_mode_and_swing_mode_not_supported(
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
|
"homeassistant.components.sensibo.util.SensiboClient.async_set_ac_state_property",
|
||||||
), pytest.raises(
|
), pytest.raises(ServiceValidationError):
|
||||||
HomeAssistantError,
|
|
||||||
match="Climate fan mode faulty_fan_mode is not supported by the integration, please open an issue",
|
|
||||||
):
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_FAN_MODE,
|
SERVICE_SET_FAN_MODE,
|
||||||
|
|
|
@ -25,7 +25,7 @@ from homeassistant.components.shelly.const import DOMAIN, MODEL_WALL_DISPLAY
|
||||||
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState
|
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState
|
||||||
from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE, STATE_UNAVAILABLE
|
from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE, STATE_UNAVAILABLE
|
||||||
from homeassistant.core import HomeAssistant, State
|
from homeassistant.core import HomeAssistant, State
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
import homeassistant.helpers.issue_registry as ir
|
import homeassistant.helpers.issue_registry as ir
|
||||||
from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
|
from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
|
||||||
|
@ -382,12 +382,13 @@ async def test_block_restored_climate_set_preset_before_online(
|
||||||
|
|
||||||
assert hass.states.get(entity_id).state == HVACMode.HEAT
|
assert hass.states.get(entity_id).state == HVACMode.HEAT
|
||||||
|
|
||||||
await hass.services.async_call(
|
with pytest.raises(ServiceValidationError):
|
||||||
CLIMATE_DOMAIN,
|
await hass.services.async_call(
|
||||||
SERVICE_SET_PRESET_MODE,
|
CLIMATE_DOMAIN,
|
||||||
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_PRESET_MODE: "Profile1"},
|
SERVICE_SET_PRESET_MODE,
|
||||||
blocking=True,
|
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_PRESET_MODE: "Profile1"},
|
||||||
)
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
mock_block_device.http_request.assert_not_called()
|
mock_block_device.http_request.assert_not_called()
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ from homeassistant.components.climate import (
|
||||||
)
|
)
|
||||||
from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE, STATE_UNAVAILABLE
|
from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE, STATE_UNAVAILABLE
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
|
|
||||||
from . import init_integration
|
from . import init_integration
|
||||||
|
@ -336,9 +336,8 @@ async def test_climate_control_errors(
|
||||||
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_TEMPERATURE: 24},
|
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_TEMPERATURE: 24},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Test exception when trying set fan level
|
# Test exception when trying set fan level
|
||||||
with pytest.raises(HomeAssistantError):
|
with pytest.raises(ServiceValidationError):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_FAN_MODE,
|
SERVICE_SET_FAN_MODE,
|
||||||
|
@ -347,7 +346,7 @@ async def test_climate_control_errors(
|
||||||
)
|
)
|
||||||
|
|
||||||
# Test exception when trying set swing mode
|
# Test exception when trying set swing mode
|
||||||
with pytest.raises(HomeAssistantError):
|
with pytest.raises(ServiceValidationError):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_SWING_MODE,
|
SERVICE_SET_SWING_MODE,
|
||||||
|
|
|
@ -43,6 +43,7 @@ from homeassistant.const import (
|
||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
|
||||||
from . import init_integration
|
from . import init_integration
|
||||||
|
@ -337,7 +338,7 @@ async def test_service_calls(
|
||||||
|
|
||||||
mock_instance.set_fanspeed.reset_mock()
|
mock_instance.set_fanspeed.reset_mock()
|
||||||
# FAN_MIDDLE is not supported
|
# FAN_MIDDLE is not supported
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ServiceValidationError):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_FAN_MODE,
|
SERVICE_SET_FAN_MODE,
|
||||||
|
|
|
@ -52,7 +52,7 @@ from homeassistant.const import (
|
||||||
Platform,
|
Platform,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||||
|
|
||||||
from .common import async_enable_traffic, find_entity_id, send_attributes_report
|
from .common import async_enable_traffic, find_entity_id, send_attributes_report
|
||||||
from .conftest import SIG_EP_INPUT, SIG_EP_OUTPUT, SIG_EP_PROFILE, SIG_EP_TYPE
|
from .conftest import SIG_EP_INPUT, SIG_EP_OUTPUT, SIG_EP_PROFILE, SIG_EP_TYPE
|
||||||
|
@ -860,12 +860,13 @@ async def test_preset_setting_invalid(
|
||||||
state = hass.states.get(entity_id)
|
state = hass.states.get(entity_id)
|
||||||
assert state.attributes[ATTR_PRESET_MODE] == PRESET_NONE
|
assert state.attributes[ATTR_PRESET_MODE] == PRESET_NONE
|
||||||
|
|
||||||
await hass.services.async_call(
|
with pytest.raises(ServiceValidationError):
|
||||||
CLIMATE_DOMAIN,
|
await hass.services.async_call(
|
||||||
SERVICE_SET_PRESET_MODE,
|
CLIMATE_DOMAIN,
|
||||||
{ATTR_ENTITY_ID: entity_id, ATTR_PRESET_MODE: "invalid_preset"},
|
SERVICE_SET_PRESET_MODE,
|
||||||
blocking=True,
|
{ATTR_ENTITY_ID: entity_id, ATTR_PRESET_MODE: "invalid_preset"},
|
||||||
)
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
state = hass.states.get(entity_id)
|
state = hass.states.get(entity_id)
|
||||||
assert state.attributes[ATTR_PRESET_MODE] == PRESET_NONE
|
assert state.attributes[ATTR_PRESET_MODE] == PRESET_NONE
|
||||||
|
@ -1251,13 +1252,14 @@ async def test_set_fan_mode_not_supported(
|
||||||
entity_id = find_entity_id(Platform.CLIMATE, device_climate_fan, hass)
|
entity_id = find_entity_id(Platform.CLIMATE, device_climate_fan, hass)
|
||||||
fan_cluster = device_climate_fan.device.endpoints[1].fan
|
fan_cluster = device_climate_fan.device.endpoints[1].fan
|
||||||
|
|
||||||
await hass.services.async_call(
|
with pytest.raises(ServiceValidationError):
|
||||||
CLIMATE_DOMAIN,
|
await hass.services.async_call(
|
||||||
SERVICE_SET_FAN_MODE,
|
CLIMATE_DOMAIN,
|
||||||
{ATTR_ENTITY_ID: entity_id, ATTR_FAN_MODE: FAN_LOW},
|
SERVICE_SET_FAN_MODE,
|
||||||
blocking=True,
|
{ATTR_ENTITY_ID: entity_id, ATTR_FAN_MODE: FAN_LOW},
|
||||||
)
|
blocking=True,
|
||||||
assert fan_cluster.write_attributes.await_count == 0
|
)
|
||||||
|
assert fan_cluster.write_attributes.await_count == 0
|
||||||
|
|
||||||
|
|
||||||
async def test_set_fan_mode(hass: HomeAssistant, device_climate_fan) -> None:
|
async def test_set_fan_mode(hass: HomeAssistant, device_climate_fan) -> None:
|
||||||
|
|
|
@ -40,6 +40,7 @@ from homeassistant.const import (
|
||||||
ATTR_TEMPERATURE,
|
ATTR_TEMPERATURE,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
from homeassistant.helpers import issue_registry as ir
|
from homeassistant.helpers import issue_registry as ir
|
||||||
|
|
||||||
from .common import (
|
from .common import (
|
||||||
|
@ -278,7 +279,7 @@ async def test_thermostat_v2(
|
||||||
client.async_send_command.reset_mock()
|
client.async_send_command.reset_mock()
|
||||||
|
|
||||||
# Test setting invalid fan mode
|
# Test setting invalid fan mode
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ServiceValidationError):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
SERVICE_SET_FAN_MODE,
|
SERVICE_SET_FAN_MODE,
|
||||||
|
@ -692,7 +693,7 @@ async def test_preset_and_no_setpoint(
|
||||||
assert state.attributes[ATTR_TEMPERATURE] is None
|
assert state.attributes[ATTR_TEMPERATURE] is None
|
||||||
assert state.attributes[ATTR_PRESET_MODE] == "Full power"
|
assert state.attributes[ATTR_PRESET_MODE] == "Full power"
|
||||||
|
|
||||||
with pytest.raises(ValueError):
|
with pytest.raises(ServiceValidationError):
|
||||||
# Test setting invalid preset mode
|
# Test setting invalid preset mode
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
CLIMATE_DOMAIN,
|
CLIMATE_DOMAIN,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue