Add switch entities for LCN key-locks and regulator-locks (#127731)

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
Andre Lengwenus 2024-10-29 20:08:30 +01:00 committed by GitHub
parent 35a9d502af
commit c9aba288b4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 617 additions and 7 deletions

View File

@ -5,14 +5,17 @@ from functools import partial
import pypck
from homeassistant.components.automation import automations_with_entity
from homeassistant.components.binary_sensor import (
DOMAIN as DOMAIN_BINARY_SENSOR,
BinarySensorEntity,
)
from homeassistant.components.script import scripts_with_entity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_DOMAIN, CONF_ENTITIES, CONF_SOURCE
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from homeassistant.helpers.typing import ConfigType
from .const import (
@ -83,11 +86,28 @@ class LcnRegulatorLockSensor(LcnEntity, BinarySensorEntity):
async def async_added_to_hass(self) -> None:
"""Run when entity about to be added to hass."""
await super().async_added_to_hass()
if not self.device_connection.is_group:
await self.device_connection.activate_status_request_handler(
self.setpoint_variable
)
entity_automations = automations_with_entity(self.hass, self.entity_id)
entity_scripts = scripts_with_entity(self.hass, self.entity_id)
if entity_automations + entity_scripts:
async_create_issue(
self.hass,
DOMAIN,
f"deprecated_binary_sensor_{self.entity_id}",
breaks_in_ha_version="2025.5.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="deprecated_regulatorlock_sensor",
translation_placeholders={
"entity": f"{DOMAIN_BINARY_SENSOR}.{self.name.lower().replace(' ', '_')}",
},
)
async def async_will_remove_from_hass(self) -> None:
"""Run when entity will be removed from hass."""
await super().async_will_remove_from_hass()
@ -156,9 +176,26 @@ class LcnLockKeysSensor(LcnEntity, BinarySensorEntity):
async def async_added_to_hass(self) -> None:
"""Run when entity about to be added to hass."""
await super().async_added_to_hass()
if not self.device_connection.is_group:
await self.device_connection.activate_status_request_handler(self.source)
entity_automations = automations_with_entity(self.hass, self.entity_id)
entity_scripts = scripts_with_entity(self.hass, self.entity_id)
if entity_automations + entity_scripts:
async_create_issue(
self.hass,
DOMAIN,
f"deprecated_binary_sensor_{self.entity_id}",
breaks_in_ha_version="2025.5.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="deprecated_keylock_sensor",
translation_placeholders={
"entity": f"{DOMAIN_BINARY_SENSOR}.{self.name.lower().replace(' ', '_')}",
},
)
async def async_will_remove_from_hass(self) -> None:
"""Run when entity will be removed from hass."""
await super().async_will_remove_from_hass()

View File

@ -42,6 +42,7 @@ CONF_LED = "led"
CONF_KEYS = "keys"
CONF_TIME = "time"
CONF_TIME_UNIT = "time_unit"
CONF_LOCK_TIME = "lock_time"
CONF_TABLE = "table"
CONF_ROW = "row"
CONF_TEXT = "text"

View File

@ -125,9 +125,13 @@ DOMAIN_DATA_SENSOR: VolDictType = {
DOMAIN_DATA_SWITCH: VolDictType = {
vol.Required(CONF_OUTPUT): vol.All(vol.Upper, vol.In(OUTPUT_PORTS + RELAY_PORTS)),
vol.Required(CONF_OUTPUT): vol.All(
vol.Upper,
vol.In(OUTPUT_PORTS + RELAY_PORTS + SETPOINTS + KEYS),
),
}
#
# Configuration
#

View File

@ -126,7 +126,11 @@ class LcnVariableSensor(LcnEntity, SensorEntity):
):
return
self._attr_native_value = input_obj.get_value().to_var_unit(self.unit)
is_regulator = self.variable.name in SETPOINTS
self._attr_native_value = input_obj.get_value().to_var_unit(
self.unit, is_regulator
)
self.async_write_ha_state()

View File

@ -74,6 +74,14 @@
"connection_refused": {
"title": "Unable to connect to PCHK.",
"description": "Configuring LCN using YAML is being removed but there was an error importing your YAML configuration.\n\nEnsure the connection (IP and port) to the LCN bus coupler is correct.\n\nConsider removing the LCN YAML configuration from your configuration.yaml file and continue to [set up the integration]({url}) manually."
},
"deprecated_regulatorlock_sensor": {
"title": "Deprecated LCN regulator lock binary sensor entity found in {info}",
"description": "Your LCN regulator lock binary sensor entity `{entity}` is beeing used in automations or scripts. A regulator lock switch entity is available and should be used going forward.\n\nPlease adjust your automations or scripts to fix this issue."
},
"deprecated_keylock_sensor": {
"title": "Deprecated LCN key lock binary sensor entity found in {info}",
"description": "Your LCN key lock binary sensor entity `{entity}` is beeing used in automations or scripts. A key lock switch entity is available and should be used going forward.\n\nPlease adjust your automations or scripts to fix this issue."
}
},
"services": {

View File

@ -19,6 +19,8 @@ from .const import (
CONF_OUTPUT,
DOMAIN,
OUTPUT_PORTS,
RELAY_PORTS,
SETPOINTS,
)
from .entity import LcnEntity
from .helpers import InputType
@ -32,12 +34,18 @@ def add_lcn_switch_entities(
entity_configs: Iterable[ConfigType],
) -> None:
"""Add entities for this domain."""
entities: list[LcnOutputSwitch | LcnRelaySwitch] = []
entities: list[
LcnOutputSwitch | LcnRelaySwitch | LcnRegulatorLockSwitch | LcnKeyLockSwitch
] = []
for entity_config in entity_configs:
if entity_config[CONF_DOMAIN_DATA][CONF_OUTPUT] in OUTPUT_PORTS:
entities.append(LcnOutputSwitch(entity_config, config_entry))
else: # in RELAY_PORTS
elif entity_config[CONF_DOMAIN_DATA][CONF_OUTPUT] in RELAY_PORTS:
entities.append(LcnRelaySwitch(entity_config, config_entry))
elif entity_config[CONF_DOMAIN_DATA][CONF_OUTPUT] in SETPOINTS:
entities.append(LcnRegulatorLockSwitch(entity_config, config_entry))
else: # in KEYS
entities.append(LcnKeyLockSwitch(entity_config, config_entry))
async_add_entities(entities)
@ -164,3 +172,118 @@ class LcnRelaySwitch(LcnEntity, SwitchEntity):
self._attr_is_on = input_obj.get_state(self.output.value)
self.async_write_ha_state()
class LcnRegulatorLockSwitch(LcnEntity, SwitchEntity):
"""Representation of a LCN switch for regulator locks."""
_attr_is_on = False
def __init__(self, config: ConfigType, config_entry: ConfigEntry) -> None:
"""Initialize the LCN switch."""
super().__init__(config, config_entry)
self.setpoint_variable = pypck.lcn_defs.Var[
config[CONF_DOMAIN_DATA][CONF_OUTPUT]
]
self.reg_id = pypck.lcn_defs.Var.to_set_point_id(self.setpoint_variable)
async def async_added_to_hass(self) -> None:
"""Run when entity about to be added to hass."""
await super().async_added_to_hass()
if not self.device_connection.is_group:
await self.device_connection.activate_status_request_handler(
self.setpoint_variable
)
async def async_will_remove_from_hass(self) -> None:
"""Run when entity will be removed from hass."""
await super().async_will_remove_from_hass()
if not self.device_connection.is_group:
await self.device_connection.cancel_status_request_handler(
self.setpoint_variable
)
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the entity on."""
if not await self.device_connection.lock_regulator(self.reg_id, True):
return
self._attr_is_on = True
self.async_write_ha_state()
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the entity off."""
if not await self.device_connection.lock_regulator(self.reg_id, False):
return
self._attr_is_on = False
self.async_write_ha_state()
def input_received(self, input_obj: InputType) -> None:
"""Set switch state when LCN input object (command) is received."""
if (
not isinstance(input_obj, pypck.inputs.ModStatusVar)
or input_obj.get_var() != self.setpoint_variable
):
return
self._attr_is_on = input_obj.get_value().is_locked_regulator()
self.async_write_ha_state()
class LcnKeyLockSwitch(LcnEntity, SwitchEntity):
"""Representation of a LCN switch for key locks."""
_attr_is_on = False
def __init__(self, config: ConfigType, config_entry: ConfigEntry) -> None:
"""Initialize the LCN switch."""
super().__init__(config, config_entry)
self.key = pypck.lcn_defs.Key[config[CONF_DOMAIN_DATA][CONF_OUTPUT]]
self.table_id = ord(self.key.name[0]) - 65
self.key_id = int(self.key.name[1]) - 1
async def async_added_to_hass(self) -> None:
"""Run when entity about to be added to hass."""
await super().async_added_to_hass()
if not self.device_connection.is_group:
await self.device_connection.activate_status_request_handler(self.key)
async def async_will_remove_from_hass(self) -> None:
"""Run when entity will be removed from hass."""
await super().async_will_remove_from_hass()
if not self.device_connection.is_group:
await self.device_connection.cancel_status_request_handler(self.key)
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the entity on."""
states = [pypck.lcn_defs.KeyLockStateModifier.NOCHANGE] * 8
states[self.key_id] = pypck.lcn_defs.KeyLockStateModifier.ON
if not await self.device_connection.lock_keys(self.table_id, states):
return
self._attr_is_on = True
self.async_write_ha_state()
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the entity off."""
states = [pypck.lcn_defs.KeyLockStateModifier.NOCHANGE] * 8
states[self.key_id] = pypck.lcn_defs.KeyLockStateModifier.OFF
if not await self.device_connection.lock_keys(self.table_id, states):
return
self._attr_is_on = False
self.async_write_ha_state()
def input_received(self, input_obj: InputType) -> None:
"""Set switch state when LCN input object (command) is received."""
if (
not isinstance(input_obj, pypck.inputs.ModStatusKeyLocks)
or self.key not in pypck.lcn_defs.Key
):
return
self._attr_is_on = input_obj.get_state(self.table_id, self.key_id)
self.async_write_ha_state()

View File

@ -93,6 +93,24 @@
"output": "RELAY2"
}
},
{
"address": [0, 7, false],
"name": "Switch_Regulator1",
"resource": "r1varsetpoint",
"domain": "switch",
"domain_data": {
"output": "R1VARSETPOINT"
}
},
{
"address": [0, 7, false],
"name": "Switch_KeyLock1",
"resource": "a1",
"domain": "switch",
"domain_data": {
"output": "A1"
}
},
{
"address": [0, 5, true],
"name": "Switch_Group5",

View File

@ -92,6 +92,24 @@
"output": "RELAY2"
}
},
{
"address": [0, 7, false],
"name": "Switch_Regulator1",
"resource": "r1varsetpoint",
"domain": "switch",
"domain_data": {
"output": "R1VARSETPOINT"
}
},
{
"address": [0, 7, false],
"name": "Switch_KeyLock1",
"resource": "a1",
"domain": "switch",
"domain_data": {
"output": "A1"
}
},
{
"address": [0, 5, true],
"name": "Switch_Group5",

View File

@ -93,6 +93,24 @@
"output": "RELAY2"
}
},
{
"address": [0, 7, false],
"name": "Switch_Regulator1",
"resource": "r1varsetpoint",
"domain": "switch",
"domain_data": {
"output": "R1VARSETPOINT"
}
},
{
"address": [0, 7, false],
"name": "Switch_KeyLock1",
"resource": "a1",
"domain": "switch",
"domain_data": {
"output": "A1"
}
},
{
"address": [0, 5, true],
"name": "Switch_Group5",

View File

@ -45,6 +45,52 @@
'state': 'off',
})
# ---
# name: test_setup_lcn_switch[switch.switch_keylock1-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': None,
'entity_id': 'switch.switch_keylock1',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Switch_KeyLock1',
'platform': 'lcn',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'lcn/config_entry_pchk.json-m000007-a1',
'unit_of_measurement': None,
})
# ---
# name: test_setup_lcn_switch[switch.switch_keylock1-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Switch_KeyLock1',
}),
'context': <ANY>,
'entity_id': 'switch.switch_keylock1',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_setup_lcn_switch[switch.switch_output1-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@ -137,6 +183,52 @@
'state': 'off',
})
# ---
# name: test_setup_lcn_switch[switch.switch_regulator1-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': None,
'entity_id': 'switch.switch_regulator1',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': None,
'original_icon': None,
'original_name': 'Switch_Regulator1',
'platform': 'lcn',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': 'lcn/config_entry_pchk.json-m000007-r1varsetpoint',
'unit_of_measurement': None,
})
# ---
# name: test_setup_lcn_switch[switch.switch_regulator1-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Switch_Regulator1',
}),
'context': <ANY>,
'entity_id': 'switch.switch_regulator1',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---
# name: test_setup_lcn_switch[switch.switch_relay1-entry]
EntityRegistryEntrySnapshot({
'aliases': set({

View File

@ -5,12 +5,19 @@ from unittest.mock import patch
from pypck.inputs import ModStatusBinSensors, ModStatusKeyLocks, ModStatusVar
from pypck.lcn_addr import LcnAddr
from pypck.lcn_defs import Var, VarValue
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components import automation, script
from homeassistant.components.automation import automations_with_entity
from homeassistant.components.lcn import DOMAIN
from homeassistant.components.lcn.helpers import get_device_connection
from homeassistant.components.script import scripts_with_entity
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE, Platform
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.helpers import entity_registry as er
import homeassistant.helpers.issue_registry as ir
from homeassistant.setup import async_setup_component
from .conftest import MockConfigEntry, init_integration
@ -131,3 +138,54 @@ async def test_unload_config_entry(hass: HomeAssistant, entry: MockConfigEntry)
assert hass.states.get(BINARY_SENSOR_LOCKREGULATOR1).state == STATE_UNAVAILABLE
assert hass.states.get(BINARY_SENSOR_SENSOR1).state == STATE_UNAVAILABLE
assert hass.states.get(BINARY_SENSOR_KEYLOCK).state == STATE_UNAVAILABLE
@pytest.mark.parametrize(
"entity_id", ["binary_sensor.sensor_lockregulator1", "binary_sensor.sensor_keylock"]
)
async def test_create_issue(
hass: HomeAssistant,
service_calls: list[ServiceCall],
issue_registry: ir.IssueRegistry,
entry: MockConfigEntry,
entity_id,
) -> None:
"""Test we create an issue when an automation or script is using a deprecated entity."""
assert await async_setup_component(
hass,
automation.DOMAIN,
{
automation.DOMAIN: {
"alias": "test",
"trigger": {"platform": "state", "entity_id": entity_id},
"action": {"action": "test.automation"},
}
},
)
assert await async_setup_component(
hass,
script.DOMAIN,
{
script.DOMAIN: {
"test": {
"sequence": {
"condition": "state",
"entity_id": entity_id,
"state": STATE_ON,
}
}
}
},
)
await init_integration(hass, entry)
assert automations_with_entity(hass, entity_id)[0] == "automation.test"
assert scripts_with_entity(hass, entity_id)[0] == "script.test"
assert issue_registry.async_get_issue(
DOMAIN, f"deprecated_binary_sensor_{entity_id}"
)
assert len(issue_registry.issues) == 1

View File

@ -2,9 +2,14 @@
from unittest.mock import patch
from pypck.inputs import ModStatusOutput, ModStatusRelays
from pypck.inputs import (
ModStatusKeyLocks,
ModStatusOutput,
ModStatusRelays,
ModStatusVar,
)
from pypck.lcn_addr import LcnAddr
from pypck.lcn_defs import RelayStateModifier
from pypck.lcn_defs import KeyLockStateModifier, RelayStateModifier, Var, VarValue
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.lcn.helpers import get_device_connection
@ -29,6 +34,8 @@ SWITCH_OUTPUT1 = "switch.switch_output1"
SWITCH_OUTPUT2 = "switch.switch_output2"
SWITCH_RELAY1 = "switch.switch_relay1"
SWITCH_RELAY2 = "switch.switch_relay2"
SWITCH_REGULATOR1 = "switch.switch_regulator1"
SWITCH_KEYLOCKK1 = "switch.switch_keylock1"
async def test_setup_lcn_switch(
@ -204,6 +211,170 @@ async def test_relay_turn_off(hass: HomeAssistant, entry: MockConfigEntry) -> No
assert state.state == STATE_OFF
async def test_regulatorlock_turn_on(
hass: HomeAssistant, entry: MockConfigEntry
) -> None:
"""Test the regulator lock switch turns on."""
await init_integration(hass, entry)
with patch.object(MockModuleConnection, "lock_regulator") as lock_regulator:
# command failed
lock_regulator.return_value = False
await hass.services.async_call(
DOMAIN_SWITCH,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: SWITCH_REGULATOR1},
blocking=True,
)
lock_regulator.assert_awaited_with(0, True)
state = hass.states.get(SWITCH_REGULATOR1)
assert state.state == STATE_OFF
# command success
lock_regulator.reset_mock(return_value=True)
lock_regulator.return_value = True
await hass.services.async_call(
DOMAIN_SWITCH,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: SWITCH_REGULATOR1},
blocking=True,
)
lock_regulator.assert_awaited_with(0, True)
state = hass.states.get(SWITCH_REGULATOR1)
assert state.state == STATE_ON
async def test_regulatorlock_turn_off(
hass: HomeAssistant, entry: MockConfigEntry
) -> None:
"""Test the regulator lock switch turns off."""
await init_integration(hass, entry)
with patch.object(MockModuleConnection, "lock_regulator") as lock_regulator:
state = hass.states.get(SWITCH_REGULATOR1)
state.state = STATE_ON
# command failed
lock_regulator.return_value = False
await hass.services.async_call(
DOMAIN_SWITCH,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: SWITCH_REGULATOR1},
blocking=True,
)
lock_regulator.assert_awaited_with(0, False)
state = hass.states.get(SWITCH_REGULATOR1)
assert state.state == STATE_ON
# command success
lock_regulator.reset_mock(return_value=True)
lock_regulator.return_value = True
await hass.services.async_call(
DOMAIN_SWITCH,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: SWITCH_REGULATOR1},
blocking=True,
)
lock_regulator.assert_awaited_with(0, False)
state = hass.states.get(SWITCH_REGULATOR1)
assert state.state == STATE_OFF
async def test_keylock_turn_on(hass: HomeAssistant, entry: MockConfigEntry) -> None:
"""Test the keylock switch turns on."""
await init_integration(hass, entry)
with patch.object(MockModuleConnection, "lock_keys") as lock_keys:
states = [KeyLockStateModifier.NOCHANGE] * 8
states[0] = KeyLockStateModifier.ON
# command failed
lock_keys.return_value = False
await hass.services.async_call(
DOMAIN_SWITCH,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: SWITCH_KEYLOCKK1},
blocking=True,
)
lock_keys.assert_awaited_with(0, states)
state = hass.states.get(SWITCH_KEYLOCKK1)
assert state.state == STATE_OFF
# command success
lock_keys.reset_mock(return_value=True)
lock_keys.return_value = True
await hass.services.async_call(
DOMAIN_SWITCH,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: SWITCH_KEYLOCKK1},
blocking=True,
)
lock_keys.assert_awaited_with(0, states)
state = hass.states.get(SWITCH_KEYLOCKK1)
assert state.state == STATE_ON
async def test_keylock_turn_off(hass: HomeAssistant, entry: MockConfigEntry) -> None:
"""Test the keylock switch turns off."""
await init_integration(hass, entry)
with patch.object(MockModuleConnection, "lock_keys") as lock_keys:
states = [KeyLockStateModifier.NOCHANGE] * 8
states[0] = KeyLockStateModifier.OFF
state = hass.states.get(SWITCH_KEYLOCKK1)
state.state = STATE_ON
# command failed
lock_keys.return_value = False
await hass.services.async_call(
DOMAIN_SWITCH,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: SWITCH_KEYLOCKK1},
blocking=True,
)
lock_keys.assert_awaited_with(0, states)
state = hass.states.get(SWITCH_KEYLOCKK1)
assert state.state == STATE_ON
# command success
lock_keys.reset_mock(return_value=True)
lock_keys.return_value = True
await hass.services.async_call(
DOMAIN_SWITCH,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: SWITCH_KEYLOCKK1},
blocking=True,
)
lock_keys.assert_awaited_with(0, states)
state = hass.states.get(SWITCH_KEYLOCKK1)
assert state.state == STATE_OFF
async def test_pushed_output_status_change(
hass: HomeAssistant, entry: MockConfigEntry
) -> None:
@ -259,6 +430,64 @@ async def test_pushed_relay_status_change(
assert state.state == STATE_OFF
async def test_pushed_regulatorlock_status_change(
hass: HomeAssistant, entry: MockConfigEntry
) -> None:
"""Test the regulator lock switch changes its state on status received."""
await init_integration(hass, entry)
device_connection = get_device_connection(hass, (0, 7, False), entry)
address = LcnAddr(0, 7, False)
states = [False] * 8
# push status "on"
states[0] = True
inp = ModStatusVar(address, Var.R1VARSETPOINT, VarValue(0x8000))
await device_connection.async_process_input(inp)
await hass.async_block_till_done()
state = hass.states.get(SWITCH_REGULATOR1)
assert state.state == STATE_ON
# push status "off"
states[0] = False
inp = ModStatusVar(address, Var.R1VARSETPOINT, VarValue(0x7FFF))
await device_connection.async_process_input(inp)
await hass.async_block_till_done()
state = hass.states.get(SWITCH_REGULATOR1)
assert state.state == STATE_OFF
async def test_pushed_keylock_status_change(
hass: HomeAssistant, entry: MockConfigEntry
) -> None:
"""Test the keylock switch changes its state on status received."""
await init_integration(hass, entry)
device_connection = get_device_connection(hass, (0, 7, False), entry)
address = LcnAddr(0, 7, False)
states = [[False] * 8 for i in range(4)]
states[0][0] = True
# push status "on"
inp = ModStatusKeyLocks(address, states)
await device_connection.async_process_input(inp)
await hass.async_block_till_done()
state = hass.states.get(SWITCH_KEYLOCKK1)
assert state.state == STATE_ON
# push status "off"
states[0][0] = False
inp = ModStatusKeyLocks(address, states)
await device_connection.async_process_input(inp)
await hass.async_block_till_done()
state = hass.states.get(SWITCH_KEYLOCKK1)
assert state.state == STATE_OFF
async def test_unload_config_entry(hass: HomeAssistant, entry: MockConfigEntry) -> None:
"""Test the switch is removed when the config entry is unloaded."""
await init_integration(hass, entry)