Add validation to climate hvac mode (#125178)
* Add validation to climate hvac mode * Make softer * Remove string --------- Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
2ef37f01b1
commit
c2d5696b5b
2 changed files with 58 additions and 13 deletions
|
@ -175,7 +175,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||
component.async_register_entity_service(
|
||||
SERVICE_SET_HVAC_MODE,
|
||||
{vol.Required(ATTR_HVAC_MODE): vol.Coerce(HVACMode)},
|
||||
"async_set_hvac_mode",
|
||||
"async_handle_set_hvac_mode_service",
|
||||
)
|
||||
component.async_register_entity_service(
|
||||
SERVICE_SET_PRESET_MODE,
|
||||
|
@ -694,20 +694,35 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||
@callback
|
||||
def _valid_mode_or_raise(
|
||||
self,
|
||||
mode_type: Literal["preset", "swing", "fan"],
|
||||
mode: str,
|
||||
modes: list[str] | None,
|
||||
mode_type: Literal["preset", "swing", "fan", "hvac"],
|
||||
mode: str | HVACMode,
|
||||
modes: list[str] | list[HVACMode] | 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"
|
||||
translation_key = f"not_valid_{mode_type}_mode"
|
||||
if mode_type == "hvac":
|
||||
report_issue = async_suggest_report_issue(
|
||||
self.hass,
|
||||
integration_domain=self.platform.platform_name,
|
||||
module=type(self).__module__,
|
||||
)
|
||||
_LOGGER.warning(
|
||||
(
|
||||
"%s::%s sets the hvac_mode %s which is not "
|
||||
"valid for this entity with modes: %s. "
|
||||
"This will stop working in 2025.3 and raise an error instead. "
|
||||
"Please %s"
|
||||
),
|
||||
self.platform.platform_name,
|
||||
self.__class__.__name__,
|
||||
mode,
|
||||
modes_str,
|
||||
report_issue,
|
||||
)
|
||||
return
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key=translation_key,
|
||||
|
@ -749,6 +764,12 @@ class ClimateEntity(Entity, cached_properties=CACHED_PROPERTIES_WITH_ATTR_):
|
|||
"""Set new target fan mode."""
|
||||
await self.hass.async_add_executor_job(self.set_fan_mode, fan_mode)
|
||||
|
||||
@final
|
||||
async def async_handle_set_hvac_mode_service(self, hvac_mode: HVACMode) -> None:
|
||||
"""Validate and set new preset mode."""
|
||||
self._valid_mode_or_raise("hvac", hvac_mode, self.hvac_modes)
|
||||
await self.async_set_hvac_mode(hvac_mode)
|
||||
|
||||
def set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set new target hvac mode."""
|
||||
raise NotImplementedError
|
||||
|
|
|
@ -27,6 +27,7 @@ from homeassistant.components.climate.const import (
|
|||
ATTR_TARGET_TEMP_HIGH,
|
||||
ATTR_TARGET_TEMP_LOW,
|
||||
SERVICE_SET_FAN_MODE,
|
||||
SERVICE_SET_HVAC_MODE,
|
||||
SERVICE_SET_PRESET_MODE,
|
||||
SERVICE_SET_SWING_MODE,
|
||||
SERVICE_SET_TEMPERATURE,
|
||||
|
@ -138,6 +139,10 @@ class MockClimateEntity(MockEntity, ClimateEntity):
|
|||
"""Set swing mode."""
|
||||
self._attr_swing_mode = swing_mode
|
||||
|
||||
def set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set new target hvac mode."""
|
||||
self._attr_hvac_mode = hvac_mode
|
||||
|
||||
|
||||
class MockClimateEntityTestMethods(MockClimateEntity):
|
||||
"""Mock Climate device."""
|
||||
|
@ -237,10 +242,12 @@ def test_deprecated_current_constants(
|
|||
)
|
||||
|
||||
|
||||
async def test_preset_mode_validation(
|
||||
hass: HomeAssistant, register_test_integration: MockConfigEntry
|
||||
async def test_mode_validation(
|
||||
hass: HomeAssistant,
|
||||
register_test_integration: MockConfigEntry,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test mode validation for fan, swing and preset."""
|
||||
"""Test mode validation for hvac_mode, fan, swing and preset."""
|
||||
climate_entity = MockClimateEntity(name="test", entity_id="climate.test")
|
||||
|
||||
setup_test_component_platform(
|
||||
|
@ -250,6 +257,7 @@ async def test_preset_mode_validation(
|
|||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("climate.test")
|
||||
assert state.state == "heat"
|
||||
assert state.attributes.get(ATTR_PRESET_MODE) == "home"
|
||||
assert state.attributes.get(ATTR_FAN_MODE) == "auto"
|
||||
assert state.attributes.get(ATTR_SWING_MODE) == "auto"
|
||||
|
@ -286,6 +294,22 @@ async def test_preset_mode_validation(
|
|||
assert state.attributes.get(ATTR_FAN_MODE) == "off"
|
||||
assert state.attributes.get(ATTR_SWING_MODE) == "off"
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_SET_HVAC_MODE,
|
||||
{
|
||||
"entity_id": "climate.test",
|
||||
"hvac_mode": "auto",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert (
|
||||
"MockClimateEntity sets the hvac_mode auto which is not valid "
|
||||
"for this entity with modes: off, heat. This will stop working "
|
||||
"in 2025.3 and raise an error instead. Please" in caplog.text
|
||||
)
|
||||
|
||||
with pytest.raises(
|
||||
ServiceValidationError,
|
||||
match="Preset mode invalid is not valid. Valid preset modes are: home, away",
|
||||
|
|
Loading…
Add table
Reference in a new issue