mirror of
https://github.com/home-assistant/core.git
synced 2025-12-20 02:48:57 +00:00
Add trigger climate.hvac_mode_changed (#159358)
This commit is contained in:
@@ -45,7 +45,7 @@ def make_entity_state_trigger_required_features(
|
|||||||
"""Trigger for entity state changes."""
|
"""Trigger for entity state changes."""
|
||||||
|
|
||||||
_domain = domain
|
_domain = domain
|
||||||
_to_state = to_state
|
_to_states = {to_state}
|
||||||
_required_features = required_features
|
_required_features = required_features
|
||||||
|
|
||||||
return CustomTrigger
|
return CustomTrigger
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ def make_binary_sensor_trigger(
|
|||||||
"""Trigger for entity state changes."""
|
"""Trigger for entity state changes."""
|
||||||
|
|
||||||
_device_class = device_class
|
_device_class = device_class
|
||||||
_to_state = to_state
|
_to_states = {to_state}
|
||||||
|
|
||||||
return CustomTrigger
|
return CustomTrigger
|
||||||
|
|
||||||
|
|||||||
@@ -98,6 +98,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"triggers": {
|
"triggers": {
|
||||||
|
"hvac_mode_changed": {
|
||||||
|
"trigger": "mdi:thermostat"
|
||||||
|
},
|
||||||
"started_cooling": {
|
"started_cooling": {
|
||||||
"trigger": "mdi:snowflake"
|
"trigger": "mdi:snowflake"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -298,6 +298,20 @@
|
|||||||
},
|
},
|
||||||
"title": "Climate",
|
"title": "Climate",
|
||||||
"triggers": {
|
"triggers": {
|
||||||
|
"hvac_mode_changed": {
|
||||||
|
"description": "Triggers after the mode of one or more climate-control devices changes.",
|
||||||
|
"fields": {
|
||||||
|
"behavior": {
|
||||||
|
"description": "[%key:component::climate::common::trigger_behavior_description%]",
|
||||||
|
"name": "[%key:component::climate::common::trigger_behavior_name%]"
|
||||||
|
},
|
||||||
|
"hvac_mode": {
|
||||||
|
"description": "The HVAC modes to trigger on.",
|
||||||
|
"name": "Modes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "Climate-control device mode changed"
|
||||||
|
},
|
||||||
"started_cooling": {
|
"started_cooling": {
|
||||||
"description": "Triggers after one or more climate-control devices start cooling.",
|
"description": "Triggers after one or more climate-control devices start cooling.",
|
||||||
"fields": {
|
"fields": {
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
"""Provides triggers for climates."""
|
"""Provides triggers for climates."""
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.const import CONF_OPTIONS
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import config_validation as cv
|
||||||
from homeassistant.helpers.trigger import (
|
from homeassistant.helpers.trigger import (
|
||||||
|
ENTITY_STATE_TRIGGER_SCHEMA_FIRST_LAST,
|
||||||
|
EntityTargetStateTriggerBase,
|
||||||
Trigger,
|
Trigger,
|
||||||
|
TriggerConfig,
|
||||||
make_entity_target_state_attribute_trigger,
|
make_entity_target_state_attribute_trigger,
|
||||||
make_entity_target_state_trigger,
|
make_entity_target_state_trigger,
|
||||||
make_entity_transition_trigger,
|
make_entity_transition_trigger,
|
||||||
@@ -10,7 +17,33 @@ from homeassistant.helpers.trigger import (
|
|||||||
|
|
||||||
from .const import ATTR_HVAC_ACTION, DOMAIN, HVACAction, HVACMode
|
from .const import ATTR_HVAC_ACTION, DOMAIN, HVACAction, HVACMode
|
||||||
|
|
||||||
|
CONF_HVAC_MODE = "hvac_mode"
|
||||||
|
|
||||||
|
HVAC_MODE_CHANGED_TRIGGER_SCHEMA = ENTITY_STATE_TRIGGER_SCHEMA_FIRST_LAST.extend(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_OPTIONS): {
|
||||||
|
vol.Required(CONF_HVAC_MODE): vol.All(
|
||||||
|
cv.ensure_list, vol.Length(min=1), [HVACMode]
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class HVACModeChangedTrigger(EntityTargetStateTriggerBase):
|
||||||
|
"""Trigger for entity state changes."""
|
||||||
|
|
||||||
|
_domain = DOMAIN
|
||||||
|
_schema = HVAC_MODE_CHANGED_TRIGGER_SCHEMA
|
||||||
|
|
||||||
|
def __init__(self, hass: HomeAssistant, config: TriggerConfig) -> None:
|
||||||
|
"""Initialize the state trigger."""
|
||||||
|
super().__init__(hass, config)
|
||||||
|
self._to_states = set(self._options[CONF_HVAC_MODE])
|
||||||
|
|
||||||
|
|
||||||
TRIGGERS: dict[str, type[Trigger]] = {
|
TRIGGERS: dict[str, type[Trigger]] = {
|
||||||
|
"hvac_mode_changed": HVACModeChangedTrigger,
|
||||||
"started_cooling": make_entity_target_state_attribute_trigger(
|
"started_cooling": make_entity_target_state_attribute_trigger(
|
||||||
DOMAIN, ATTR_HVAC_ACTION, HVACAction.COOLING
|
DOMAIN, ATTR_HVAC_ACTION, HVACAction.COOLING
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
.trigger_common: &trigger_common
|
.trigger_common: &trigger_common
|
||||||
target:
|
target: &trigger_climate_target
|
||||||
entity:
|
entity:
|
||||||
domain: climate
|
domain: climate
|
||||||
fields:
|
fields:
|
||||||
behavior:
|
behavior: &trigger_behavior
|
||||||
required: true
|
required: true
|
||||||
default: any
|
default: any
|
||||||
selector:
|
selector:
|
||||||
@@ -19,3 +19,18 @@ started_drying: *trigger_common
|
|||||||
started_heating: *trigger_common
|
started_heating: *trigger_common
|
||||||
turned_off: *trigger_common
|
turned_off: *trigger_common
|
||||||
turned_on: *trigger_common
|
turned_on: *trigger_common
|
||||||
|
|
||||||
|
hvac_mode_changed:
|
||||||
|
target: *trigger_climate_target
|
||||||
|
fields:
|
||||||
|
behavior: *trigger_behavior
|
||||||
|
hvac_mode:
|
||||||
|
context:
|
||||||
|
filter_target: target
|
||||||
|
required: true
|
||||||
|
selector:
|
||||||
|
state:
|
||||||
|
# Note: This should allow selecting multiple modes, but state selector does not support that yet.
|
||||||
|
hide_states:
|
||||||
|
- unavailable
|
||||||
|
- unknown
|
||||||
|
|||||||
@@ -433,11 +433,21 @@ class EntityTriggerBase(Trigger):
|
|||||||
class EntityTargetStateTriggerBase(EntityTriggerBase):
|
class EntityTargetStateTriggerBase(EntityTriggerBase):
|
||||||
"""Trigger for entity state changes to a specific state."""
|
"""Trigger for entity state changes to a specific state."""
|
||||||
|
|
||||||
_to_state: str
|
_to_states: set[str]
|
||||||
|
|
||||||
|
def is_valid_transition(self, from_state: State, to_state: State) -> bool:
|
||||||
|
"""Check if the origin state is valid and the state has changed."""
|
||||||
|
if from_state.state in (STATE_UNAVAILABLE, STATE_UNKNOWN):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return (
|
||||||
|
from_state.state != to_state.state
|
||||||
|
and from_state.state not in self._to_states
|
||||||
|
)
|
||||||
|
|
||||||
def is_valid_state(self, state: State) -> bool:
|
def is_valid_state(self, state: State) -> bool:
|
||||||
"""Check if the new state matches the expected state."""
|
"""Check if the new state matches the expected state."""
|
||||||
return state.state == self._to_state
|
return state.state in self._to_states
|
||||||
|
|
||||||
|
|
||||||
class EntityTransitionTriggerBase(EntityTriggerBase):
|
class EntityTransitionTriggerBase(EntityTriggerBase):
|
||||||
@@ -495,15 +505,20 @@ class EntityTargetStateAttributeTriggerBase(EntityTriggerBase):
|
|||||||
|
|
||||||
|
|
||||||
def make_entity_target_state_trigger(
|
def make_entity_target_state_trigger(
|
||||||
domain: str, to_state: str
|
domain: str, to_states: str | set[str]
|
||||||
) -> type[EntityTargetStateTriggerBase]:
|
) -> type[EntityTargetStateTriggerBase]:
|
||||||
"""Create a trigger for entity state changes to a specific state."""
|
"""Create a trigger for entity state changes to specific state(s)."""
|
||||||
|
|
||||||
|
if isinstance(to_states, str):
|
||||||
|
to_states_set = {to_states}
|
||||||
|
else:
|
||||||
|
to_states_set = to_states
|
||||||
|
|
||||||
class CustomTrigger(EntityTargetStateTriggerBase):
|
class CustomTrigger(EntityTargetStateTriggerBase):
|
||||||
"""Trigger for entity state changes."""
|
"""Trigger for entity state changes."""
|
||||||
|
|
||||||
_domain = domain
|
_domain = domain
|
||||||
_to_state = to_state
|
_to_states = to_states_set
|
||||||
|
|
||||||
return CustomTrigger
|
return CustomTrigger
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
"""The tests for components."""
|
"""The tests for components."""
|
||||||
|
|
||||||
|
from collections.abc import Iterable
|
||||||
from enum import StrEnum
|
from enum import StrEnum
|
||||||
import itertools
|
import itertools
|
||||||
from typing import TypedDict
|
from typing import TypedDict
|
||||||
@@ -345,6 +346,15 @@ def set_or_remove_state(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def other_states(state: StrEnum) -> list[str]:
|
def other_states(state: StrEnum | Iterable[StrEnum]) -> list[str]:
|
||||||
"""Return a sorted list with all states except the specified one."""
|
"""Return a sorted list with all states except the specified one."""
|
||||||
return sorted({s.value for s in state.__class__} - {state.value})
|
if isinstance(state, StrEnum):
|
||||||
|
excluded_values = {state.value}
|
||||||
|
enum_class = state.__class__
|
||||||
|
else:
|
||||||
|
if len(state) == 0:
|
||||||
|
raise ValueError("state iterable must not be empty")
|
||||||
|
excluded_values = {s.value for s in state}
|
||||||
|
enum_class = list(state)[0].__class__
|
||||||
|
|
||||||
|
return sorted({s.value for s in enum_class} - excluded_values)
|
||||||
|
|||||||
@@ -1,17 +1,22 @@
|
|||||||
"""Test climate trigger."""
|
"""Test climate trigger."""
|
||||||
|
|
||||||
from collections.abc import Generator
|
from collections.abc import Generator
|
||||||
|
from contextlib import AbstractContextManager, nullcontext as does_not_raise
|
||||||
|
from typing import Any
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.climate.const import (
|
from homeassistant.components.climate.const import (
|
||||||
ATTR_HVAC_ACTION,
|
ATTR_HVAC_ACTION,
|
||||||
HVACAction,
|
HVACAction,
|
||||||
HVACMode,
|
HVACMode,
|
||||||
)
|
)
|
||||||
from homeassistant.const import ATTR_LABEL_ID, CONF_ENTITY_ID
|
from homeassistant.components.climate.trigger import CONF_HVAC_MODE
|
||||||
|
from homeassistant.const import ATTR_LABEL_ID, CONF_ENTITY_ID, CONF_OPTIONS, CONF_TARGET
|
||||||
from homeassistant.core import HomeAssistant, ServiceCall
|
from homeassistant.core import HomeAssistant, ServiceCall
|
||||||
|
from homeassistant.helpers.trigger import async_validate_trigger_config
|
||||||
|
|
||||||
from tests.components import (
|
from tests.components import (
|
||||||
StateDescription,
|
StateDescription,
|
||||||
@@ -48,6 +53,7 @@ async def target_climates(hass: HomeAssistant) -> list[str]:
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"trigger_key",
|
"trigger_key",
|
||||||
[
|
[
|
||||||
|
"climate.hvac_mode_changed",
|
||||||
"climate.turned_off",
|
"climate.turned_off",
|
||||||
"climate.turned_on",
|
"climate.turned_on",
|
||||||
"climate.started_heating",
|
"climate.started_heating",
|
||||||
@@ -66,20 +72,105 @@ async def test_climate_triggers_gated_by_labs_flag(
|
|||||||
) in caplog.text
|
) in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("enable_experimental_triggers_conditions")
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("trigger", "trigger_options", "expected_result"),
|
||||||
|
[
|
||||||
|
# Test validating climate.hvac_mode_changed
|
||||||
|
# Valid configurations
|
||||||
|
(
|
||||||
|
"climate.hvac_mode_changed",
|
||||||
|
{CONF_HVAC_MODE: [HVACMode.HEAT, HVACMode.COOL]},
|
||||||
|
does_not_raise(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"climate.hvac_mode_changed",
|
||||||
|
{CONF_HVAC_MODE: HVACMode.HEAT},
|
||||||
|
does_not_raise(),
|
||||||
|
),
|
||||||
|
# Invalid configurations
|
||||||
|
(
|
||||||
|
"climate.hvac_mode_changed",
|
||||||
|
# Empty hvac_mode list
|
||||||
|
{CONF_HVAC_MODE: []},
|
||||||
|
pytest.raises(vol.Invalid),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"climate.hvac_mode_changed",
|
||||||
|
# Missing CONF_HVAC_MODE
|
||||||
|
{},
|
||||||
|
pytest.raises(vol.Invalid),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"climate.hvac_mode_changed",
|
||||||
|
{CONF_HVAC_MODE: ["invalid_mode"]},
|
||||||
|
pytest.raises(vol.Invalid),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_climate_trigger_validation(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
trigger: str,
|
||||||
|
trigger_options: dict[str, Any],
|
||||||
|
expected_result: AbstractContextManager,
|
||||||
|
) -> None:
|
||||||
|
"""Test climate trigger config validation."""
|
||||||
|
with expected_result:
|
||||||
|
await async_validate_trigger_config(
|
||||||
|
hass,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"platform": trigger,
|
||||||
|
CONF_TARGET: {CONF_ENTITY_ID: "climate.test_climate"},
|
||||||
|
CONF_OPTIONS: trigger_options,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parametrize_climate_trigger_states(
|
||||||
|
*,
|
||||||
|
trigger: str,
|
||||||
|
trigger_options: dict | None = None,
|
||||||
|
target_states: list[str | None | tuple[str | None, dict]],
|
||||||
|
other_states: list[str | None | tuple[str | None, dict]],
|
||||||
|
additional_attributes: dict | None = None,
|
||||||
|
trigger_from_none: bool = True,
|
||||||
|
) -> list[tuple[str, dict[str, Any], list[StateDescription]]]:
|
||||||
|
"""Parametrize states and expected service call counts."""
|
||||||
|
trigger_options = trigger_options or {}
|
||||||
|
return [
|
||||||
|
(s[0], trigger_options, *s[1:])
|
||||||
|
for s in parametrize_trigger_states(
|
||||||
|
trigger=trigger,
|
||||||
|
target_states=target_states,
|
||||||
|
other_states=other_states,
|
||||||
|
additional_attributes=additional_attributes,
|
||||||
|
trigger_from_none=trigger_from_none,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("enable_experimental_triggers_conditions")
|
@pytest.mark.usefixtures("enable_experimental_triggers_conditions")
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("trigger_target_config", "entity_id", "entities_in_target"),
|
("trigger_target_config", "entity_id", "entities_in_target"),
|
||||||
parametrize_target_entities("climate"),
|
parametrize_target_entities("climate"),
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("trigger", "states"),
|
("trigger", "trigger_options", "states"),
|
||||||
[
|
[
|
||||||
*parametrize_trigger_states(
|
*parametrize_climate_trigger_states(
|
||||||
|
trigger="climate.hvac_mode_changed",
|
||||||
|
trigger_options={CONF_HVAC_MODE: [HVACMode.HEAT, HVACMode.COOL]},
|
||||||
|
target_states=[HVACMode.HEAT, HVACMode.COOL],
|
||||||
|
other_states=other_states([HVACMode.HEAT, HVACMode.COOL]),
|
||||||
|
),
|
||||||
|
*parametrize_climate_trigger_states(
|
||||||
trigger="climate.turned_off",
|
trigger="climate.turned_off",
|
||||||
target_states=[HVACMode.OFF],
|
target_states=[HVACMode.OFF],
|
||||||
other_states=other_states(HVACMode.OFF),
|
other_states=other_states(HVACMode.OFF),
|
||||||
),
|
),
|
||||||
*parametrize_trigger_states(
|
*parametrize_climate_trigger_states(
|
||||||
trigger="climate.turned_on",
|
trigger="climate.turned_on",
|
||||||
target_states=[
|
target_states=[
|
||||||
HVACMode.AUTO,
|
HVACMode.AUTO,
|
||||||
@@ -103,6 +194,7 @@ async def test_climate_state_trigger_behavior_any(
|
|||||||
entity_id: str,
|
entity_id: str,
|
||||||
entities_in_target: int,
|
entities_in_target: int,
|
||||||
trigger: str,
|
trigger: str,
|
||||||
|
trigger_options: dict[str, Any],
|
||||||
states: list[StateDescription],
|
states: list[StateDescription],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test that the climate state trigger fires when any climate state changes to a specific state."""
|
"""Test that the climate state trigger fires when any climate state changes to a specific state."""
|
||||||
@@ -113,7 +205,7 @@ async def test_climate_state_trigger_behavior_any(
|
|||||||
set_or_remove_state(hass, eid, states[0]["included"])
|
set_or_remove_state(hass, eid, states[0]["included"])
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
await arm_trigger(hass, trigger, {}, trigger_target_config)
|
await arm_trigger(hass, trigger, trigger_options, trigger_target_config)
|
||||||
|
|
||||||
for state in states[1:]:
|
for state in states[1:]:
|
||||||
included_state = state["included"]
|
included_state = state["included"]
|
||||||
@@ -200,14 +292,20 @@ async def test_climate_state_attribute_trigger_behavior_any(
|
|||||||
parametrize_target_entities("climate"),
|
parametrize_target_entities("climate"),
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("trigger", "states"),
|
("trigger", "trigger_options", "states"),
|
||||||
[
|
[
|
||||||
*parametrize_trigger_states(
|
*parametrize_climate_trigger_states(
|
||||||
|
trigger="climate.hvac_mode_changed",
|
||||||
|
trigger_options={CONF_HVAC_MODE: [HVACMode.HEAT, HVACMode.COOL]},
|
||||||
|
target_states=[HVACMode.HEAT, HVACMode.COOL],
|
||||||
|
other_states=other_states([HVACMode.HEAT, HVACMode.COOL]),
|
||||||
|
),
|
||||||
|
*parametrize_climate_trigger_states(
|
||||||
trigger="climate.turned_off",
|
trigger="climate.turned_off",
|
||||||
target_states=[HVACMode.OFF],
|
target_states=[HVACMode.OFF],
|
||||||
other_states=other_states(HVACMode.OFF),
|
other_states=other_states(HVACMode.OFF),
|
||||||
),
|
),
|
||||||
*parametrize_trigger_states(
|
*parametrize_climate_trigger_states(
|
||||||
trigger="climate.turned_on",
|
trigger="climate.turned_on",
|
||||||
target_states=[
|
target_states=[
|
||||||
HVACMode.AUTO,
|
HVACMode.AUTO,
|
||||||
@@ -231,6 +329,7 @@ async def test_climate_state_trigger_behavior_first(
|
|||||||
entities_in_target: int,
|
entities_in_target: int,
|
||||||
entity_id: str,
|
entity_id: str,
|
||||||
trigger: str,
|
trigger: str,
|
||||||
|
trigger_options: dict[str, Any],
|
||||||
states: list[StateDescription],
|
states: list[StateDescription],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test that the climate state trigger fires when the first climate changes to a specific state."""
|
"""Test that the climate state trigger fires when the first climate changes to a specific state."""
|
||||||
@@ -241,7 +340,9 @@ async def test_climate_state_trigger_behavior_first(
|
|||||||
set_or_remove_state(hass, eid, states[0]["included"])
|
set_or_remove_state(hass, eid, states[0]["included"])
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
await arm_trigger(hass, trigger, {"behavior": "first"}, trigger_target_config)
|
await arm_trigger(
|
||||||
|
hass, trigger, {"behavior": "first"} | trigger_options, trigger_target_config
|
||||||
|
)
|
||||||
|
|
||||||
for state in states[1:]:
|
for state in states[1:]:
|
||||||
included_state = state["included"]
|
included_state = state["included"]
|
||||||
@@ -326,14 +427,20 @@ async def test_climate_state_attribute_trigger_behavior_first(
|
|||||||
parametrize_target_entities("climate"),
|
parametrize_target_entities("climate"),
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("trigger", "states"),
|
("trigger", "trigger_options", "states"),
|
||||||
[
|
[
|
||||||
*parametrize_trigger_states(
|
*parametrize_climate_trigger_states(
|
||||||
|
trigger="climate.hvac_mode_changed",
|
||||||
|
trigger_options={CONF_HVAC_MODE: [HVACMode.HEAT, HVACMode.COOL]},
|
||||||
|
target_states=[HVACMode.HEAT, HVACMode.COOL],
|
||||||
|
other_states=other_states([HVACMode.HEAT, HVACMode.COOL]),
|
||||||
|
),
|
||||||
|
*parametrize_climate_trigger_states(
|
||||||
trigger="climate.turned_off",
|
trigger="climate.turned_off",
|
||||||
target_states=[HVACMode.OFF],
|
target_states=[HVACMode.OFF],
|
||||||
other_states=other_states(HVACMode.OFF),
|
other_states=other_states(HVACMode.OFF),
|
||||||
),
|
),
|
||||||
*parametrize_trigger_states(
|
*parametrize_climate_trigger_states(
|
||||||
trigger="climate.turned_on",
|
trigger="climate.turned_on",
|
||||||
target_states=[
|
target_states=[
|
||||||
HVACMode.AUTO,
|
HVACMode.AUTO,
|
||||||
@@ -357,6 +464,7 @@ async def test_climate_state_trigger_behavior_last(
|
|||||||
entities_in_target: int,
|
entities_in_target: int,
|
||||||
entity_id: str,
|
entity_id: str,
|
||||||
trigger: str,
|
trigger: str,
|
||||||
|
trigger_options: dict[str, Any],
|
||||||
states: list[StateDescription],
|
states: list[StateDescription],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test that the climate state trigger fires when the last climate changes to a specific state."""
|
"""Test that the climate state trigger fires when the last climate changes to a specific state."""
|
||||||
@@ -367,7 +475,9 @@ async def test_climate_state_trigger_behavior_last(
|
|||||||
set_or_remove_state(hass, eid, states[0]["included"])
|
set_or_remove_state(hass, eid, states[0]["included"])
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
await arm_trigger(hass, trigger, {"behavior": "last"}, trigger_target_config)
|
await arm_trigger(
|
||||||
|
hass, trigger, {"behavior": "last"} | trigger_options, trigger_target_config
|
||||||
|
)
|
||||||
|
|
||||||
for state in states[1:]:
|
for state in states[1:]:
|
||||||
included_state = state["included"]
|
included_state = state["included"]
|
||||||
|
|||||||
Reference in New Issue
Block a user