diff --git a/homeassistant/components/knx/const.py b/homeassistant/components/knx/const.py index e22546d3806..7a9dfc34546 100644 --- a/homeassistant/components/knx/const.py +++ b/homeassistant/components/knx/const.py @@ -52,8 +52,8 @@ CONF_KNX_DEFAULT_RATE_LIMIT: Final = 0 DEFAULT_ROUTING_IA: Final = "0.0.240" CONF_KNX_TELEGRAM_LOG_SIZE: Final = "telegram_log_size" -TELEGRAM_LOG_DEFAULT: Final = 200 -TELEGRAM_LOG_MAX: Final = 5000 # ~2 MB or ~5 hours of reasonable bus load +TELEGRAM_LOG_DEFAULT: Final = 1000 +TELEGRAM_LOG_MAX: Final = 25000 # ~10 MB or ~25 hours of reasonable bus load ## # Secure constants diff --git a/homeassistant/components/knx/telegrams.py b/homeassistant/components/knx/telegrams.py index f4b31fd11f9..dcd5f477679 100644 --- a/homeassistant/components/knx/telegrams.py +++ b/homeassistant/components/knx/telegrams.py @@ -75,6 +75,7 @@ class Telegrams: ) ) self.recent_telegrams: deque[TelegramDict] = deque(maxlen=log_size) + self.last_ga_telegrams: dict[str, TelegramDict] = {} async def load_history(self) -> None: """Load history from store.""" @@ -88,6 +89,9 @@ class Telegrams: if isinstance(telegram["payload"], list): telegram["payload"] = tuple(telegram["payload"]) # type: ignore[unreachable] self.recent_telegrams.extend(telegrams) + self.last_ga_telegrams = { + t["destination"]: t for t in telegrams if t["payload"] is not None + } async def save_history(self) -> None: """Save history to store.""" @@ -98,6 +102,9 @@ class Telegrams: """Handle incoming and outgoing telegrams from xknx.""" telegram_dict = self.telegram_to_dict(telegram) self.recent_telegrams.append(telegram_dict) + if telegram_dict["payload"] is not None: + # exclude GroupValueRead telegrams + self.last_ga_telegrams[telegram_dict["destination"]] = telegram_dict async_dispatcher_send(self.hass, SIGNAL_KNX_TELEGRAM, telegram, telegram_dict) def telegram_to_dict(self, telegram: Telegram) -> TelegramDict: diff --git a/homeassistant/components/knx/websocket.py b/homeassistant/components/knx/websocket.py index 6cb2218b221..9ba3e0ccff6 100644 --- a/homeassistant/components/knx/websocket.py +++ b/homeassistant/components/knx/websocket.py @@ -47,6 +47,7 @@ async def register_panel(hass: HomeAssistant) -> None: websocket_api.async_register_command(hass, ws_project_file_process) websocket_api.async_register_command(hass, ws_project_file_remove) websocket_api.async_register_command(hass, ws_group_monitor_info) + websocket_api.async_register_command(hass, ws_group_telegrams) websocket_api.async_register_command(hass, ws_subscribe_telegram) websocket_api.async_register_command(hass, ws_get_knx_project) websocket_api.async_register_command(hass, ws_validate_entity) @@ -287,6 +288,27 @@ def ws_group_monitor_info( ) +@websocket_api.require_admin +@websocket_api.websocket_command( + { + vol.Required("type"): "knx/group_telegrams", + } +) +@provide_knx +@callback +def ws_group_telegrams( + hass: HomeAssistant, + knx: KNXModule, + connection: websocket_api.ActiveConnection, + msg: dict, +) -> None: + """Handle get group telegrams command.""" + connection.send_result( + msg["id"], + knx.telegrams.last_ga_telegrams, + ) + + @websocket_api.require_admin @websocket_api.websocket_command( { diff --git a/tests/components/knx/test_config_flow.py b/tests/components/knx/test_config_flow.py index 78751c7e641..2187721a518 100644 --- a/tests/components/knx/test_config_flow.py +++ b/tests/components/knx/test_config_flow.py @@ -913,7 +913,7 @@ async def test_form_with_automatic_connection_handling( CONF_KNX_ROUTE_BACK: False, CONF_KNX_TUNNEL_ENDPOINT_IA: None, CONF_KNX_STATE_UPDATER: True, - CONF_KNX_TELEGRAM_LOG_SIZE: 200, + CONF_KNX_TELEGRAM_LOG_SIZE: 1000, } knx_setup.assert_called_once() @@ -1210,7 +1210,7 @@ async def test_options_flow_connection_type( CONF_KNX_SECURE_DEVICE_AUTHENTICATION: None, CONF_KNX_SECURE_USER_ID: None, CONF_KNX_SECURE_USER_PASSWORD: None, - CONF_KNX_TELEGRAM_LOG_SIZE: 200, + CONF_KNX_TELEGRAM_LOG_SIZE: 1000, } diff --git a/tests/components/knx/test_websocket.py b/tests/components/knx/test_websocket.py index b3e4b7aaa38..a34f126e4f4 100644 --- a/tests/components/knx/test_websocket.py +++ b/tests/components/knx/test_websocket.py @@ -180,6 +180,37 @@ async def test_knx_group_monitor_info_command( assert res["result"]["recent_telegrams"] == [] +async def test_knx_group_telegrams_command( + hass: HomeAssistant, knx: KNXTestKit, hass_ws_client: WebSocketGenerator +) -> None: + """Test knx/group_telegrams command.""" + await knx.setup_integration({}) + client = await hass_ws_client(hass) + + await client.send_json_auto_id({"type": "knx/group_telegrams"}) + res = await client.receive_json() + assert res["success"], res + assert res["result"] == {} + + # # get some telegrams to populate the cache + await knx.receive_write("1/1/1", True) + await knx.receive_read("2/2/2") # read telegram shall be ignored + await knx.receive_write("3/3/3", 0x34) + + await client.send_json_auto_id({"type": "knx/group_telegrams"}) + res = await client.receive_json() + assert res["success"], res + assert len(res["result"]) == 2 + assert "1/1/1" in res["result"] + assert res["result"]["1/1/1"]["destination"] == "1/1/1" + assert "3/3/3" in res["result"] + assert res["result"]["3/3/3"]["payload"] == 52 + assert res["result"]["3/3/3"]["telegramtype"] == "GroupValueWrite" + assert res["result"]["3/3/3"]["source"] == "1.2.3" + assert res["result"]["3/3/3"]["direction"] == "Incoming" + assert res["result"]["3/3/3"]["timestamp"] is not None + + async def test_knx_subscribe_telegrams_command_recent_telegrams( hass: HomeAssistant, knx: KNXTestKit, hass_ws_client: WebSocketGenerator ) -> None: