core/tests/components/template/test_switch.py

737 lines
22 KiB
Python

"""The tests for the Template switch platform."""
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant import setup
from homeassistant.components import template
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.const import (
ATTR_ENTITY_ID,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
STATE_OFF,
STATE_ON,
STATE_UNAVAILABLE,
)
from homeassistant.core import CoreState, HomeAssistant, ServiceCall, State
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.setup import async_setup_component
from tests.common import (
MockConfigEntry,
assert_setup_component,
mock_component,
mock_restore_cache,
)
OPTIMISTIC_SWITCH_CONFIG = {
"turn_on": {
"service": "test.automation",
"data_template": {
"action": "turn_on",
"caller": "{{ this.entity_id }}",
},
},
"turn_off": {
"service": "test.automation",
"data_template": {
"action": "turn_off",
"caller": "{{ this.entity_id }}",
},
},
}
async def test_setup_config_entry(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
) -> None:
"""Test the config flow."""
hass.states.async_set(
"switch.one",
"on",
{},
)
template_config_entry = MockConfigEntry(
data={},
domain=template.DOMAIN,
options={
"name": "My template",
"value_template": "{{ states('switch.one') }}",
"template_type": SWITCH_DOMAIN,
},
title="My template",
)
template_config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(template_config_entry.entry_id)
await hass.async_block_till_done()
state = hass.states.get("switch.my_template")
assert state is not None
assert state == snapshot
async def test_template_state_text(hass: HomeAssistant) -> None:
"""Test the state text of a template."""
with assert_setup_component(1, "switch"):
assert await async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test_template_switch": {
**OPTIMISTIC_SWITCH_CONFIG,
"value_template": "{{ states.switch.test_state.state }}",
}
},
}
},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
hass.states.async_set("switch.test_state", STATE_ON)
await hass.async_block_till_done()
state = hass.states.get("switch.test_template_switch")
assert state.state == STATE_ON
hass.states.async_set("switch.test_state", STATE_OFF)
await hass.async_block_till_done()
state = hass.states.get("switch.test_template_switch")
assert state.state == STATE_OFF
async def test_template_state_boolean_on(hass: HomeAssistant) -> None:
"""Test the setting of the state with boolean on."""
with assert_setup_component(1, "switch"):
assert await async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test_template_switch": {
**OPTIMISTIC_SWITCH_CONFIG,
"value_template": "{{ 1 == 1 }}",
}
},
}
},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
state = hass.states.get("switch.test_template_switch")
assert state.state == STATE_ON
async def test_template_state_boolean_off(hass: HomeAssistant) -> None:
"""Test the setting of the state with off."""
with assert_setup_component(1, "switch"):
assert await async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test_template_switch": {
**OPTIMISTIC_SWITCH_CONFIG,
"value_template": "{{ 1 == 2 }}",
}
},
}
},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
state = hass.states.get("switch.test_template_switch")
assert state.state == STATE_OFF
async def test_icon_template(hass: HomeAssistant) -> None:
"""Test icon template."""
with assert_setup_component(1, "switch"):
assert await async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test_template_switch": {
**OPTIMISTIC_SWITCH_CONFIG,
"value_template": "{{ states.switch.test_state.state }}",
"icon_template": (
"{% if states.switch.test_state.state %}"
"mdi:check"
"{% endif %}"
),
}
},
}
},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
state = hass.states.get("switch.test_template_switch")
assert state.attributes.get("icon") == ""
hass.states.async_set("switch.test_state", STATE_ON)
await hass.async_block_till_done()
state = hass.states.get("switch.test_template_switch")
assert state.attributes["icon"] == "mdi:check"
async def test_entity_picture_template(hass: HomeAssistant) -> None:
"""Test entity_picture template."""
with assert_setup_component(1, "switch"):
assert await async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test_template_switch": {
**OPTIMISTIC_SWITCH_CONFIG,
"value_template": "{{ states.switch.test_state.state }}",
"entity_picture_template": (
"{% if states.switch.test_state.state %}"
"/local/switch.png"
"{% endif %}"
),
}
},
}
},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
state = hass.states.get("switch.test_template_switch")
assert state.attributes.get("entity_picture") == ""
hass.states.async_set("switch.test_state", STATE_ON)
await hass.async_block_till_done()
state = hass.states.get("switch.test_template_switch")
assert state.attributes["entity_picture"] == "/local/switch.png"
async def test_template_syntax_error(hass: HomeAssistant) -> None:
"""Test templating syntax error."""
with assert_setup_component(0, "switch"):
assert await async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test_template_switch": {
**OPTIMISTIC_SWITCH_CONFIG,
"value_template": "{% if rubbish %}",
}
},
}
},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
assert hass.states.async_all("switch") == []
async def test_invalid_name_does_not_create(hass: HomeAssistant) -> None:
"""Test invalid name."""
with assert_setup_component(0, "switch"):
assert await async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test INVALID switch": {
**OPTIMISTIC_SWITCH_CONFIG,
"value_template": "{{ rubbish }",
}
},
}
},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
assert hass.states.async_all("switch") == []
async def test_invalid_switch_does_not_create(hass: HomeAssistant) -> None:
"""Test invalid switch."""
with assert_setup_component(0, "switch"):
assert await async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {"test_template_switch": "Invalid"},
}
},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
assert hass.states.async_all("switch") == []
async def test_no_switches_does_not_create(hass: HomeAssistant) -> None:
"""Test if there are no switches no creation."""
with assert_setup_component(0, "switch"):
assert await async_setup_component(
hass, "switch", {"switch": {"platform": "template"}}
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
assert hass.states.async_all("switch") == []
async def test_missing_on_does_not_create(hass: HomeAssistant) -> None:
"""Test missing on."""
with assert_setup_component(0, "switch"):
assert await async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test_template_switch": {
"value_template": "{{ states.switch.test_state.state }}",
"not_on": {
"service": "switch.turn_on",
"entity_id": "switch.test_state",
},
"turn_off": {
"service": "switch.turn_off",
"entity_id": "switch.test_state",
},
}
},
}
},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
assert hass.states.async_all("switch") == []
async def test_missing_off_does_not_create(hass: HomeAssistant) -> None:
"""Test missing off."""
with assert_setup_component(0, "switch"):
assert await async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test_template_switch": {
"value_template": "{{ states.switch.test_state.state }}",
"turn_on": {
"service": "switch.turn_on",
"entity_id": "switch.test_state",
},
"not_off": {
"service": "switch.turn_off",
"entity_id": "switch.test_state",
},
}
},
}
},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
assert hass.states.async_all("switch") == []
async def test_on_action(hass: HomeAssistant, calls: list[ServiceCall]) -> None:
"""Test on action."""
assert await async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test_template_switch": {
**OPTIMISTIC_SWITCH_CONFIG,
"value_template": "{{ states.switch.test_state.state }}",
}
},
}
},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
hass.states.async_set("switch.test_state", STATE_OFF)
await hass.async_block_till_done()
state = hass.states.get("switch.test_template_switch")
assert state.state == STATE_OFF
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "switch.test_template_switch"},
blocking=True,
)
assert len(calls) == 1
assert calls[-1].data["action"] == "turn_on"
assert calls[-1].data["caller"] == "switch.test_template_switch"
async def test_on_action_optimistic(
hass: HomeAssistant, calls: list[ServiceCall]
) -> None:
"""Test on action in optimistic mode."""
assert await async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test_template_switch": {
**OPTIMISTIC_SWITCH_CONFIG,
}
},
}
},
)
await hass.async_start()
await hass.async_block_till_done()
hass.states.async_set("switch.test_template_switch", STATE_OFF)
await hass.async_block_till_done()
state = hass.states.get("switch.test_template_switch")
assert state.state == STATE_OFF
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: "switch.test_template_switch"},
blocking=True,
)
state = hass.states.get("switch.test_template_switch")
assert state.state == STATE_ON
assert len(calls) == 1
assert calls[-1].data["action"] == "turn_on"
assert calls[-1].data["caller"] == "switch.test_template_switch"
async def test_off_action(hass: HomeAssistant, calls: list[ServiceCall]) -> None:
"""Test off action."""
assert await async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test_template_switch": {
**OPTIMISTIC_SWITCH_CONFIG,
"value_template": "{{ states.switch.test_state.state }}",
}
},
}
},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
hass.states.async_set("switch.test_state", STATE_ON)
await hass.async_block_till_done()
state = hass.states.get("switch.test_template_switch")
assert state.state == STATE_ON
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "switch.test_template_switch"},
blocking=True,
)
assert len(calls) == 1
assert calls[-1].data["action"] == "turn_off"
assert calls[-1].data["caller"] == "switch.test_template_switch"
async def test_off_action_optimistic(
hass: HomeAssistant, calls: list[ServiceCall]
) -> None:
"""Test off action in optimistic mode."""
assert await async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test_template_switch": {
**OPTIMISTIC_SWITCH_CONFIG,
}
},
}
},
)
await hass.async_start()
await hass.async_block_till_done()
hass.states.async_set("switch.test_template_switch", STATE_ON)
await hass.async_block_till_done()
state = hass.states.get("switch.test_template_switch")
assert state.state == STATE_ON
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: "switch.test_template_switch"},
blocking=True,
)
state = hass.states.get("switch.test_template_switch")
assert state.state == STATE_OFF
assert len(calls) == 1
assert calls[-1].data["action"] == "turn_off"
assert calls[-1].data["caller"] == "switch.test_template_switch"
async def test_restore_state(hass: HomeAssistant) -> None:
"""Test state restoration."""
mock_restore_cache(
hass,
(
State("switch.s1", STATE_ON),
State("switch.s2", STATE_OFF),
),
)
hass.set_state(CoreState.starting)
mock_component(hass, "recorder")
await async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"s1": {
**OPTIMISTIC_SWITCH_CONFIG,
},
"s2": {
**OPTIMISTIC_SWITCH_CONFIG,
},
},
}
},
)
await hass.async_block_till_done()
state = hass.states.get("switch.s1")
assert state
assert state.state == STATE_ON
state = hass.states.get("switch.s2")
assert state
assert state.state == STATE_OFF
async def test_available_template_with_entities(hass: HomeAssistant) -> None:
"""Test availability templates with values from other entities."""
await setup.async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test_template_switch": {
**OPTIMISTIC_SWITCH_CONFIG,
"value_template": "{{ 1 == 1 }}",
"availability_template": (
"{{ is_state('availability_state.state', 'on') }}"
),
}
},
}
},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
hass.states.async_set("availability_state.state", STATE_ON)
await hass.async_block_till_done()
assert hass.states.get("switch.test_template_switch").state != STATE_UNAVAILABLE
hass.states.async_set("availability_state.state", STATE_OFF)
await hass.async_block_till_done()
assert hass.states.get("switch.test_template_switch").state == STATE_UNAVAILABLE
async def test_invalid_availability_template_keeps_component_available(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""Test that an invalid availability keeps the device available."""
await setup.async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test_template_switch": {
**OPTIMISTIC_SWITCH_CONFIG,
"value_template": "{{ true }}",
"availability_template": "{{ x - 12 }}",
}
},
}
},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
assert hass.states.get("switch.test_template_switch").state != STATE_UNAVAILABLE
assert "UndefinedError: 'x' is undefined" in caplog.text
async def test_unique_id(hass: HomeAssistant) -> None:
"""Test unique_id option only creates one switch per id."""
await setup.async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test_template_switch_01": {
**OPTIMISTIC_SWITCH_CONFIG,
"unique_id": "not-so-unique-anymore",
"value_template": "{{ true }}",
},
"test_template_switch_02": {
**OPTIMISTIC_SWITCH_CONFIG,
"unique_id": "not-so-unique-anymore",
"value_template": "{{ false }}",
},
},
}
},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
assert len(hass.states.async_all("switch")) == 1
async def test_device_id(
hass: HomeAssistant,
device_registry: dr.DeviceRegistry,
entity_registry: er.EntityRegistry,
) -> None:
"""Test for device for Template."""
device_config_entry = MockConfigEntry()
device_config_entry.add_to_hass(hass)
device_entry = device_registry.async_get_or_create(
config_entry_id=device_config_entry.entry_id,
identifiers={("test", "identifier_test")},
connections={("mac", "30:31:32:33:34:35")},
)
await hass.async_block_till_done()
assert device_entry is not None
assert device_entry.id is not None
template_config_entry = MockConfigEntry(
data={},
domain=template.DOMAIN,
options={
"name": "My template",
"value_template": "{{ true }}",
"template_type": "switch",
"device_id": device_entry.id,
},
title="My template",
)
template_config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(template_config_entry.entry_id)
await hass.async_block_till_done()
template_entity = entity_registry.async_get("switch.my_template")
assert template_entity is not None
assert template_entity.device_id == device_entry.id