Add KNX service event_register (#45248)

This commit is contained in:
Matthias Alphart 2021-01-22 15:27:51 +01:00 committed by GitHub
parent 89fc92f68a
commit 4aceb0dd27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 120 additions and 69 deletions

View File

@ -4,6 +4,7 @@ import logging
import voluptuous as vol
from xknx import XKNX
from xknx.core.telegram_queue import TelegramQueue
from xknx.devices import DateTime, ExposeSensor
from xknx.dpt import DPTArray, DPTBase, DPTBinary
from xknx.exceptions import XKNXException
@ -59,7 +60,7 @@ CONF_KNX_CONFIG = "config_file"
CONF_KNX_ROUTING = "routing"
CONF_KNX_TUNNELING = "tunneling"
CONF_KNX_FIRE_EVENT = "fire_event"
CONF_KNX_FIRE_EVENT_FILTER = "fire_event_filter"
CONF_KNX_EVENT_FILTER = "event_filter"
CONF_KNX_INDIVIDUAL_ADDRESS = "individual_address"
CONF_KNX_MCAST_GRP = "multicast_group"
CONF_KNX_MCAST_PORT = "multicast_port"
@ -71,10 +72,15 @@ SERVICE_KNX_SEND = "send"
SERVICE_KNX_ATTR_ADDRESS = "address"
SERVICE_KNX_ATTR_PAYLOAD = "payload"
SERVICE_KNX_ATTR_TYPE = "type"
SERVICE_KNX_ATTR_REMOVE = "remove"
SERVICE_KNX_EVENT_REGISTER = "event_register"
CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.Schema(
DOMAIN: vol.All(
cv.deprecated(CONF_KNX_FIRE_EVENT),
cv.deprecated("fire_event_filter", replacement_key=CONF_KNX_EVENT_FILTER),
vol.Schema(
{
vol.Optional(CONF_KNX_CONFIG): cv.string,
vol.Exclusive(
@ -83,15 +89,19 @@ CONFIG_SCHEMA = vol.Schema(
vol.Exclusive(
CONF_KNX_TUNNELING, "connection_type"
): ConnectionSchema.TUNNELING_SCHEMA,
vol.Inclusive(CONF_KNX_FIRE_EVENT, "fire_ev"): cv.boolean,
vol.Inclusive(CONF_KNX_FIRE_EVENT_FILTER, "fire_ev"): vol.All(
vol.Optional(CONF_KNX_FIRE_EVENT): cv.boolean,
vol.Optional(CONF_KNX_EVENT_FILTER, default=[]): vol.All(
cv.ensure_list, [cv.string]
),
vol.Optional(
CONF_KNX_INDIVIDUAL_ADDRESS, default=XKNX.DEFAULT_ADDRESS
): cv.string,
vol.Optional(CONF_KNX_MCAST_GRP, default=DEFAULT_MCAST_GRP): cv.string,
vol.Optional(CONF_KNX_MCAST_PORT, default=DEFAULT_MCAST_PORT): cv.port,
vol.Optional(
CONF_KNX_MCAST_GRP, default=DEFAULT_MCAST_GRP
): cv.string,
vol.Optional(
CONF_KNX_MCAST_PORT, default=DEFAULT_MCAST_PORT
): cv.port,
vol.Optional(CONF_KNX_STATE_UPDATER, default=True): cv.boolean,
vol.Optional(CONF_KNX_RATE_LIMIT, default=20): vol.All(
vol.Coerce(int), vol.Range(min=1, max=100)
@ -127,6 +137,7 @@ CONFIG_SCHEMA = vol.Schema(
cv.ensure_list, [WeatherSchema.SCHEMA]
),
}
),
)
},
extra=vol.ALLOW_EXTRA,
@ -151,6 +162,13 @@ SERVICE_KNX_SEND_SCHEMA = vol.Any(
),
)
SERVICE_KNX_EVENT_REGISTER_SCHEMA = vol.Schema(
{
vol.Required(SERVICE_KNX_ATTR_ADDRESS): cv.string,
vol.Optional(SERVICE_KNX_ATTR_REMOVE, default=False): cv.boolean,
}
)
async def async_setup(hass, config):
"""Set up the KNX component."""
@ -188,6 +206,14 @@ async def async_setup(hass, config):
schema=SERVICE_KNX_SEND_SCHEMA,
)
async_register_admin_service(
hass,
DOMAIN,
SERVICE_KNX_EVENT_REGISTER,
hass.data[DOMAIN].service_event_register_modify,
schema=SERVICE_KNX_EVENT_REGISTER_SCHEMA,
)
async def reload_service_handler(service_call: ServiceCallType) -> None:
"""Remove all KNX components and load new ones from config."""
@ -221,10 +247,11 @@ class KNXModule:
self.hass = hass
self.config = config
self.connected = False
self.init_xknx()
self.register_callbacks()
self.exposures = []
self.init_xknx()
self._knx_event_callback: TelegramQueue.Callback = self.register_callback()
def init_xknx(self):
"""Initialize of KNX object."""
self.xknx = XKNX(
@ -289,19 +316,6 @@ class KNXModule:
auto_reconnect=True,
)
def register_callbacks(self):
"""Register callbacks within XKNX object."""
if (
CONF_KNX_FIRE_EVENT in self.config[DOMAIN]
and self.config[DOMAIN][CONF_KNX_FIRE_EVENT]
):
address_filters = list(
map(AddressFilter, self.config[DOMAIN][CONF_KNX_FIRE_EVENT_FILTER])
)
self.xknx.telegram_queue.register_telegram_received_cb(
self.telegram_received_cb, address_filters
)
@callback
def async_create_exposures(self):
"""Create exposures."""
@ -349,6 +363,35 @@ class KNXModule:
},
)
def register_callback(self) -> TelegramQueue.Callback:
"""Register callback within XKNX TelegramQueue."""
address_filters = list(
map(AddressFilter, self.config[DOMAIN][CONF_KNX_EVENT_FILTER])
)
return self.xknx.telegram_queue.register_telegram_received_cb(
self.telegram_received_cb,
address_filters=address_filters,
group_addresses=[],
)
async def service_event_register_modify(self, call):
"""Service for adding or removing a GroupAddress to the knx_event filter."""
group_address = GroupAddress(call.data.get(SERVICE_KNX_ATTR_ADDRESS))
if call.data.get(SERVICE_KNX_ATTR_REMOVE):
try:
self._knx_event_callback.group_addresses.remove(group_address)
except ValueError:
_LOGGER.warning(
"Service event_register could not remove event for '%s'",
group_address,
)
elif group_address not in self._knx_event_callback.group_addresses:
self._knx_event_callback.group_addresses.append(group_address)
_LOGGER.debug(
"Service event_register registered event for '%s'",
group_address,
)
async def service_send_to_knx_bus(self, call):
"""Service for sending an arbitrary KNX message to the KNX bus."""
attr_payload = call.data.get(SERVICE_KNX_ATTR_PAYLOAD)

View File

@ -10,3 +10,11 @@ send:
type:
description: "Optional. If set, the payload will not be sent as raw bytes, but encoded as given DPT. Knx sensor types are valid values (see https://www.home-assistant.io/integrations/sensor.knx)."
example: "temperature"
event_register:
description: "Add or remove single group address to knx_event filter for triggering `knx_event`s. Only addresses added with this service can be removed."
fields:
address:
description: "Group address that shall be added or removed."
example: "1/1/0"
remove:
description: "Optional. If `True` the group address will be removed. Defaults to `False`."