mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Add KNX service event_register (#45248)
This commit is contained in:
parent
89fc92f68a
commit
4aceb0dd27
@ -4,6 +4,7 @@ import logging
|
|||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
from xknx import XKNX
|
from xknx import XKNX
|
||||||
|
from xknx.core.telegram_queue import TelegramQueue
|
||||||
from xknx.devices import DateTime, ExposeSensor
|
from xknx.devices import DateTime, ExposeSensor
|
||||||
from xknx.dpt import DPTArray, DPTBase, DPTBinary
|
from xknx.dpt import DPTArray, DPTBase, DPTBinary
|
||||||
from xknx.exceptions import XKNXException
|
from xknx.exceptions import XKNXException
|
||||||
@ -59,7 +60,7 @@ CONF_KNX_CONFIG = "config_file"
|
|||||||
CONF_KNX_ROUTING = "routing"
|
CONF_KNX_ROUTING = "routing"
|
||||||
CONF_KNX_TUNNELING = "tunneling"
|
CONF_KNX_TUNNELING = "tunneling"
|
||||||
CONF_KNX_FIRE_EVENT = "fire_event"
|
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_INDIVIDUAL_ADDRESS = "individual_address"
|
||||||
CONF_KNX_MCAST_GRP = "multicast_group"
|
CONF_KNX_MCAST_GRP = "multicast_group"
|
||||||
CONF_KNX_MCAST_PORT = "multicast_port"
|
CONF_KNX_MCAST_PORT = "multicast_port"
|
||||||
@ -71,62 +72,72 @@ SERVICE_KNX_SEND = "send"
|
|||||||
SERVICE_KNX_ATTR_ADDRESS = "address"
|
SERVICE_KNX_ATTR_ADDRESS = "address"
|
||||||
SERVICE_KNX_ATTR_PAYLOAD = "payload"
|
SERVICE_KNX_ATTR_PAYLOAD = "payload"
|
||||||
SERVICE_KNX_ATTR_TYPE = "type"
|
SERVICE_KNX_ATTR_TYPE = "type"
|
||||||
|
SERVICE_KNX_ATTR_REMOVE = "remove"
|
||||||
|
SERVICE_KNX_EVENT_REGISTER = "event_register"
|
||||||
|
|
||||||
CONFIG_SCHEMA = vol.Schema(
|
CONFIG_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
DOMAIN: vol.Schema(
|
DOMAIN: vol.All(
|
||||||
{
|
cv.deprecated(CONF_KNX_FIRE_EVENT),
|
||||||
vol.Optional(CONF_KNX_CONFIG): cv.string,
|
cv.deprecated("fire_event_filter", replacement_key=CONF_KNX_EVENT_FILTER),
|
||||||
vol.Exclusive(
|
vol.Schema(
|
||||||
CONF_KNX_ROUTING, "connection_type"
|
{
|
||||||
): ConnectionSchema.ROUTING_SCHEMA,
|
vol.Optional(CONF_KNX_CONFIG): cv.string,
|
||||||
vol.Exclusive(
|
vol.Exclusive(
|
||||||
CONF_KNX_TUNNELING, "connection_type"
|
CONF_KNX_ROUTING, "connection_type"
|
||||||
): ConnectionSchema.TUNNELING_SCHEMA,
|
): ConnectionSchema.ROUTING_SCHEMA,
|
||||||
vol.Inclusive(CONF_KNX_FIRE_EVENT, "fire_ev"): cv.boolean,
|
vol.Exclusive(
|
||||||
vol.Inclusive(CONF_KNX_FIRE_EVENT_FILTER, "fire_ev"): vol.All(
|
CONF_KNX_TUNNELING, "connection_type"
|
||||||
cv.ensure_list, [cv.string]
|
): ConnectionSchema.TUNNELING_SCHEMA,
|
||||||
),
|
vol.Optional(CONF_KNX_FIRE_EVENT): cv.boolean,
|
||||||
vol.Optional(
|
vol.Optional(CONF_KNX_EVENT_FILTER, default=[]): vol.All(
|
||||||
CONF_KNX_INDIVIDUAL_ADDRESS, default=XKNX.DEFAULT_ADDRESS
|
cv.ensure_list, [cv.string]
|
||||||
): cv.string,
|
),
|
||||||
vol.Optional(CONF_KNX_MCAST_GRP, default=DEFAULT_MCAST_GRP): cv.string,
|
vol.Optional(
|
||||||
vol.Optional(CONF_KNX_MCAST_PORT, default=DEFAULT_MCAST_PORT): cv.port,
|
CONF_KNX_INDIVIDUAL_ADDRESS, default=XKNX.DEFAULT_ADDRESS
|
||||||
vol.Optional(CONF_KNX_STATE_UPDATER, default=True): cv.boolean,
|
): cv.string,
|
||||||
vol.Optional(CONF_KNX_RATE_LIMIT, default=20): vol.All(
|
vol.Optional(
|
||||||
vol.Coerce(int), vol.Range(min=1, max=100)
|
CONF_KNX_MCAST_GRP, default=DEFAULT_MCAST_GRP
|
||||||
),
|
): cv.string,
|
||||||
vol.Optional(CONF_KNX_EXPOSE): vol.All(
|
vol.Optional(
|
||||||
cv.ensure_list, [ExposeSchema.SCHEMA]
|
CONF_KNX_MCAST_PORT, default=DEFAULT_MCAST_PORT
|
||||||
),
|
): cv.port,
|
||||||
vol.Optional(SupportedPlatforms.cover.value): vol.All(
|
vol.Optional(CONF_KNX_STATE_UPDATER, default=True): cv.boolean,
|
||||||
cv.ensure_list, [CoverSchema.SCHEMA]
|
vol.Optional(CONF_KNX_RATE_LIMIT, default=20): vol.All(
|
||||||
),
|
vol.Coerce(int), vol.Range(min=1, max=100)
|
||||||
vol.Optional(SupportedPlatforms.binary_sensor.value): vol.All(
|
),
|
||||||
cv.ensure_list, [BinarySensorSchema.SCHEMA]
|
vol.Optional(CONF_KNX_EXPOSE): vol.All(
|
||||||
),
|
cv.ensure_list, [ExposeSchema.SCHEMA]
|
||||||
vol.Optional(SupportedPlatforms.light.value): vol.All(
|
),
|
||||||
cv.ensure_list, [LightSchema.SCHEMA]
|
vol.Optional(SupportedPlatforms.cover.value): vol.All(
|
||||||
),
|
cv.ensure_list, [CoverSchema.SCHEMA]
|
||||||
vol.Optional(SupportedPlatforms.climate.value): vol.All(
|
),
|
||||||
cv.ensure_list, [ClimateSchema.SCHEMA]
|
vol.Optional(SupportedPlatforms.binary_sensor.value): vol.All(
|
||||||
),
|
cv.ensure_list, [BinarySensorSchema.SCHEMA]
|
||||||
vol.Optional(SupportedPlatforms.notify.value): vol.All(
|
),
|
||||||
cv.ensure_list, [NotifySchema.SCHEMA]
|
vol.Optional(SupportedPlatforms.light.value): vol.All(
|
||||||
),
|
cv.ensure_list, [LightSchema.SCHEMA]
|
||||||
vol.Optional(SupportedPlatforms.switch.value): vol.All(
|
),
|
||||||
cv.ensure_list, [SwitchSchema.SCHEMA]
|
vol.Optional(SupportedPlatforms.climate.value): vol.All(
|
||||||
),
|
cv.ensure_list, [ClimateSchema.SCHEMA]
|
||||||
vol.Optional(SupportedPlatforms.sensor.value): vol.All(
|
),
|
||||||
cv.ensure_list, [SensorSchema.SCHEMA]
|
vol.Optional(SupportedPlatforms.notify.value): vol.All(
|
||||||
),
|
cv.ensure_list, [NotifySchema.SCHEMA]
|
||||||
vol.Optional(SupportedPlatforms.scene.value): vol.All(
|
),
|
||||||
cv.ensure_list, [SceneSchema.SCHEMA]
|
vol.Optional(SupportedPlatforms.switch.value): vol.All(
|
||||||
),
|
cv.ensure_list, [SwitchSchema.SCHEMA]
|
||||||
vol.Optional(SupportedPlatforms.weather.value): vol.All(
|
),
|
||||||
cv.ensure_list, [WeatherSchema.SCHEMA]
|
vol.Optional(SupportedPlatforms.sensor.value): vol.All(
|
||||||
),
|
cv.ensure_list, [SensorSchema.SCHEMA]
|
||||||
}
|
),
|
||||||
|
vol.Optional(SupportedPlatforms.scene.value): vol.All(
|
||||||
|
cv.ensure_list, [SceneSchema.SCHEMA]
|
||||||
|
),
|
||||||
|
vol.Optional(SupportedPlatforms.weather.value): vol.All(
|
||||||
|
cv.ensure_list, [WeatherSchema.SCHEMA]
|
||||||
|
),
|
||||||
|
}
|
||||||
|
),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
extra=vol.ALLOW_EXTRA,
|
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):
|
async def async_setup(hass, config):
|
||||||
"""Set up the KNX component."""
|
"""Set up the KNX component."""
|
||||||
@ -188,6 +206,14 @@ async def async_setup(hass, config):
|
|||||||
schema=SERVICE_KNX_SEND_SCHEMA,
|
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:
|
async def reload_service_handler(service_call: ServiceCallType) -> None:
|
||||||
"""Remove all KNX components and load new ones from config."""
|
"""Remove all KNX components and load new ones from config."""
|
||||||
|
|
||||||
@ -221,10 +247,11 @@ class KNXModule:
|
|||||||
self.hass = hass
|
self.hass = hass
|
||||||
self.config = config
|
self.config = config
|
||||||
self.connected = False
|
self.connected = False
|
||||||
self.init_xknx()
|
|
||||||
self.register_callbacks()
|
|
||||||
self.exposures = []
|
self.exposures = []
|
||||||
|
|
||||||
|
self.init_xknx()
|
||||||
|
self._knx_event_callback: TelegramQueue.Callback = self.register_callback()
|
||||||
|
|
||||||
def init_xknx(self):
|
def init_xknx(self):
|
||||||
"""Initialize of KNX object."""
|
"""Initialize of KNX object."""
|
||||||
self.xknx = XKNX(
|
self.xknx = XKNX(
|
||||||
@ -289,19 +316,6 @@ class KNXModule:
|
|||||||
auto_reconnect=True,
|
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
|
@callback
|
||||||
def async_create_exposures(self):
|
def async_create_exposures(self):
|
||||||
"""Create exposures."""
|
"""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):
|
async def service_send_to_knx_bus(self, call):
|
||||||
"""Service for sending an arbitrary KNX message to the KNX bus."""
|
"""Service for sending an arbitrary KNX message to the KNX bus."""
|
||||||
attr_payload = call.data.get(SERVICE_KNX_ATTR_PAYLOAD)
|
attr_payload = call.data.get(SERVICE_KNX_ATTR_PAYLOAD)
|
||||||
|
@ -10,3 +10,11 @@ send:
|
|||||||
type:
|
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)."
|
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"
|
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`."
|
||||||
|
Loading…
x
Reference in New Issue
Block a user