From e671ad41ec6da3db2a5f44b60a3eeae413696b36 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Mon, 6 Sep 2021 09:50:54 -0400 Subject: [PATCH] Replace zigpy-cc with zigpy-znp (#55828) * Replace zigpy-cc with zigpy-znp in a ZHA config migration * Fix failing unit tests --- homeassistant/components/zha/__init__.py | 11 ++++- homeassistant/components/zha/config_flow.py | 2 +- homeassistant/components/zha/core/const.py | 7 --- homeassistant/components/zha/core/gateway.py | 8 ++-- homeassistant/components/zha/manifest.json | 1 - requirements_all.txt | 3 -- requirements_test_all.txt | 3 -- tests/components/zha/test_config_flow.py | 48 +++++++++++++++++--- tests/components/zha/test_init.py | 6 +-- 9 files changed, 61 insertions(+), 28 deletions(-) diff --git a/homeassistant/components/zha/__init__.py b/homeassistant/components/zha/__init__.py index e5b8c0936fd..b50adf15020 100644 --- a/homeassistant/components/zha/__init__.py +++ b/homeassistant/components/zha/__init__.py @@ -184,7 +184,16 @@ async def async_migrate_entry( data[CONF_DEVICE][CONF_BAUDRATE] = baudrate config_entry.version = 2 - hass.config_entries.async_update_entry(config_entry, data=data) + config_entry.data = data + + if config_entry.version == 2: + data = {**config_entry.data} + + if data[CONF_RADIO_TYPE] == "ti_cc": + data[CONF_RADIO_TYPE] = "znp" + + config_entry.version = 3 + config_entry.data = data _LOGGER.info("Migration to version %s successful", config_entry.version) return True diff --git a/homeassistant/components/zha/config_flow.py b/homeassistant/components/zha/config_flow.py index 481b79c5aa7..9173db4d510 100644 --- a/homeassistant/components/zha/config_flow.py +++ b/homeassistant/components/zha/config_flow.py @@ -31,7 +31,7 @@ DECONZ_DOMAIN = "deconz" class ZhaFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): """Handle a config flow.""" - VERSION = 2 + VERSION = 3 def __init__(self): """Initialize flow instance.""" diff --git a/homeassistant/components/zha/core/const.py b/homeassistant/components/zha/core/const.py index 04ed3ba4281..fe0240472bd 100644 --- a/homeassistant/components/zha/core/const.py +++ b/homeassistant/components/zha/core/const.py @@ -7,7 +7,6 @@ import logging import bellows.zigbee.application import voluptuous as vol from zigpy.config import CONF_DEVICE_PATH # noqa: F401 # pylint: disable=unused-import -import zigpy_cc.zigbee.application import zigpy_deconz.zigbee.application import zigpy_xbee.zigbee.application import zigpy_zigate.zigbee.application @@ -181,7 +180,6 @@ DATA_ZHA_SHUTDOWN_TASK = "zha_shutdown_task" DEBUG_COMP_BELLOWS = "bellows" DEBUG_COMP_ZHA = "homeassistant.components.zha" DEBUG_COMP_ZIGPY = "zigpy" -DEBUG_COMP_ZIGPY_CC = "zigpy_cc" DEBUG_COMP_ZIGPY_ZNP = "zigpy_znp" DEBUG_COMP_ZIGPY_DECONZ = "zigpy_deconz" DEBUG_COMP_ZIGPY_XBEE = "zigpy_xbee" @@ -192,7 +190,6 @@ DEBUG_LEVELS = { DEBUG_COMP_BELLOWS: logging.DEBUG, DEBUG_COMP_ZHA: logging.DEBUG, DEBUG_COMP_ZIGPY: logging.DEBUG, - DEBUG_COMP_ZIGPY_CC: logging.DEBUG, DEBUG_COMP_ZIGPY_ZNP: logging.DEBUG, DEBUG_COMP_ZIGPY_DECONZ: logging.DEBUG, DEBUG_COMP_ZIGPY_XBEE: logging.DEBUG, @@ -246,10 +243,6 @@ class RadioType(enum.Enum): "deCONZ = dresden elektronik deCONZ protocol: ConBee I/II, RaspBee I/II", zigpy_deconz.zigbee.application.ControllerApplication, ) - ti_cc = ( - "Legacy TI_CC = Texas Instruments Z-Stack ZNP protocol: CC253x, CC26x2, CC13x2", - zigpy_cc.zigbee.application.ControllerApplication, - ) zigate = ( "ZiGate = ZiGate Zigbee radios: PiZiGate, ZiGate USB-TTL, ZiGate WiFi", zigpy_zigate.zigbee.application.ControllerApplication, diff --git a/homeassistant/components/zha/core/gateway.py b/homeassistant/components/zha/core/gateway.py index 50da16802b3..4e793b39a8a 100644 --- a/homeassistant/components/zha/core/gateway.py +++ b/homeassistant/components/zha/core/gateway.py @@ -46,10 +46,10 @@ from .const import ( DEBUG_COMP_BELLOWS, DEBUG_COMP_ZHA, DEBUG_COMP_ZIGPY, - DEBUG_COMP_ZIGPY_CC, DEBUG_COMP_ZIGPY_DECONZ, DEBUG_COMP_ZIGPY_XBEE, DEBUG_COMP_ZIGPY_ZIGATE, + DEBUG_COMP_ZIGPY_ZNP, DEBUG_LEVEL_CURRENT, DEBUG_LEVEL_ORIGINAL, DEBUG_LEVELS, @@ -689,7 +689,9 @@ def async_capture_log_levels(): DEBUG_COMP_BELLOWS: logging.getLogger(DEBUG_COMP_BELLOWS).getEffectiveLevel(), DEBUG_COMP_ZHA: logging.getLogger(DEBUG_COMP_ZHA).getEffectiveLevel(), DEBUG_COMP_ZIGPY: logging.getLogger(DEBUG_COMP_ZIGPY).getEffectiveLevel(), - DEBUG_COMP_ZIGPY_CC: logging.getLogger(DEBUG_COMP_ZIGPY_CC).getEffectiveLevel(), + DEBUG_COMP_ZIGPY_ZNP: logging.getLogger( + DEBUG_COMP_ZIGPY_ZNP + ).getEffectiveLevel(), DEBUG_COMP_ZIGPY_DECONZ: logging.getLogger( DEBUG_COMP_ZIGPY_DECONZ ).getEffectiveLevel(), @@ -708,7 +710,7 @@ def async_set_logger_levels(levels): logging.getLogger(DEBUG_COMP_BELLOWS).setLevel(levels[DEBUG_COMP_BELLOWS]) logging.getLogger(DEBUG_COMP_ZHA).setLevel(levels[DEBUG_COMP_ZHA]) logging.getLogger(DEBUG_COMP_ZIGPY).setLevel(levels[DEBUG_COMP_ZIGPY]) - logging.getLogger(DEBUG_COMP_ZIGPY_CC).setLevel(levels[DEBUG_COMP_ZIGPY_CC]) + logging.getLogger(DEBUG_COMP_ZIGPY_ZNP).setLevel(levels[DEBUG_COMP_ZIGPY_ZNP]) logging.getLogger(DEBUG_COMP_ZIGPY_DECONZ).setLevel(levels[DEBUG_COMP_ZIGPY_DECONZ]) logging.getLogger(DEBUG_COMP_ZIGPY_XBEE).setLevel(levels[DEBUG_COMP_ZIGPY_XBEE]) logging.getLogger(DEBUG_COMP_ZIGPY_ZIGATE).setLevel(levels[DEBUG_COMP_ZIGPY_ZIGATE]) diff --git a/homeassistant/components/zha/manifest.json b/homeassistant/components/zha/manifest.json index 4b2b27e829c..19ffff2f12b 100644 --- a/homeassistant/components/zha/manifest.json +++ b/homeassistant/components/zha/manifest.json @@ -8,7 +8,6 @@ "pyserial==3.5", "pyserial-asyncio==0.5", "zha-quirks==0.0.60", - "zigpy-cc==0.5.2", "zigpy-deconz==0.13.0", "zigpy==0.37.1", "zigpy-xbee==0.14.0", diff --git a/requirements_all.txt b/requirements_all.txt index 60bfe276c37..cfe5c4ea8ec 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2467,9 +2467,6 @@ zhong_hong_hvac==1.0.9 # homeassistant.components.ziggo_mediabox_xl ziggo-mediabox-xl==1.1.0 -# homeassistant.components.zha -zigpy-cc==0.5.2 - # homeassistant.components.zha zigpy-deconz==0.13.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 57c001d6c1c..7b5185dac17 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1381,9 +1381,6 @@ zeroconf==0.36.2 # homeassistant.components.zha zha-quirks==0.0.60 -# homeassistant.components.zha -zigpy-cc==0.5.2 - # homeassistant.components.zha zigpy-deconz==0.13.0 diff --git a/tests/components/zha/test_config_flow.py b/tests/components/zha/test_config_flow.py index 732b7cf440d..c00e25fa636 100644 --- a/tests/components/zha/test_config_flow.py +++ b/tests/components/zha/test_config_flow.py @@ -13,7 +13,7 @@ from homeassistant.components.ssdp import ( ATTR_UPNP_MANUFACTURER_URL, ATTR_UPNP_SERIAL, ) -from homeassistant.components.zha import config_flow +from homeassistant.components.zha import async_migrate_entry, config_flow from homeassistant.components.zha.core.const import ( CONF_BAUDRATE, CONF_FLOWCONTROL, @@ -447,7 +447,7 @@ async def test_user_flow_existing_config_entry(hass): assert result["type"] == "abort" -@patch("zigpy_cc.zigbee.application.ControllerApplication.probe", return_value=False) +@patch("zigpy_znp.zigbee.application.ControllerApplication.probe", return_value=False) @patch( "zigpy_deconz.zigbee.application.ControllerApplication.probe", return_value=False ) @@ -455,7 +455,7 @@ async def test_user_flow_existing_config_entry(hass): "zigpy_zigate.zigbee.application.ControllerApplication.probe", return_value=False ) @patch("zigpy_xbee.zigbee.application.ControllerApplication.probe", return_value=False) -async def test_probe_radios(xbee_probe, zigate_probe, deconz_probe, cc_probe, hass): +async def test_probe_radios(xbee_probe, zigate_probe, deconz_probe, znp_probe, hass): """Test detect radios.""" app_ctrl_cls = MagicMock() app_ctrl_cls.SCHEMA_DEVICE = zigpy.config.SCHEMA_DEVICE @@ -468,6 +468,7 @@ async def test_probe_radios(xbee_probe, zigate_probe, deconz_probe, cc_probe, ha with p1 as probe_mock: res = await config_flow.detect_radios("/dev/null") assert probe_mock.await_count == 1 + assert znp_probe.await_count == 1 # ZNP appears earlier in the radio list assert res[CONF_RADIO_TYPE] == "ezsp" assert zigpy.config.CONF_DEVICE in res assert ( @@ -479,10 +480,10 @@ async def test_probe_radios(xbee_probe, zigate_probe, deconz_probe, cc_probe, ha assert xbee_probe.await_count == 1 assert zigate_probe.await_count == 1 assert deconz_probe.await_count == 1 - assert cc_probe.await_count == 1 + assert znp_probe.await_count == 2 -@patch("zigpy_cc.zigbee.application.ControllerApplication.probe", return_value=False) +@patch("zigpy_znp.zigbee.application.ControllerApplication.probe", return_value=False) @patch( "zigpy_deconz.zigbee.application.ControllerApplication.probe", return_value=False ) @@ -490,7 +491,7 @@ async def test_probe_radios(xbee_probe, zigate_probe, deconz_probe, cc_probe, ha "zigpy_zigate.zigbee.application.ControllerApplication.probe", return_value=False ) @patch("zigpy_xbee.zigbee.application.ControllerApplication.probe", return_value=False) -async def test_probe_new_ezsp(xbee_probe, zigate_probe, deconz_probe, cc_probe, hass): +async def test_probe_new_ezsp(xbee_probe, zigate_probe, deconz_probe, znp_probe, hass): """Test detect radios.""" app_ctrl_cls = MagicMock() app_ctrl_cls.SCHEMA_DEVICE = zigpy.config.SCHEMA_DEVICE @@ -560,3 +561,38 @@ async def test_user_port_config(probe_mock, hass): ) assert result["data"][CONF_RADIO_TYPE] == "ezsp" assert probe_mock.await_count == 1 + + +@pytest.mark.parametrize( + "old_type,new_type", + [ + ("ezsp", "ezsp"), + ("ti_cc", "znp"), # only one that should change + ("znp", "znp"), + ("deconz", "deconz"), + ], +) +async def test_migration_ti_cc_to_znp(old_type, new_type, hass, config_entry): + """Test zigpy-cc to zigpy-znp config migration.""" + await setup.async_setup_component(hass, "persistent_notification", {}) + + config_entry = MockConfigEntry( + domain=DOMAIN, + unique_id=old_type + new_type, + data={ + CONF_RADIO_TYPE: old_type, + CONF_DEVICE: { + CONF_DEVICE_PATH: "/dev/ttyUSB1", + CONF_BAUDRATE: 115200, + CONF_FLOWCONTROL: None, + }, + }, + ) + + config_entry.version = 2 + config_entry.add_to_hass(hass) + + await async_migrate_entry(hass, config_entry) + + assert config_entry.version > 2 + assert config_entry.data[CONF_RADIO_TYPE] == new_type diff --git a/tests/components/zha/test_init.py b/tests/components/zha/test_init.py index f259febd817..bb8c502562e 100644 --- a/tests/components/zha/test_init.py +++ b/tests/components/zha/test_init.py @@ -42,7 +42,7 @@ async def test_migration_from_v1_no_baudrate(hass, config_entry_v1, config): assert config_entry_v1.data[CONF_DEVICE][CONF_DEVICE_PATH] == DATA_PORT_PATH assert CONF_BAUDRATE not in config_entry_v1.data[CONF_DEVICE] assert CONF_USB_PATH not in config_entry_v1.data - assert config_entry_v1.version == 2 + assert config_entry_v1.version == 3 @patch("homeassistant.components.zha.async_setup_entry", AsyncMock(return_value=True)) @@ -57,7 +57,7 @@ async def test_migration_from_v1_with_baudrate(hass, config_entry_v1): assert CONF_USB_PATH not in config_entry_v1.data assert CONF_BAUDRATE in config_entry_v1.data[CONF_DEVICE] assert config_entry_v1.data[CONF_DEVICE][CONF_BAUDRATE] == 115200 - assert config_entry_v1.version == 2 + assert config_entry_v1.version == 3 @patch("homeassistant.components.zha.async_setup_entry", AsyncMock(return_value=True)) @@ -71,7 +71,7 @@ async def test_migration_from_v1_wrong_baudrate(hass, config_entry_v1): assert config_entry_v1.data[CONF_DEVICE][CONF_DEVICE_PATH] == DATA_PORT_PATH assert CONF_USB_PATH not in config_entry_v1.data assert CONF_BAUDRATE not in config_entry_v1.data[CONF_DEVICE] - assert config_entry_v1.version == 2 + assert config_entry_v1.version == 3 @pytest.mark.skipif(