Skip to content

Commit f77e6cc

Browse files
authored
Add missing exception translations to LCN (home-assistant#147723)
1 parent cb8e076 commit f77e6cc

File tree

7 files changed

+88
-13
lines changed

7 files changed

+88
-13
lines changed

homeassistant/components/lcn/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,11 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: LcnConfigEntry) -
104104
) as ex:
105105
await lcn_connection.async_close()
106106
raise ConfigEntryNotReady(
107-
f"Unable to connect to {config_entry.title}: {ex}"
107+
translation_domain=DOMAIN,
108+
translation_key="cannot_connect",
109+
translation_placeholders={
110+
"config_entry_title": config_entry.title,
111+
},
108112
) from ex
109113

110114
_LOGGER.info('LCN connected to "%s"', config_entry.title)

homeassistant/components/lcn/helpers.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
CONF_SWITCHES,
2727
)
2828
from homeassistant.core import HomeAssistant
29+
from homeassistant.exceptions import HomeAssistantError
2930
from homeassistant.helpers import device_registry as dr, entity_registry as er
3031
from homeassistant.helpers.typing import ConfigType
3132

@@ -100,7 +101,11 @@ def get_resource(domain_name: str, domain_data: ConfigType) -> str:
100101
return cast(str, domain_data["setpoint"])
101102
if domain_name == "scene":
102103
return f"{domain_data['register']}{domain_data['scene']}"
103-
raise ValueError("Unknown domain")
104+
raise HomeAssistantError(
105+
translation_domain=DOMAIN,
106+
translation_key="invalid_domain",
107+
translation_placeholders={CONF_DOMAIN: domain_name},
108+
)
104109

105110

106111
def generate_unique_id(
@@ -304,6 +309,8 @@ def get_device_config(
304309
def is_states_string(states_string: str) -> list[str]:
305310
"""Validate the given states string and return states list."""
306311
if len(states_string) != 8:
307-
raise ValueError("Invalid length of states string")
312+
raise HomeAssistantError(
313+
translation_domain=DOMAIN, translation_key="invalid_length_of_states_string"
314+
)
308315
states = {"1": "ON", "0": "OFF", "T": "TOGGLE", "-": "NOCHANGE"}
309316
return [states[state_string] for state_string in states_string]

homeassistant/components/lcn/quality_scale.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ rules:
1919
test-before-setup: done
2020
unique-config-entry: done
2121
# Silver
22-
action-exceptions: todo
22+
action-exceptions: done
2323
config-entry-unloading: done
2424
docs-configuration-parameters:
2525
status: exempt

homeassistant/components/lcn/services.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,9 @@ async def async_call_service(self, service: ServiceCall) -> None:
330330
if (delay_time := service.data[CONF_TIME]) != 0:
331331
hit = pypck.lcn_defs.SendKeyCommand.HIT
332332
if pypck.lcn_defs.SendKeyCommand[service.data[CONF_STATE]] != hit:
333-
raise ValueError(
334-
"Only hit command is allowed when sending deferred keys."
333+
raise ServiceValidationError(
334+
translation_domain=DOMAIN,
335+
translation_key="invalid_send_keys_action",
335336
)
336337
delay_unit = pypck.lcn_defs.TimeUnit.parse(service.data[CONF_TIME_UNIT])
337338
await device_connection.send_keys_hit_deferred(keys, delay_time, delay_unit)
@@ -368,8 +369,9 @@ async def async_call_service(self, service: ServiceCall) -> None:
368369

369370
if (delay_time := service.data[CONF_TIME]) != 0:
370371
if table_id != 0:
371-
raise ValueError(
372-
"Only table A is allowed when locking keys for a specific time."
372+
raise ServiceValidationError(
373+
translation_domain=DOMAIN,
374+
translation_key="invalid_lock_keys_table",
373375
)
374376
delay_unit = pypck.lcn_defs.TimeUnit.parse(service.data[CONF_TIME_UNIT])
375377
await device_connection.lock_keys_tab_a_temporary(

homeassistant/components/lcn/strings.json

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -414,11 +414,23 @@
414414
}
415415
},
416416
"exceptions": {
417-
"invalid_address": {
418-
"message": "LCN device for given address has not been configured."
417+
"cannot_connect": {
418+
"message": "Unable to connect to {config_entry_title}."
419419
},
420420
"invalid_device_id": {
421-
"message": "LCN device for given device ID has not been configured."
421+
"message": "LCN device for given device ID {device_id} has not been configured."
422+
},
423+
"invalid_domain": {
424+
"message": "Invalid domain {domain}."
425+
},
426+
"invalid_send_keys_action": {
427+
"message": "Invalid state for sending keys. Only 'hit' allowed for deferred sending."
428+
},
429+
"invalid_lock_keys_table": {
430+
"message": "Invalid table for locking keys. Only table A allowed when locking for a specific time."
431+
},
432+
"invalid_length_of_states_string": {
433+
"message": "Invalid length of states string. Expected 8 characters."
422434
}
423435
}
424436
}

tests/components/lcn/test_services.py

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
CONF_UNIT_OF_MEASUREMENT,
3131
)
3232
from homeassistant.core import HomeAssistant
33+
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
3334
from homeassistant.setup import async_setup_component
3435

3536
from .conftest import (
@@ -134,6 +135,23 @@ async def test_service_relays(
134135

135136
control_relays.assert_awaited_with(relay_states)
136137

138+
# wrong states string
139+
with (
140+
patch.object(MockModuleConnection, "control_relays") as control_relays,
141+
pytest.raises(HomeAssistantError) as exc_info,
142+
):
143+
await hass.services.async_call(
144+
DOMAIN,
145+
LcnService.RELAYS,
146+
{
147+
CONF_DEVICE_ID: get_device(hass, entry, (0, 7, False)).id,
148+
CONF_STATE: "0011TT--00",
149+
},
150+
blocking=True,
151+
)
152+
assert exc_info.value.translation_domain == DOMAIN
153+
assert exc_info.value.translation_key == "invalid_length_of_states_string"
154+
137155

138156
async def test_service_led(
139157
hass: HomeAssistant,
@@ -328,7 +346,7 @@ async def test_service_send_keys_hit_deferred(
328346
patch.object(
329347
MockModuleConnection, "send_keys_hit_deferred"
330348
) as send_keys_hit_deferred,
331-
pytest.raises(ValueError),
349+
pytest.raises(ServiceValidationError) as exc_info,
332350
):
333351
await hass.services.async_call(
334352
DOMAIN,
@@ -342,6 +360,8 @@ async def test_service_send_keys_hit_deferred(
342360
},
343361
blocking=True,
344362
)
363+
assert exc_info.value.translation_domain == DOMAIN
364+
assert exc_info.value.translation_key == "invalid_send_keys_action"
345365

346366

347367
async def test_service_lock_keys(
@@ -369,6 +389,24 @@ async def test_service_lock_keys(
369389

370390
lock_keys.assert_awaited_with(0, lock_states)
371391

392+
# wrong states string
393+
with (
394+
patch.object(MockModuleConnection, "lock_keys") as lock_keys,
395+
pytest.raises(HomeAssistantError) as exc_info,
396+
):
397+
await hass.services.async_call(
398+
DOMAIN,
399+
LcnService.LOCK_KEYS,
400+
{
401+
CONF_DEVICE_ID: get_device(hass, entry, (0, 7, False)).id,
402+
CONF_TABLE: "a",
403+
CONF_STATE: "0011TT--00",
404+
},
405+
blocking=True,
406+
)
407+
assert exc_info.value.translation_domain == DOMAIN
408+
assert exc_info.value.translation_key == "invalid_length_of_states_string"
409+
372410

373411
async def test_service_lock_keys_tab_a_temporary(
374412
hass: HomeAssistant,
@@ -406,7 +444,7 @@ async def test_service_lock_keys_tab_a_temporary(
406444
patch.object(
407445
MockModuleConnection, "lock_keys_tab_a_temporary"
408446
) as lock_keys_tab_a_temporary,
409-
pytest.raises(ValueError),
447+
pytest.raises(ServiceValidationError) as exc_info,
410448
):
411449
await hass.services.async_call(
412450
DOMAIN,
@@ -420,6 +458,8 @@ async def test_service_lock_keys_tab_a_temporary(
420458
},
421459
blocking=True,
422460
)
461+
assert exc_info.value.translation_domain == DOMAIN
462+
assert exc_info.value.translation_key == "invalid_lock_keys_table"
423463

424464

425465
async def test_service_dyn_text(

tests/components/lcn/test_websocket.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,16 @@ async def test_lcn_entities_add_command(
192192

193193
assert entity_config in entry.data[CONF_ENTITIES]
194194

195+
# invalid domain
196+
await client.send_json_auto_id(
197+
{**ENTITIES_ADD_PAYLOAD, "entry_id": entry.entry_id, CONF_DOMAIN: "invalid"}
198+
)
199+
200+
res = await client.receive_json()
201+
assert not res["success"]
202+
assert res["error"]["code"] == "home_assistant_error"
203+
assert res["error"]["translation_key"] == "invalid_domain"
204+
195205

196206
async def test_lcn_entities_delete_command(
197207
hass: HomeAssistant, hass_ws_client: WebSocketGenerator, entry: MockConfigEntry

0 commit comments

Comments
 (0)