mirror of
https://github.com/home-assistant/core.git
synced 2025-07-13 00:07:10 +00:00
Add switch entities for LCN key-locks and regulator-locks (#127731)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
parent
35a9d502af
commit
c9aba288b4
@ -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()
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
#
|
||||
|
@ -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()
|
||||
|
||||
|
||||
|
@ -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": {
|
||||
|
@ -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()
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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({
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user