Add device_id parameter to LCN actions (service calls) (#129590)

pull/133492/head
Andre Lengwenus 2024-12-18 14:35:02 +01:00 committed by GitHub
parent c06bc53724
commit a46a0ad2b4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 398 additions and 69 deletions

View File

@ -31,6 +31,7 @@ from .const import (
CONF_SK_NUM_TRIES,
CONF_TRANSITION,
CONNECTION,
DEVICE_CONNECTIONS,
DOMAIN,
PLATFORMS,
)
@ -102,6 +103,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
_LOGGER.debug('LCN connected to "%s"', config_entry.title)
hass.data[DOMAIN][config_entry.entry_id] = {
CONNECTION: lcn_connection,
DEVICE_CONNECTIONS: {},
ADD_ENTITIES_CALLBACKS: {},
}
# Update config_entry with LCN device serials

View File

@ -20,6 +20,7 @@ DEFAULT_NAME = "pchk"
ADD_ENTITIES_CALLBACKS = "add_entities_callbacks"
CONNECTION = "connection"
DEVICE_CONNECTIONS = "device_connections"
CONF_HARDWARE_SERIAL = "hardware_serial"
CONF_SOFTWARE_SERIAL = "software_serial"
CONF_HARDWARE_TYPE = "hardware_type"

View File

@ -38,6 +38,7 @@ from .const import (
CONF_SCENES,
CONF_SOFTWARE_SERIAL,
CONNECTION,
DEVICE_CONNECTIONS,
DOMAIN,
LED_PORTS,
LOGICOP_PORTS,
@ -237,7 +238,7 @@ def register_lcn_address_devices(
identifiers = {(DOMAIN, generate_unique_id(config_entry.entry_id, address))}
if device_config[CONF_ADDRESS][2]: # is group
device_model = f"LCN group (g{address[0]:03d}{address[1]:03d})"
device_model = "LCN group"
sw_version = None
else: # is module
hardware_type = device_config[CONF_HARDWARE_TYPE]
@ -245,10 +246,10 @@ def register_lcn_address_devices(
hardware_name = pypck.lcn_defs.HARDWARE_DESCRIPTIONS[hardware_type]
else:
hardware_name = pypck.lcn_defs.HARDWARE_DESCRIPTIONS[-1]
device_model = f"{hardware_name} (m{address[0]:03d}{address[1]:03d})"
device_model = f"{hardware_name}"
sw_version = f"{device_config[CONF_SOFTWARE_SERIAL]:06X}"
device_registry.async_get_or_create(
device_entry = device_registry.async_get_or_create(
config_entry_id=config_entry.entry_id,
identifiers=identifiers,
via_device=host_identifiers,
@ -258,6 +259,10 @@ def register_lcn_address_devices(
model=device_model,
)
hass.data[DOMAIN][config_entry.entry_id][DEVICE_CONNECTIONS][
device_entry.id
] = get_device_connection(hass, address, config_entry)
async def async_update_device_config(
device_connection: DeviceConnectionType, device_config: ConfigType

View File

@ -8,12 +8,21 @@ import voluptuous as vol
from homeassistant.const import (
CONF_ADDRESS,
CONF_BRIGHTNESS,
CONF_DEVICE_ID,
CONF_HOST,
CONF_STATE,
CONF_UNIT_OF_MEASUREMENT,
)
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.core import (
HomeAssistant,
ServiceCall,
ServiceResponse,
SupportsResponse,
)
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers import device_registry as dr
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from .const import (
CONF_KEYS,
@ -30,6 +39,7 @@ from .const import (
CONF_TRANSITION,
CONF_VALUE,
CONF_VARIABLE,
DEVICE_CONNECTIONS,
DOMAIN,
LED_PORTS,
LED_STATUS,
@ -53,7 +63,13 @@ from .helpers import (
class LcnServiceCall:
"""Parent class for all LCN service calls."""
schema = vol.Schema({vol.Required(CONF_ADDRESS): is_address})
schema = vol.Schema(
{
vol.Optional(CONF_DEVICE_ID): cv.string,
vol.Optional(CONF_ADDRESS): is_address,
}
)
supports_response = SupportsResponse.NONE
def __init__(self, hass: HomeAssistant) -> None:
"""Initialize service call."""
@ -61,8 +77,37 @@ class LcnServiceCall:
def get_device_connection(self, service: ServiceCall) -> DeviceConnectionType:
"""Get address connection object."""
address, host_name = service.data[CONF_ADDRESS]
if CONF_DEVICE_ID not in service.data and CONF_ADDRESS not in service.data:
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="no_device_identifier",
)
if CONF_DEVICE_ID in service.data:
device_id = service.data[CONF_DEVICE_ID]
device_registry = dr.async_get(self.hass)
if not (device := device_registry.async_get(device_id)):
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="invalid_device_id",
translation_placeholders={"device_id": device_id},
)
return self.hass.data[DOMAIN][device.primary_config_entry][
DEVICE_CONNECTIONS
][device_id]
async_create_issue(
self.hass,
DOMAIN,
"deprecated_address_parameter",
breaks_in_ha_version="2025.6.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="deprecated_address_parameter",
)
address, host_name = service.data[CONF_ADDRESS]
for config_entry in self.hass.config_entries.async_entries(DOMAIN):
if config_entry.data[CONF_HOST] == host_name:
device_connection = get_device_connection(
@ -73,7 +118,7 @@ class LcnServiceCall:
return device_connection
raise ValueError("Invalid host name.")
async def async_call_service(self, service: ServiceCall) -> None:
async def async_call_service(self, service: ServiceCall) -> ServiceResponse:
"""Execute service call."""
raise NotImplementedError

View File

@ -2,8 +2,76 @@
output_abs:
fields:
device_id:
example: "91aa039a2fb6e0b9f9ec7eb219a6b7d2"
selector: &device_selector
device:
filter:
- integration: lcn
model: LCN group
- integration: lcn
model: UnknownModuleType
- integration: lcn
model: LCN-SW1.0
- integration: lcn
model: LCN-SW1.1
- integration: lcn
model: LCN-UP1.0
- integration: lcn
model: LCN-UP2
- integration: lcn
model: LCN-SW2
- integration: lcn
model: LCN-UP-Profi1-Plus
- integration: lcn
model: LCN-DI12
- integration: lcn
model: LCN-HU
- integration: lcn
model: LCN-SH
- integration: lcn
model: LCN-UP2
- integration: lcn
model: LCN-UPP
- integration: lcn
model: LCN-SK
- integration: lcn
model: LCN-LD
- integration: lcn
model: LCN-SH-Plus
- integration: lcn
model: LCN-UPS
- integration: lcn
model: LCN_UPS24V
- integration: lcn
model: LCN-GTM
- integration: lcn
model: LCN-SHS
- integration: lcn
model: LCN-ESD
- integration: lcn
model: LCN-EB2
- integration: lcn
model: LCN-MRS
- integration: lcn
model: LCN-EB11
- integration: lcn
model: LCN-UMR
- integration: lcn
model: LCN-UPU
- integration: lcn
model: LCN-UMR24V
- integration: lcn
model: LCN-SHD
- integration: lcn
model: LCN-SHU
- integration: lcn
model: LCN-SR6
- integration: lcn
model: LCN-UMF
- integration: lcn
model: LCN-WBH
address:
required: true
example: "myhome.s0.m7"
selector:
text:
@ -34,8 +102,10 @@ output_abs:
output_rel:
fields:
device_id:
example: "91aa039a2fb6e0b9f9ec7eb219a6b7d2"
selector: *device_selector
address:
required: true
example: "myhome.s0.m7"
selector:
text:
@ -58,8 +128,10 @@ output_rel:
output_toggle:
fields:
device_id:
example: "91aa039a2fb6e0b9f9ec7eb219a6b7d2"
selector: *device_selector
address:
required: true
example: "myhome.s0.m7"
selector:
text:
@ -83,8 +155,10 @@ output_toggle:
relays:
fields:
device_id:
example: "91aa039a2fb6e0b9f9ec7eb219a6b7d2"
selector: *device_selector
address:
required: true
example: "myhome.s0.m7"
selector:
text:
@ -96,8 +170,10 @@ relays:
led:
fields:
device_id:
example: "91aa039a2fb6e0b9f9ec7eb219a6b7d2"
selector: *device_selector
address:
required: true
example: "myhome.s0.m7"
selector:
text:
@ -130,8 +206,10 @@ led:
var_abs:
fields:
device_id:
example: "91aa039a2fb6e0b9f9ec7eb219a6b7d2"
selector: *device_selector
address:
required: true
example: "myhome.s0.m7"
selector:
text:
@ -197,8 +275,10 @@ var_abs:
var_reset:
fields:
device_id:
example: "91aa039a2fb6e0b9f9ec7eb219a6b7d2"
selector: *device_selector
address:
required: true
example: "myhome.s0.m7"
selector:
text:
@ -230,8 +310,10 @@ var_reset:
var_rel:
fields:
device_id:
example: "91aa039a2fb6e0b9f9ec7eb219a6b7d2"
selector: *device_selector
address:
required: true
example: "myhome.s0.m7"
selector:
text:
@ -321,8 +403,10 @@ var_rel:
lock_regulator:
fields:
device_id:
example: "91aa039a2fb6e0b9f9ec7eb219a6b7d2"
selector: *device_selector
address:
required: true
example: "myhome.s0.m7"
selector:
text:
@ -355,8 +439,10 @@ lock_regulator:
send_keys:
fields:
device_id:
example: "91aa039a2fb6e0b9f9ec7eb219a6b7d2"
selector: *device_selector
address:
required: true
example: "myhome.s0.m7"
selector:
text:
@ -402,8 +488,10 @@ send_keys:
lock_keys:
fields:
device_id:
example: "91aa039a2fb6e0b9f9ec7eb219a6b7d2"
selector: *device_selector
address:
required: true
example: "myhome.s0.m7"
selector:
text:
@ -445,8 +533,10 @@ lock_keys:
dyn_text:
fields:
device_id:
example: "91aa039a2fb6e0b9f9ec7eb219a6b7d2"
selector: *device_selector
address:
required: true
example: "myhome.s0.m7"
selector:
text:
@ -464,8 +554,10 @@ dyn_text:
pck:
fields:
device_id:
example: "91aa039a2fb6e0b9f9ec7eb219a6b7d2"
selector: *device_selector
address:
required: true
example: "myhome.s0.m7"
selector:
text:

View File

@ -70,6 +70,10 @@
"deprecated_keylock_sensor": {
"title": "Deprecated LCN key lock binary sensor",
"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."
},
"deprecated_address_parameter": {
"title": "Deprecated 'address' parameter",
"description": "The 'address' parameter in the LCN service calls is deprecated. The 'devide_id' parameter should be used going forward.\n\nPlease adjust your automations or scripts to fix this issue."
}
},
"services": {
@ -77,6 +81,10 @@
"name": "Output absolute brightness",
"description": "Sets absolute brightness of output port in percent.",
"fields": {
"device_id": {
"name": "[%key:common::config_flow::data::device%]",
"description": "The device_id of the LCN module or group."
},
"address": {
"name": "Address",
"description": "Module address."
@ -99,6 +107,10 @@
"name": "Output relative brightness",
"description": "Sets relative brightness of output port in percent.",
"fields": {
"device_id": {
"name": "[%key:common::config_flow::data::device%]",
"description": "[%key:component::lcn::services::output_abs::fields::device_id::description%]"
},
"address": {
"name": "Address",
"description": "[%key:component::lcn::services::output_abs::fields::address::description%]"
@ -117,6 +129,10 @@
"name": "Toggle output",
"description": "Toggles output port.",
"fields": {
"device_id": {
"name": "[%key:common::config_flow::data::device%]",
"description": "[%key:component::lcn::services::output_abs::fields::device_id::description%]"
},
"address": {
"name": "Address",
"description": "[%key:component::lcn::services::output_abs::fields::address::description%]"
@ -135,6 +151,10 @@
"name": "Relays",
"description": "Sets the relays status.",
"fields": {
"device_id": {
"name": "[%key:common::config_flow::data::device%]",
"description": "[%key:component::lcn::services::output_abs::fields::device_id::description%]"
},
"address": {
"name": "Address",
"description": "[%key:component::lcn::services::output_abs::fields::address::description%]"
@ -149,6 +169,10 @@
"name": "LED",
"description": "Sets the led state.",
"fields": {
"device_id": {
"name": "[%key:common::config_flow::data::device%]",
"description": "[%key:component::lcn::services::output_abs::fields::device_id::description%]"
},
"address": {
"name": "Address",
"description": "[%key:component::lcn::services::output_abs::fields::address::description%]"
@ -167,6 +191,10 @@
"name": "Set absolute variable",
"description": "Sets absolute value of a variable or setpoint.",
"fields": {
"device_id": {
"name": "[%key:common::config_flow::data::device%]",
"description": "[%key:component::lcn::services::output_abs::fields::device_id::description%]"
},
"address": {
"name": "Address",
"description": "[%key:component::lcn::services::output_abs::fields::address::description%]"
@ -189,6 +217,10 @@
"name": "Reset variable",
"description": "Resets value of variable or setpoint.",
"fields": {
"device_id": {
"name": "[%key:common::config_flow::data::device%]",
"description": "[%key:component::lcn::services::output_abs::fields::device_id::description%]"
},
"address": {
"name": "Address",
"description": "[%key:component::lcn::services::output_abs::fields::address::description%]"
@ -203,6 +235,10 @@
"name": "Shift variable",
"description": "Shift value of a variable, setpoint or threshold.",
"fields": {
"device_id": {
"name": "[%key:common::config_flow::data::device%]",
"description": "[%key:component::lcn::services::output_abs::fields::device_id::description%]"
},
"address": {
"name": "Address",
"description": "[%key:component::lcn::services::output_abs::fields::address::description%]"
@ -229,6 +265,10 @@
"name": "Lock regulator",
"description": "Locks a regulator setpoint.",
"fields": {
"device_id": {
"name": "[%key:common::config_flow::data::device%]",
"description": "[%key:component::lcn::services::output_abs::fields::device_id::description%]"
},
"address": {
"name": "Address",
"description": "[%key:component::lcn::services::output_abs::fields::address::description%]"
@ -247,6 +287,10 @@
"name": "Send keys",
"description": "Sends keys (which executes bound commands).",
"fields": {
"device_id": {
"name": "[%key:common::config_flow::data::device%]",
"description": "[%key:component::lcn::services::output_abs::fields::device_id::description%]"
},
"address": {
"name": "Address",
"description": "[%key:component::lcn::services::output_abs::fields::address::description%]"
@ -273,6 +317,10 @@
"name": "Lock keys",
"description": "Locks keys.",
"fields": {
"device_id": {
"name": "[%key:common::config_flow::data::device%]",
"description": "[%key:component::lcn::services::output_abs::fields::device_id::description%]"
},
"address": {
"name": "Address",
"description": "[%key:component::lcn::services::output_abs::fields::address::description%]"
@ -299,6 +347,10 @@
"name": "Dynamic text",
"description": "Sends dynamic text to LCN-GTxD displays.",
"fields": {
"device_id": {
"name": "[%key:common::config_flow::data::device%]",
"description": "[%key:component::lcn::services::output_abs::fields::device_id::description%]"
},
"address": {
"name": "Address",
"description": "[%key:component::lcn::services::output_abs::fields::address::description%]"
@ -317,6 +369,10 @@
"name": "PCK",
"description": "Sends arbitrary PCK command.",
"fields": {
"device_id": {
"name": "[%key:common::config_flow::data::device%]",
"description": "[%key:component::lcn::services::output_abs::fields::device_id::description%]"
},
"address": {
"name": "Address",
"description": "[%key:component::lcn::services::output_abs::fields::address::description%]"
@ -326,6 +382,39 @@
"description": "PCK command (without address header)."
}
}
},
"address_to_device_id": {
"name": "Address to device id",
"description": "Convert LCN address to device id.",
"fields": {
"id": {
"name": "Module or group id",
"description": "Target module or group id."
},
"segment_id": {
"name": "Segment id",
"description": "Target segment id."
},
"type": {
"name": "Type",
"description": "Target type."
},
"host": {
"name": "Host name",
"description": "Host name as given in the integration panel."
}
}
}
},
"exceptions": {
"no_device_identifier": {
"message": "No device identifier provided. Please provide the device id."
},
"invalid_address": {
"message": "LCN device for given address has not been configured."
},
"invalid_device_id": {
"message": "LCN device for given device id has not been configured."
}
}
}

View File

@ -26,22 +26,37 @@ from homeassistant.components.lcn.services import LcnService
from homeassistant.const import (
CONF_ADDRESS,
CONF_BRIGHTNESS,
CONF_DEVICE_ID,
CONF_STATE,
CONF_UNIT_OF_MEASUREMENT,
)
from homeassistant.core import HomeAssistant
import homeassistant.helpers.issue_registry as ir
from homeassistant.setup import async_setup_component
from .conftest import (
MockConfigEntry,
MockModuleConnection,
MockPchkConnectionManager,
get_device,
init_integration,
)
@patch("homeassistant.components.lcn.PchkConnectionManager", MockPchkConnectionManager)
async def test_service_output_abs(hass: HomeAssistant, entry: MockConfigEntry) -> None:
def device_config(
hass: HomeAssistant, entry: MockConfigEntry, config_type: str
) -> dict[str, str]:
"""Return test device config depending on type."""
if config_type == CONF_ADDRESS:
return {CONF_ADDRESS: "pchk.s0.m7"}
return {CONF_DEVICE_ID: get_device(hass, entry, (0, 7, False)).id}
@pytest.mark.parametrize("config_type", [CONF_ADDRESS, CONF_DEVICE_ID])
async def test_service_output_abs(
hass: HomeAssistant,
entry: MockConfigEntry,
config_type: str,
) -> None:
"""Test output_abs service."""
await async_setup_component(hass, "persistent_notification", {})
await init_integration(hass, entry)
@ -51,7 +66,7 @@ async def test_service_output_abs(hass: HomeAssistant, entry: MockConfigEntry) -
DOMAIN,
LcnService.OUTPUT_ABS,
{
CONF_ADDRESS: "pchk.s0.m7",
**device_config(hass, entry, config_type),
CONF_OUTPUT: "output1",
CONF_BRIGHTNESS: 100,
CONF_TRANSITION: 5,
@ -62,8 +77,12 @@ async def test_service_output_abs(hass: HomeAssistant, entry: MockConfigEntry) -
dim_output.assert_awaited_with(0, 100, 9)
@patch("homeassistant.components.lcn.PchkConnectionManager", MockPchkConnectionManager)
async def test_service_output_rel(hass: HomeAssistant, entry: MockConfigEntry) -> None:
@pytest.mark.parametrize("config_type", [CONF_ADDRESS, CONF_DEVICE_ID])
async def test_service_output_rel(
hass: HomeAssistant,
entry: MockConfigEntry,
config_type: str,
) -> None:
"""Test output_rel service."""
await async_setup_component(hass, "persistent_notification", {})
await init_integration(hass, entry)
@ -73,7 +92,7 @@ async def test_service_output_rel(hass: HomeAssistant, entry: MockConfigEntry) -
DOMAIN,
LcnService.OUTPUT_REL,
{
CONF_ADDRESS: "pchk.s0.m7",
**device_config(hass, entry, config_type),
CONF_OUTPUT: "output1",
CONF_BRIGHTNESS: 25,
},
@ -83,9 +102,11 @@ async def test_service_output_rel(hass: HomeAssistant, entry: MockConfigEntry) -
rel_output.assert_awaited_with(0, 25)
@patch("homeassistant.components.lcn.PchkConnectionManager", MockPchkConnectionManager)
@pytest.mark.parametrize("config_type", [CONF_ADDRESS, CONF_DEVICE_ID])
async def test_service_output_toggle(
hass: HomeAssistant, entry: MockConfigEntry
hass: HomeAssistant,
entry: MockConfigEntry,
config_type: str,
) -> None:
"""Test output_toggle service."""
await async_setup_component(hass, "persistent_notification", {})
@ -96,7 +117,7 @@ async def test_service_output_toggle(
DOMAIN,
LcnService.OUTPUT_TOGGLE,
{
CONF_ADDRESS: "pchk.s0.m7",
**device_config(hass, entry, config_type),
CONF_OUTPUT: "output1",
CONF_TRANSITION: 5,
},
@ -106,8 +127,12 @@ async def test_service_output_toggle(
toggle_output.assert_awaited_with(0, 9)
@patch("homeassistant.components.lcn.PchkConnectionManager", MockPchkConnectionManager)
async def test_service_relays(hass: HomeAssistant, entry: MockConfigEntry) -> None:
@pytest.mark.parametrize("config_type", [CONF_ADDRESS, CONF_DEVICE_ID])
async def test_service_relays(
hass: HomeAssistant,
entry: MockConfigEntry,
config_type: str,
) -> None:
"""Test relays service."""
await async_setup_component(hass, "persistent_notification", {})
await init_integration(hass, entry)
@ -116,7 +141,7 @@ async def test_service_relays(hass: HomeAssistant, entry: MockConfigEntry) -> No
await hass.services.async_call(
DOMAIN,
LcnService.RELAYS,
{CONF_ADDRESS: "pchk.s0.m7", CONF_STATE: "0011TT--"},
{**device_config(hass, entry, config_type), CONF_STATE: "0011TT--"},
blocking=True,
)
@ -126,8 +151,12 @@ async def test_service_relays(hass: HomeAssistant, entry: MockConfigEntry) -> No
control_relays.assert_awaited_with(relay_states)
@patch("homeassistant.components.lcn.PchkConnectionManager", MockPchkConnectionManager)
async def test_service_led(hass: HomeAssistant, entry: MockConfigEntry) -> None:
@pytest.mark.parametrize("config_type", [CONF_ADDRESS, CONF_DEVICE_ID])
async def test_service_led(
hass: HomeAssistant,
entry: MockConfigEntry,
config_type: str,
) -> None:
"""Test led service."""
await async_setup_component(hass, "persistent_notification", {})
await init_integration(hass, entry)
@ -136,7 +165,11 @@ async def test_service_led(hass: HomeAssistant, entry: MockConfigEntry) -> None:
await hass.services.async_call(
DOMAIN,
LcnService.LED,
{CONF_ADDRESS: "pchk.s0.m7", CONF_LED: "led6", CONF_STATE: "blink"},
{
**device_config(hass, entry, config_type),
CONF_LED: "led6",
CONF_STATE: "blink",
},
blocking=True,
)
@ -146,8 +179,12 @@ async def test_service_led(hass: HomeAssistant, entry: MockConfigEntry) -> None:
control_led.assert_awaited_with(led, led_state)
@patch("homeassistant.components.lcn.PchkConnectionManager", MockPchkConnectionManager)
async def test_service_var_abs(hass: HomeAssistant, entry: MockConfigEntry) -> None:
@pytest.mark.parametrize("config_type", [CONF_ADDRESS, CONF_DEVICE_ID])
async def test_service_var_abs(
hass: HomeAssistant,
entry: MockConfigEntry,
config_type: str,
) -> None:
"""Test var_abs service."""
await async_setup_component(hass, "persistent_notification", {})
await init_integration(hass, entry)
@ -157,7 +194,7 @@ async def test_service_var_abs(hass: HomeAssistant, entry: MockConfigEntry) -> N
DOMAIN,
LcnService.VAR_ABS,
{
CONF_ADDRESS: "pchk.s0.m7",
**device_config(hass, entry, config_type),
CONF_VARIABLE: "var1",
CONF_VALUE: 75,
CONF_UNIT_OF_MEASUREMENT: "%",
@ -170,8 +207,12 @@ async def test_service_var_abs(hass: HomeAssistant, entry: MockConfigEntry) -> N
)
@patch("homeassistant.components.lcn.PchkConnectionManager", MockPchkConnectionManager)
async def test_service_var_rel(hass: HomeAssistant, entry: MockConfigEntry) -> None:
@pytest.mark.parametrize("config_type", [CONF_ADDRESS, CONF_DEVICE_ID])
async def test_service_var_rel(
hass: HomeAssistant,
entry: MockConfigEntry,
config_type: str,
) -> None:
"""Test var_rel service."""
await async_setup_component(hass, "persistent_notification", {})
await init_integration(hass, entry)
@ -181,7 +222,7 @@ async def test_service_var_rel(hass: HomeAssistant, entry: MockConfigEntry) -> N
DOMAIN,
LcnService.VAR_REL,
{
CONF_ADDRESS: "pchk.s0.m7",
**device_config(hass, entry, config_type),
CONF_VARIABLE: "var1",
CONF_VALUE: 10,
CONF_UNIT_OF_MEASUREMENT: "%",
@ -198,8 +239,12 @@ async def test_service_var_rel(hass: HomeAssistant, entry: MockConfigEntry) -> N
)
@patch("homeassistant.components.lcn.PchkConnectionManager", MockPchkConnectionManager)
async def test_service_var_reset(hass: HomeAssistant, entry: MockConfigEntry) -> None:
@pytest.mark.parametrize("config_type", [CONF_ADDRESS, CONF_DEVICE_ID])
async def test_service_var_reset(
hass: HomeAssistant,
entry: MockConfigEntry,
config_type: str,
) -> None:
"""Test var_reset service."""
await async_setup_component(hass, "persistent_notification", {})
await init_integration(hass, entry)
@ -208,16 +253,18 @@ async def test_service_var_reset(hass: HomeAssistant, entry: MockConfigEntry) ->
await hass.services.async_call(
DOMAIN,
LcnService.VAR_RESET,
{CONF_ADDRESS: "pchk.s0.m7", CONF_VARIABLE: "var1"},
{**device_config(hass, entry, config_type), CONF_VARIABLE: "var1"},
blocking=True,
)
var_reset.assert_awaited_with(pypck.lcn_defs.Var["VAR1"])
@patch("homeassistant.components.lcn.PchkConnectionManager", MockPchkConnectionManager)
@pytest.mark.parametrize("config_type", [CONF_ADDRESS, CONF_DEVICE_ID])
async def test_service_lock_regulator(
hass: HomeAssistant, entry: MockConfigEntry
hass: HomeAssistant,
entry: MockConfigEntry,
config_type: str,
) -> None:
"""Test lock_regulator service."""
await async_setup_component(hass, "persistent_notification", {})
@ -228,7 +275,7 @@ async def test_service_lock_regulator(
DOMAIN,
LcnService.LOCK_REGULATOR,
{
CONF_ADDRESS: "pchk.s0.m7",
**device_config(hass, entry, config_type),
CONF_SETPOINT: "r1varsetpoint",
CONF_STATE: True,
},
@ -238,8 +285,12 @@ async def test_service_lock_regulator(
lock_regulator.assert_awaited_with(0, True)
@patch("homeassistant.components.lcn.PchkConnectionManager", MockPchkConnectionManager)
async def test_service_send_keys(hass: HomeAssistant, entry: MockConfigEntry) -> None:
@pytest.mark.parametrize("config_type", [CONF_ADDRESS, CONF_DEVICE_ID])
async def test_service_send_keys(
hass: HomeAssistant,
entry: MockConfigEntry,
config_type: str,
) -> None:
"""Test send_keys service."""
await async_setup_component(hass, "persistent_notification", {})
await init_integration(hass, entry)
@ -248,7 +299,11 @@ async def test_service_send_keys(hass: HomeAssistant, entry: MockConfigEntry) ->
await hass.services.async_call(
DOMAIN,
LcnService.SEND_KEYS,
{CONF_ADDRESS: "pchk.s0.m7", CONF_KEYS: "a1a5d8", CONF_STATE: "hit"},
{
**device_config(hass, entry, config_type),
CONF_KEYS: "a1a5d8",
CONF_STATE: "hit",
},
blocking=True,
)
@ -260,9 +315,11 @@ async def test_service_send_keys(hass: HomeAssistant, entry: MockConfigEntry) ->
send_keys.assert_awaited_with(keys, pypck.lcn_defs.SendKeyCommand["HIT"])
@patch("homeassistant.components.lcn.PchkConnectionManager", MockPchkConnectionManager)
@pytest.mark.parametrize("config_type", [CONF_ADDRESS, CONF_DEVICE_ID])
async def test_service_send_keys_hit_deferred(
hass: HomeAssistant, entry: MockConfigEntry
hass: HomeAssistant,
entry: MockConfigEntry,
config_type: str,
) -> None:
"""Test send_keys (hit_deferred) service."""
await async_setup_component(hass, "persistent_notification", {})
@ -281,7 +338,7 @@ async def test_service_send_keys_hit_deferred(
DOMAIN,
LcnService.SEND_KEYS,
{
CONF_ADDRESS: "pchk.s0.m7",
**device_config(hass, entry, config_type),
CONF_KEYS: "a1a5d8",
CONF_TIME: 5,
CONF_TIME_UNIT: "s",
@ -304,7 +361,7 @@ async def test_service_send_keys_hit_deferred(
DOMAIN,
LcnService.SEND_KEYS,
{
CONF_ADDRESS: "pchk.s0.m7",
**device_config(hass, entry, config_type),
CONF_KEYS: "a1a5d8",
CONF_STATE: "make",
CONF_TIME: 5,
@ -314,8 +371,12 @@ async def test_service_send_keys_hit_deferred(
)
@patch("homeassistant.components.lcn.PchkConnectionManager", MockPchkConnectionManager)
async def test_service_lock_keys(hass: HomeAssistant, entry: MockConfigEntry) -> None:
@pytest.mark.parametrize("config_type", [CONF_ADDRESS, CONF_DEVICE_ID])
async def test_service_lock_keys(
hass: HomeAssistant,
entry: MockConfigEntry,
config_type: str,
) -> None:
"""Test lock_keys service."""
await async_setup_component(hass, "persistent_notification", {})
await init_integration(hass, entry)
@ -324,7 +385,11 @@ async def test_service_lock_keys(hass: HomeAssistant, entry: MockConfigEntry) ->
await hass.services.async_call(
DOMAIN,
LcnService.LOCK_KEYS,
{CONF_ADDRESS: "pchk.s0.m7", CONF_TABLE: "a", CONF_STATE: "0011TT--"},
{
**device_config(hass, entry, config_type),
CONF_TABLE: "a",
CONF_STATE: "0011TT--",
},
blocking=True,
)
@ -334,9 +399,11 @@ async def test_service_lock_keys(hass: HomeAssistant, entry: MockConfigEntry) ->
lock_keys.assert_awaited_with(0, lock_states)
@patch("homeassistant.components.lcn.PchkConnectionManager", MockPchkConnectionManager)
@pytest.mark.parametrize("config_type", [CONF_ADDRESS, CONF_DEVICE_ID])
async def test_service_lock_keys_tab_a_temporary(
hass: HomeAssistant, entry: MockConfigEntry
hass: HomeAssistant,
entry: MockConfigEntry,
config_type: str,
) -> None:
"""Test lock_keys (tab_a_temporary) service."""
await async_setup_component(hass, "persistent_notification", {})
@ -350,7 +417,7 @@ async def test_service_lock_keys_tab_a_temporary(
DOMAIN,
LcnService.LOCK_KEYS,
{
CONF_ADDRESS: "pchk.s0.m7",
**device_config(hass, entry, config_type),
CONF_STATE: "0011TT--",
CONF_TIME: 10,
CONF_TIME_UNIT: "s",
@ -376,7 +443,7 @@ async def test_service_lock_keys_tab_a_temporary(
DOMAIN,
LcnService.LOCK_KEYS,
{
CONF_ADDRESS: "pchk.s0.m7",
**device_config(hass, entry, config_type),
CONF_TABLE: "b",
CONF_STATE: "0011TT--",
CONF_TIME: 10,
@ -386,8 +453,12 @@ async def test_service_lock_keys_tab_a_temporary(
)
@patch("homeassistant.components.lcn.PchkConnectionManager", MockPchkConnectionManager)
async def test_service_dyn_text(hass: HomeAssistant, entry: MockConfigEntry) -> None:
@pytest.mark.parametrize("config_type", [CONF_ADDRESS, CONF_DEVICE_ID])
async def test_service_dyn_text(
hass: HomeAssistant,
entry: MockConfigEntry,
config_type: str,
) -> None:
"""Test dyn_text service."""
await async_setup_component(hass, "persistent_notification", {})
await init_integration(hass, entry)
@ -396,15 +467,23 @@ async def test_service_dyn_text(hass: HomeAssistant, entry: MockConfigEntry) ->
await hass.services.async_call(
DOMAIN,
LcnService.DYN_TEXT,
{CONF_ADDRESS: "pchk.s0.m7", CONF_ROW: 1, CONF_TEXT: "text in row 1"},
{
**device_config(hass, entry, config_type),
CONF_ROW: 1,
CONF_TEXT: "text in row 1",
},
blocking=True,
)
dyn_text.assert_awaited_with(0, "text in row 1")
@patch("homeassistant.components.lcn.PchkConnectionManager", MockPchkConnectionManager)
async def test_service_pck(hass: HomeAssistant, entry: MockConfigEntry) -> None:
@pytest.mark.parametrize("config_type", [CONF_ADDRESS, CONF_DEVICE_ID])
async def test_service_pck(
hass: HomeAssistant,
entry: MockConfigEntry,
config_type: str,
) -> None:
"""Test pck service."""
await async_setup_component(hass, "persistent_notification", {})
await init_integration(hass, entry)
@ -413,14 +492,13 @@ async def test_service_pck(hass: HomeAssistant, entry: MockConfigEntry) -> None:
await hass.services.async_call(
DOMAIN,
LcnService.PCK,
{CONF_ADDRESS: "pchk.s0.m7", CONF_PCK: "PIN4"},
{**device_config(hass, entry, config_type), CONF_PCK: "PIN4"},
blocking=True,
)
pck.assert_awaited_with("PIN4")
@patch("homeassistant.components.lcn.PchkConnectionManager", MockPchkConnectionManager)
async def test_service_called_with_invalid_host_id(
hass: HomeAssistant, entry: MockConfigEntry
) -> None:
@ -437,3 +515,20 @@ async def test_service_called_with_invalid_host_id(
)
pck.assert_not_awaited()
async def test_service_with_deprecated_address_parameter(
hass: HomeAssistant, entry: MockConfigEntry, issue_registry: ir.IssueRegistry
) -> None:
"""Test service puts issue in registry if called with address parameter."""
await async_setup_component(hass, "persistent_notification", {})
await init_integration(hass, entry)
await hass.services.async_call(
DOMAIN,
LcnService.PCK,
{CONF_ADDRESS: "pchk.s0.m7", CONF_PCK: "PIN4"},
blocking=True,
)
assert issue_registry.async_get_issue(DOMAIN, "deprecated_address_parameter")