From 98c41f7398c8de7489a6beb5451731f2b13e3832 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Sun, 31 Dec 2023 04:54:09 -0500 Subject: [PATCH] Bump ZHA dependencies (#106756) * Bump ZHA dependencies * Revert "Remove bellows thread, as it has been removed upstream" This reverts commit c28053f4bf2539eb6150d35af19687610aaeac5e. --- homeassistant/components/zha/core/const.py | 1 + homeassistant/components/zha/core/gateway.py | 10 +++++ homeassistant/components/zha/manifest.json | 6 +-- homeassistant/components/zha/radio_manager.py | 2 + requirements_all.txt | 6 +-- requirements_test_all.txt | 6 +-- tests/components/zha/test_gateway.py | 45 ++++++++++++++++++- 7 files changed, 66 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/zha/core/const.py b/homeassistant/components/zha/core/const.py index 7e591a596e5..ecbd347a621 100644 --- a/homeassistant/components/zha/core/const.py +++ b/homeassistant/components/zha/core/const.py @@ -139,6 +139,7 @@ CONF_ENABLE_IDENTIFY_ON_JOIN = "enable_identify_on_join" CONF_ENABLE_QUIRKS = "enable_quirks" CONF_RADIO_TYPE = "radio_type" CONF_USB_PATH = "usb_path" +CONF_USE_THREAD = "use_thread" CONF_ZIGPY = "zigpy_config" CONF_CONSIDER_UNAVAILABLE_MAINS = "consider_unavailable_mains" diff --git a/homeassistant/components/zha/core/gateway.py b/homeassistant/components/zha/core/gateway.py index 1308abb3d37..12e439f1059 100644 --- a/homeassistant/components/zha/core/gateway.py +++ b/homeassistant/components/zha/core/gateway.py @@ -46,6 +46,7 @@ from .const import ( ATTR_SIGNATURE, ATTR_TYPE, CONF_RADIO_TYPE, + CONF_USE_THREAD, CONF_ZIGPY, DATA_ZHA, DEBUG_COMP_BELLOWS, @@ -158,6 +159,15 @@ class ZHAGateway: if CONF_NWK_VALIDATE_SETTINGS not in app_config: app_config[CONF_NWK_VALIDATE_SETTINGS] = True + # The bellows UART thread sometimes propagates a cancellation into the main Core + # event loop, when a connection to a TCP coordinator fails in a specific way + if ( + CONF_USE_THREAD not in app_config + and radio_type is RadioType.ezsp + and app_config[CONF_DEVICE][CONF_DEVICE_PATH].startswith("socket://") + ): + app_config[CONF_USE_THREAD] = False + # Local import to avoid circular dependencies # pylint: disable-next=import-outside-toplevel from homeassistant.components.homeassistant_hardware.silabs_multiprotocol_addon import ( diff --git a/homeassistant/components/zha/manifest.json b/homeassistant/components/zha/manifest.json index 6a14a3064a6..db5939123e4 100644 --- a/homeassistant/components/zha/manifest.json +++ b/homeassistant/components/zha/manifest.json @@ -21,12 +21,12 @@ "universal_silabs_flasher" ], "requirements": [ - "bellows==0.37.4", + "bellows==0.37.6", "pyserial==3.5", "pyserial-asyncio==0.6", "zha-quirks==0.0.109", - "zigpy-deconz==0.22.3", - "zigpy==0.60.2", + "zigpy-deconz==0.22.4", + "zigpy==0.60.3", "zigpy-xbee==0.20.1", "zigpy-zigate==0.12.0", "zigpy-znp==0.12.1", diff --git a/homeassistant/components/zha/radio_manager.py b/homeassistant/components/zha/radio_manager.py index 92a90e0e13a..d3ca03de8d8 100644 --- a/homeassistant/components/zha/radio_manager.py +++ b/homeassistant/components/zha/radio_manager.py @@ -10,6 +10,7 @@ import logging import os from typing import Any, Self +from bellows.config import CONF_USE_THREAD import voluptuous as vol from zigpy.application import ControllerApplication import zigpy.backups @@ -174,6 +175,7 @@ class ZhaRadioManager: app_config[CONF_DATABASE] = database_path app_config[CONF_DEVICE] = self.device_settings app_config[CONF_NWK_BACKUP_ENABLED] = False + app_config[CONF_USE_THREAD] = False app_config = self.radio_type.controller.SCHEMA(app_config) app = await self.radio_type.controller.new( diff --git a/requirements_all.txt b/requirements_all.txt index 2e93f5a0a32..39ddc20c838 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -526,7 +526,7 @@ beautifulsoup4==4.12.2 # beewi-smartclim==0.0.10 # homeassistant.components.zha -bellows==0.37.4 +bellows==0.37.6 # homeassistant.components.bmw_connected_drive bimmer-connected[china]==0.14.6 @@ -2878,7 +2878,7 @@ zhong-hong-hvac==1.0.9 ziggo-mediabox-xl==1.1.0 # homeassistant.components.zha -zigpy-deconz==0.22.3 +zigpy-deconz==0.22.4 # homeassistant.components.zha zigpy-xbee==0.20.1 @@ -2890,7 +2890,7 @@ zigpy-zigate==0.12.0 zigpy-znp==0.12.1 # homeassistant.components.zha -zigpy==0.60.2 +zigpy==0.60.3 # homeassistant.components.zoneminder zm-py==0.5.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 971e20484a3..6b9c70bc73b 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -448,7 +448,7 @@ base36==0.1.1 beautifulsoup4==4.12.2 # homeassistant.components.zha -bellows==0.37.4 +bellows==0.37.6 # homeassistant.components.bmw_connected_drive bimmer-connected[china]==0.14.6 @@ -2174,7 +2174,7 @@ zeversolar==0.3.1 zha-quirks==0.0.109 # homeassistant.components.zha -zigpy-deconz==0.22.3 +zigpy-deconz==0.22.4 # homeassistant.components.zha zigpy-xbee==0.20.1 @@ -2186,7 +2186,7 @@ zigpy-zigate==0.12.0 zigpy-znp==0.12.1 # homeassistant.components.zha -zigpy==0.60.2 +zigpy==0.60.3 # homeassistant.components.zwave_js zwave-js-server-python==0.55.2 diff --git a/tests/components/zha/test_gateway.py b/tests/components/zha/test_gateway.py index 1d9042daa4a..4f520920704 100644 --- a/tests/components/zha/test_gateway.py +++ b/tests/components/zha/test_gateway.py @@ -1,8 +1,9 @@ """Test ZHA Gateway.""" import asyncio -from unittest.mock import patch +from unittest.mock import MagicMock, patch import pytest +from zigpy.application import ControllerApplication import zigpy.profiles.zha as zha import zigpy.zcl.clusters.general as general import zigpy.zcl.clusters.lighting as lighting @@ -222,6 +223,48 @@ async def test_gateway_create_group_with_id( assert zha_group.group_id == 0x1234 +@patch( + "homeassistant.components.zha.core.gateway.ZHAGateway.async_load_devices", + MagicMock(), +) +@patch( + "homeassistant.components.zha.core.gateway.ZHAGateway.async_load_groups", + MagicMock(), +) +@pytest.mark.parametrize( + ("device_path", "thread_state", "config_override"), + [ + ("/dev/ttyUSB0", True, {}), + ("socket://192.168.1.123:9999", False, {}), + ("socket://192.168.1.123:9999", True, {"use_thread": True}), + ], +) +async def test_gateway_initialize_bellows_thread( + device_path: str, + thread_state: bool, + config_override: dict, + hass: HomeAssistant, + zigpy_app_controller: ControllerApplication, + config_entry: MockConfigEntry, +) -> None: + """Test ZHA disabling the UART thread when connecting to a TCP coordinator.""" + config_entry.data = dict(config_entry.data) + config_entry.data["device"]["path"] = device_path + config_entry.add_to_hass(hass) + + zha_gateway = ZHAGateway(hass, {"zigpy_config": config_override}, config_entry) + + with patch( + "bellows.zigbee.application.ControllerApplication.new", + return_value=zigpy_app_controller, + ) as mock_new: + await zha_gateway.async_initialize() + + mock_new.mock_calls[-1].kwargs["config"]["use_thread"] is thread_state + + await zha_gateway.shutdown() + + @pytest.mark.parametrize( ("device_path", "config_override", "expected_channel"), [