mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Add optional type
for KNX notify entity configuration (#70451)
This commit is contained in:
parent
0c2acdf337
commit
639e3bb900
@ -7,7 +7,7 @@ from xknx import XKNX
|
|||||||
from xknx.devices import Notification as XknxNotification
|
from xknx.devices import Notification as XknxNotification
|
||||||
|
|
||||||
from homeassistant.components.notify import BaseNotificationService
|
from homeassistant.components.notify import BaseNotificationService
|
||||||
from homeassistant.const import CONF_NAME
|
from homeassistant.const import CONF_NAME, CONF_TYPE
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
@ -34,6 +34,7 @@ async def async_get_service(
|
|||||||
xknx,
|
xknx,
|
||||||
name=device_config[CONF_NAME],
|
name=device_config[CONF_NAME],
|
||||||
group_address=device_config[KNX_ADDRESS],
|
group_address=device_config[KNX_ADDRESS],
|
||||||
|
value_type=device_config[CONF_TYPE],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
|
@ -3,12 +3,13 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
from collections.abc import Callable
|
||||||
import ipaddress
|
import ipaddress
|
||||||
from typing import Any, ClassVar, Final
|
from typing import Any, ClassVar, Final
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
from xknx.devices.climate import SetpointShiftMode
|
from xknx.devices.climate import SetpointShiftMode
|
||||||
from xknx.dpt import DPTBase, DPTNumeric
|
from xknx.dpt import DPTBase, DPTNumeric, DPTString
|
||||||
from xknx.exceptions import ConversionError, CouldNotParseAddress
|
from xknx.exceptions import ConversionError, CouldNotParseAddress
|
||||||
from xknx.telegram.address import IndividualAddress, parse_device_group_address
|
from xknx.telegram.address import IndividualAddress, parse_device_group_address
|
||||||
|
|
||||||
@ -54,6 +55,28 @@ from .const import (
|
|||||||
##################
|
##################
|
||||||
|
|
||||||
|
|
||||||
|
def dpt_subclass_validator(dpt_base_class: type[DPTBase]) -> Callable[[Any], str | int]:
|
||||||
|
"""Validate that value is parsable as given sensor type."""
|
||||||
|
|
||||||
|
def dpt_value_validator(value: Any) -> str | int:
|
||||||
|
"""Validate that value is parsable as sensor type."""
|
||||||
|
if (
|
||||||
|
isinstance(value, (str, int))
|
||||||
|
and dpt_base_class.parse_transcoder(value) is not None
|
||||||
|
):
|
||||||
|
return value
|
||||||
|
raise vol.Invalid(
|
||||||
|
f"type '{value}' is not a valid DPT identifier for {dpt_base_class.__name__}."
|
||||||
|
)
|
||||||
|
|
||||||
|
return dpt_value_validator
|
||||||
|
|
||||||
|
|
||||||
|
numeric_type_validator = dpt_subclass_validator(DPTNumeric) # type: ignore[misc]
|
||||||
|
sensor_type_validator = dpt_subclass_validator(DPTBase) # type: ignore[misc]
|
||||||
|
string_type_validator = dpt_subclass_validator(DPTString)
|
||||||
|
|
||||||
|
|
||||||
def ga_validator(value: Any) -> str | int:
|
def ga_validator(value: Any) -> str | int:
|
||||||
"""Validate that value is parsable as GroupAddress or InternalGroupAddress."""
|
"""Validate that value is parsable as GroupAddress or InternalGroupAddress."""
|
||||||
if isinstance(value, (str, int)):
|
if isinstance(value, (str, int)):
|
||||||
@ -131,13 +154,6 @@ def number_limit_sub_validator(entity_config: OrderedDict) -> OrderedDict:
|
|||||||
return entity_config
|
return entity_config
|
||||||
|
|
||||||
|
|
||||||
def numeric_type_validator(value: Any) -> str | int:
|
|
||||||
"""Validate that value is parsable as numeric sensor type."""
|
|
||||||
if isinstance(value, (str, int)) and DPTNumeric.parse_transcoder(value) is not None:
|
|
||||||
return value
|
|
||||||
raise vol.Invalid(f"value '{value}' is not a valid numeric sensor type.")
|
|
||||||
|
|
||||||
|
|
||||||
def _max_payload_value(payload_length: int) -> int:
|
def _max_payload_value(payload_length: int) -> int:
|
||||||
if payload_length == 0:
|
if payload_length == 0:
|
||||||
return 0x3F
|
return 0x3F
|
||||||
@ -194,13 +210,6 @@ def select_options_sub_validator(entity_config: OrderedDict) -> OrderedDict:
|
|||||||
return entity_config
|
return entity_config
|
||||||
|
|
||||||
|
|
||||||
def sensor_type_validator(value: Any) -> str | int:
|
|
||||||
"""Validate that value is parsable as sensor type."""
|
|
||||||
if isinstance(value, (str, int)) and DPTBase.parse_transcoder(value) is not None:
|
|
||||||
return value
|
|
||||||
raise vol.Invalid(f"value '{value}' is not a valid sensor type.")
|
|
||||||
|
|
||||||
|
|
||||||
sync_state_validator = vol.Any(
|
sync_state_validator = vol.Any(
|
||||||
vol.All(vol.Coerce(int), vol.Range(min=2, max=1440)),
|
vol.All(vol.Coerce(int), vol.Range(min=2, max=1440)),
|
||||||
cv.boolean,
|
cv.boolean,
|
||||||
@ -733,6 +742,7 @@ class NotifySchema(KNXPlatformSchema):
|
|||||||
ENTITY_SCHEMA = vol.Schema(
|
ENTITY_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||||
|
vol.Optional(CONF_TYPE, default="latin_1"): string_type_validator,
|
||||||
vol.Required(KNX_ADDRESS): ga_validator,
|
vol.Required(KNX_ADDRESS): ga_validator,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from homeassistant.components.knx.const import KNX_ADDRESS
|
from homeassistant.components.knx.const import KNX_ADDRESS
|
||||||
from homeassistant.components.knx.schema import NotifySchema
|
from homeassistant.components.knx.schema import NotifySchema
|
||||||
from homeassistant.const import CONF_NAME
|
from homeassistant.const import CONF_NAME, CONF_TYPE
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from .conftest import KNXTestKit
|
from .conftest import KNXTestKit
|
||||||
@ -75,18 +75,22 @@ async def test_notify_simple(hass: HomeAssistant, knx: KNXTestKit):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_notify_multiple_sends_to_all(hass: HomeAssistant, knx: KNXTestKit):
|
async def test_notify_multiple_sends_to_all_with_different_encodings(
|
||||||
"""Test KNX notify can send to all devices."""
|
hass: HomeAssistant, knx: KNXTestKit
|
||||||
|
):
|
||||||
|
"""Test KNX notify `type` configuration."""
|
||||||
await knx.setup_integration(
|
await knx.setup_integration(
|
||||||
{
|
{
|
||||||
NotifySchema.PLATFORM: [
|
NotifySchema.PLATFORM: [
|
||||||
{
|
{
|
||||||
CONF_NAME: "test",
|
CONF_NAME: "ASCII",
|
||||||
KNX_ADDRESS: "1/0/0",
|
KNX_ADDRESS: "1/0/0",
|
||||||
|
CONF_TYPE: "string",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
CONF_NAME: "test2",
|
CONF_NAME: "Latin-1",
|
||||||
KNX_ADDRESS: "1/0/1",
|
KNX_ADDRESS: "1/0/1",
|
||||||
|
CONF_TYPE: "latin_1",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -94,44 +98,15 @@ async def test_notify_multiple_sends_to_all(hass: HomeAssistant, knx: KNXTestKit
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
"notify", "notify", {"message": "I love KNX"}, blocking=True
|
"notify", "notify", {"message": "Gänsefüßchen"}, blocking=True
|
||||||
)
|
)
|
||||||
|
|
||||||
await knx.assert_write(
|
await knx.assert_write(
|
||||||
"1/0/0",
|
"1/0/0",
|
||||||
(
|
# "G?nsef??chen"
|
||||||
0x49,
|
(71, 63, 110, 115, 101, 102, 63, 63, 99, 104, 101, 110, 0, 0),
|
||||||
0x20,
|
|
||||||
0x6C,
|
|
||||||
0x6F,
|
|
||||||
0x76,
|
|
||||||
0x65,
|
|
||||||
0x20,
|
|
||||||
0x4B,
|
|
||||||
0x4E,
|
|
||||||
0x58,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
await knx.assert_write(
|
await knx.assert_write(
|
||||||
"1/0/1",
|
"1/0/1",
|
||||||
(
|
(71, 228, 110, 115, 101, 102, 252, 223, 99, 104, 101, 110, 0, 0),
|
||||||
0x49,
|
|
||||||
0x20,
|
|
||||||
0x6C,
|
|
||||||
0x6F,
|
|
||||||
0x76,
|
|
||||||
0x65,
|
|
||||||
0x20,
|
|
||||||
0x4B,
|
|
||||||
0x4E,
|
|
||||||
0x58,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
0x0,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user