From 8bbf55c85d5c78fb8cd25bbb70906ca43ce47b56 Mon Sep 17 00:00:00 2001 From: Simone Chemelli Date: Fri, 4 Mar 2022 23:43:33 +0100 Subject: [PATCH 01/17] Add unique_id to Fritz diagnostics (#67384) Co-authored-by: Paulus Schoutsen --- homeassistant/components/fritz/diagnostics.py | 3 +++ tests/components/fritz/test_diagnostics.py | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/fritz/diagnostics.py b/homeassistant/components/fritz/diagnostics.py index fa4ff6a7db8..ed45295892b 100644 --- a/homeassistant/components/fritz/diagnostics.py +++ b/homeassistant/components/fritz/diagnostics.py @@ -22,6 +22,9 @@ async def async_get_config_entry_diagnostics( "entry": async_redact_data(entry.as_dict(), TO_REDACT), "device_info": { "model": avm_wrapper.model, + "unique_id": avm_wrapper.unique_id.replace( + avm_wrapper.unique_id[6:11], "XX:XX" + ), "current_firmware": avm_wrapper.current_firmware, "latest_firmware": avm_wrapper.latest_firmware, "update_available": avm_wrapper.update_available, diff --git a/tests/components/fritz/test_diagnostics.py b/tests/components/fritz/test_diagnostics.py index 892210d0844..a4b4942c375 100644 --- a/tests/components/fritz/test_diagnostics.py +++ b/tests/components/fritz/test_diagnostics.py @@ -11,7 +11,7 @@ from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant from homeassistant.setup import async_setup_component -from .const import MOCK_USER_DATA +from .const import MOCK_MESH_MASTER_MAC, MOCK_USER_DATA from tests.common import MockConfigEntry from tests.components.diagnostics import get_diagnostics_for_config_entry @@ -69,6 +69,7 @@ async def test_entry_diagnostics( "latest_firmware": None, "mesh_role": "master", "model": "FRITZ!Box 7530 AX", + "unique_id": MOCK_MESH_MASTER_MAC.replace("6F:12", "XX:XX"), "update_available": False, "wan_link_properties": { "NewLayer1DownstreamMaxBitRate": 318557000, From 9849b86a8455fefe01d09f3ff72c9b153a1bc587 Mon Sep 17 00:00:00 2001 From: Chris Talkington Date: Thu, 3 Mar 2022 23:08:29 -0600 Subject: [PATCH 02/17] Suppress roku power off timeout errors (#67414) --- homeassistant/components/roku/__init__.py | 32 --------------- homeassistant/components/roku/helpers.py | 40 +++++++++++++++++++ homeassistant/components/roku/manifest.json | 2 +- homeassistant/components/roku/media_player.py | 29 +++++++------- homeassistant/components/roku/remote.py | 8 ++-- homeassistant/components/roku/select.py | 5 +-- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/roku/test_media_player.py | 9 ++++- 9 files changed, 70 insertions(+), 59 deletions(-) diff --git a/homeassistant/components/roku/__init__.py b/homeassistant/components/roku/__init__.py index e6e31f08713..f24d08909b8 100644 --- a/homeassistant/components/roku/__init__.py +++ b/homeassistant/components/roku/__init__.py @@ -1,14 +1,6 @@ """Support for Roku.""" from __future__ import annotations -from collections.abc import Awaitable, Callable, Coroutine -from functools import wraps -import logging -from typing import Any, TypeVar - -from rokuecp import RokuConnectionError, RokuError -from typing_extensions import Concatenate, ParamSpec - from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, Platform from homeassistant.core import HomeAssistant @@ -16,7 +8,6 @@ from homeassistant.helpers import config_validation as cv from .const import DOMAIN from .coordinator import RokuDataUpdateCoordinator -from .entity import RokuEntity CONFIG_SCHEMA = cv.removed(DOMAIN, raise_if_present=False) @@ -27,10 +18,6 @@ PLATFORMS = [ Platform.SELECT, Platform.SENSOR, ] -_LOGGER = logging.getLogger(__name__) - -_T = TypeVar("_T", bound="RokuEntity") -_P = ParamSpec("_P") async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: @@ -53,22 +40,3 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: if unload_ok: hass.data[DOMAIN].pop(entry.entry_id) return unload_ok - - -def roku_exception_handler( - func: Callable[Concatenate[_T, _P], Awaitable[None]] # type: ignore[misc] -) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, None]]: # type: ignore[misc] - """Decorate Roku calls to handle Roku exceptions.""" - - @wraps(func) - async def wrapper(self: _T, *args: _P.args, **kwargs: _P.kwargs) -> None: - try: - await func(self, *args, **kwargs) - except RokuConnectionError as error: - if self.available: - _LOGGER.error("Error communicating with API: %s", error) - except RokuError as error: - if self.available: - _LOGGER.error("Invalid response from API: %s", error) - - return wrapper diff --git a/homeassistant/components/roku/helpers.py b/homeassistant/components/roku/helpers.py index 7f507a9fe52..26fdb53c935 100644 --- a/homeassistant/components/roku/helpers.py +++ b/homeassistant/components/roku/helpers.py @@ -1,6 +1,21 @@ """Helpers for Roku.""" from __future__ import annotations +from collections.abc import Awaitable, Callable, Coroutine +from functools import wraps +import logging +from typing import Any, TypeVar + +from rokuecp import RokuConnectionError, RokuConnectionTimeoutError, RokuError +from typing_extensions import Concatenate, ParamSpec + +from .entity import RokuEntity + +_LOGGER = logging.getLogger(__name__) + +_T = TypeVar("_T", bound=RokuEntity) +_P = ParamSpec("_P") + def format_channel_name(channel_number: str, channel_name: str | None = None) -> str: """Format a Roku Channel name.""" @@ -8,3 +23,28 @@ def format_channel_name(channel_number: str, channel_name: str | None = None) -> return f"{channel_name} ({channel_number})" return channel_number + + +def roku_exception_handler(ignore_timeout: bool = False) -> Callable[..., Callable]: + """Decorate Roku calls to handle Roku exceptions.""" + + def decorator( + func: Callable[Concatenate[_T, _P], Awaitable[None]], # type: ignore[misc] + ) -> Callable[Concatenate[_T, _P], Coroutine[Any, Any, None]]: # type: ignore[misc] + @wraps(func) + async def wrapper(self: _T, *args: _P.args, **kwargs: _P.kwargs) -> None: + try: + await func(self, *args, **kwargs) + except RokuConnectionTimeoutError as error: + if not ignore_timeout and self.available: + _LOGGER.error("Error communicating with API: %s", error) + except RokuConnectionError as error: + if self.available: + _LOGGER.error("Error communicating with API: %s", error) + except RokuError as error: + if self.available: + _LOGGER.error("Invalid response from API: %s", error) + + return wrapper + + return decorator diff --git a/homeassistant/components/roku/manifest.json b/homeassistant/components/roku/manifest.json index 4918e7742be..433ce6b29d1 100644 --- a/homeassistant/components/roku/manifest.json +++ b/homeassistant/components/roku/manifest.json @@ -2,7 +2,7 @@ "domain": "roku", "name": "Roku", "documentation": "https://www.home-assistant.io/integrations/roku", - "requirements": ["rokuecp==0.14.1"], + "requirements": ["rokuecp==0.15.0"], "homekit": { "models": ["3810X", "4660X", "7820X", "C105X", "C135X"] }, diff --git a/homeassistant/components/roku/media_player.py b/homeassistant/components/roku/media_player.py index 9cf17d890a4..8dd76f0b9cb 100644 --- a/homeassistant/components/roku/media_player.py +++ b/homeassistant/components/roku/media_player.py @@ -51,7 +51,6 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_platform from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import roku_exception_handler from .browse_media import async_browse_media from .const import ( ATTR_ARTIST_NAME, @@ -65,7 +64,7 @@ from .const import ( ) from .coordinator import RokuDataUpdateCoordinator from .entity import RokuEntity -from .helpers import format_channel_name +from .helpers import format_channel_name, roku_exception_handler _LOGGER = logging.getLogger(__name__) @@ -289,7 +288,7 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity): app.name for app in self.coordinator.data.apps if app.name is not None ) - @roku_exception_handler + @roku_exception_handler() async def search(self, keyword: str) -> None: """Emulate opening the search screen and entering the search keyword.""" await self.coordinator.roku.search(keyword) @@ -321,68 +320,68 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity): media_content_type, ) - @roku_exception_handler + @roku_exception_handler() async def async_turn_on(self) -> None: """Turn on the Roku.""" await self.coordinator.roku.remote("poweron") await self.coordinator.async_request_refresh() - @roku_exception_handler + @roku_exception_handler(ignore_timeout=True) async def async_turn_off(self) -> None: """Turn off the Roku.""" await self.coordinator.roku.remote("poweroff") await self.coordinator.async_request_refresh() - @roku_exception_handler + @roku_exception_handler() async def async_media_pause(self) -> None: """Send pause command.""" if self.state not in (STATE_STANDBY, STATE_PAUSED): await self.coordinator.roku.remote("play") await self.coordinator.async_request_refresh() - @roku_exception_handler + @roku_exception_handler() async def async_media_play(self) -> None: """Send play command.""" if self.state not in (STATE_STANDBY, STATE_PLAYING): await self.coordinator.roku.remote("play") await self.coordinator.async_request_refresh() - @roku_exception_handler + @roku_exception_handler() async def async_media_play_pause(self) -> None: """Send play/pause command.""" if self.state != STATE_STANDBY: await self.coordinator.roku.remote("play") await self.coordinator.async_request_refresh() - @roku_exception_handler + @roku_exception_handler() async def async_media_previous_track(self) -> None: """Send previous track command.""" await self.coordinator.roku.remote("reverse") await self.coordinator.async_request_refresh() - @roku_exception_handler + @roku_exception_handler() async def async_media_next_track(self) -> None: """Send next track command.""" await self.coordinator.roku.remote("forward") await self.coordinator.async_request_refresh() - @roku_exception_handler + @roku_exception_handler() async def async_mute_volume(self, mute: bool) -> None: """Mute the volume.""" await self.coordinator.roku.remote("volume_mute") await self.coordinator.async_request_refresh() - @roku_exception_handler + @roku_exception_handler() async def async_volume_up(self) -> None: """Volume up media player.""" await self.coordinator.roku.remote("volume_up") - @roku_exception_handler + @roku_exception_handler() async def async_volume_down(self) -> None: """Volume down media player.""" await self.coordinator.roku.remote("volume_down") - @roku_exception_handler + @roku_exception_handler() async def async_play_media( self, media_type: str, media_id: str, **kwargs: Any ) -> None: @@ -487,7 +486,7 @@ class RokuMediaPlayer(RokuEntity, MediaPlayerEntity): await self.coordinator.async_request_refresh() - @roku_exception_handler + @roku_exception_handler() async def async_select_source(self, source: str) -> None: """Select input source.""" if source == "Home": diff --git a/homeassistant/components/roku/remote.py b/homeassistant/components/roku/remote.py index 9a0cd6f51e3..6d1312c0b03 100644 --- a/homeassistant/components/roku/remote.py +++ b/homeassistant/components/roku/remote.py @@ -9,10 +9,10 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import roku_exception_handler from .const import DOMAIN from .coordinator import RokuDataUpdateCoordinator from .entity import RokuEntity +from .helpers import roku_exception_handler async def async_setup_entry( @@ -44,19 +44,19 @@ class RokuRemote(RokuEntity, RemoteEntity): """Return true if device is on.""" return not self.coordinator.data.state.standby - @roku_exception_handler + @roku_exception_handler() async def async_turn_on(self, **kwargs: Any) -> None: """Turn the device on.""" await self.coordinator.roku.remote("poweron") await self.coordinator.async_request_refresh() - @roku_exception_handler + @roku_exception_handler(ignore_timeout=True) async def async_turn_off(self, **kwargs: Any) -> None: """Turn the device off.""" await self.coordinator.roku.remote("poweroff") await self.coordinator.async_request_refresh() - @roku_exception_handler + @roku_exception_handler() async def async_send_command(self, command: Iterable[str], **kwargs: Any) -> None: """Send a command to one device.""" num_repeats = kwargs[ATTR_NUM_REPEATS] diff --git a/homeassistant/components/roku/select.py b/homeassistant/components/roku/select.py index 9120a4fe9ce..e11748114d1 100644 --- a/homeassistant/components/roku/select.py +++ b/homeassistant/components/roku/select.py @@ -12,11 +12,10 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback -from . import roku_exception_handler from .const import DOMAIN from .coordinator import RokuDataUpdateCoordinator from .entity import RokuEntity -from .helpers import format_channel_name +from .helpers import format_channel_name, roku_exception_handler @dataclass @@ -163,7 +162,7 @@ class RokuSelectEntity(RokuEntity, SelectEntity): """Return a set of selectable options.""" return self.entity_description.options_fn(self.coordinator.data) - @roku_exception_handler + @roku_exception_handler() async def async_select_option(self, option: str) -> None: """Set the option.""" await self.entity_description.set_fn( diff --git a/requirements_all.txt b/requirements_all.txt index 84f1dbb2004..debbd81d853 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2121,7 +2121,7 @@ rjpl==0.3.6 rocketchat-API==0.6.1 # homeassistant.components.roku -rokuecp==0.14.1 +rokuecp==0.15.0 # homeassistant.components.roomba roombapy==1.6.5 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index d32cd1609b5..92688ce8908 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1313,7 +1313,7 @@ rflink==0.0.62 ring_doorbell==0.7.2 # homeassistant.components.roku -rokuecp==0.14.1 +rokuecp==0.15.0 # homeassistant.components.roomba roombapy==1.6.5 diff --git a/tests/components/roku/test_media_player.py b/tests/components/roku/test_media_player.py index 050814e3817..21fd2e861b6 100644 --- a/tests/components/roku/test_media_player.py +++ b/tests/components/roku/test_media_player.py @@ -3,7 +3,7 @@ from datetime import timedelta from unittest.mock import MagicMock, patch import pytest -from rokuecp import RokuError +from rokuecp import RokuConnectionError, RokuConnectionTimeoutError, RokuError from homeassistant.components.media_player import MediaPlayerDeviceClass from homeassistant.components.media_player.const import ( @@ -164,10 +164,15 @@ async def test_tv_setup( assert device_entry.suggested_area == "Living room" +@pytest.mark.parametrize( + "error", + [RokuConnectionTimeoutError, RokuConnectionError, RokuError], +) async def test_availability( hass: HomeAssistant, mock_roku: MagicMock, mock_config_entry: MockConfigEntry, + error: RokuError, ) -> None: """Test entity availability.""" now = dt_util.utcnow() @@ -179,7 +184,7 @@ async def test_availability( await hass.async_block_till_done() with patch("homeassistant.util.dt.utcnow", return_value=future): - mock_roku.update.side_effect = RokuError + mock_roku.update.side_effect = error async_fire_time_changed(hass, future) await hass.async_block_till_done() assert hass.states.get(MAIN_ENTITY_ID).state == STATE_UNAVAILABLE From 24013ad94cf26a459dcd646e3aa835abf4c3d65c Mon Sep 17 00:00:00 2001 From: Joakim Plate Date: Thu, 3 Mar 2022 11:29:58 +0100 Subject: [PATCH 03/17] rfxtrx: bump to 0.28 (#67530) --- homeassistant/components/rfxtrx/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/rfxtrx/manifest.json b/homeassistant/components/rfxtrx/manifest.json index d7125518329..edbf5c8556c 100644 --- a/homeassistant/components/rfxtrx/manifest.json +++ b/homeassistant/components/rfxtrx/manifest.json @@ -2,7 +2,7 @@ "domain": "rfxtrx", "name": "RFXCOM RFXtrx", "documentation": "https://www.home-assistant.io/integrations/rfxtrx", - "requirements": ["pyRFXtrx==0.27.1"], + "requirements": ["pyRFXtrx==0.28.0"], "codeowners": ["@danielhiversen", "@elupus", "@RobBie1221"], "config_flow": true, "iot_class": "local_push", diff --git a/requirements_all.txt b/requirements_all.txt index debbd81d853..695842fe244 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1360,7 +1360,7 @@ pyMetEireann==2021.8.0 pyMetno==0.9.0 # homeassistant.components.rfxtrx -pyRFXtrx==0.27.1 +pyRFXtrx==0.28.0 # homeassistant.components.switchmate # pySwitchmate==0.4.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 92688ce8908..37b96d4f8ac 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -858,7 +858,7 @@ pyMetEireann==2021.8.0 pyMetno==0.9.0 # homeassistant.components.rfxtrx -pyRFXtrx==0.27.1 +pyRFXtrx==0.28.0 # homeassistant.components.tibber pyTibber==0.22.1 From b54652a849783340d71d8d8724b3bc60d0a8410b Mon Sep 17 00:00:00 2001 From: Teemu R Date: Fri, 4 Mar 2022 05:55:01 +0100 Subject: [PATCH 04/17] Remove use of deprecated xiaomi_miio classes (#67590) --- homeassistant/components/xiaomi_miio/__init__.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/xiaomi_miio/__init__.py b/homeassistant/components/xiaomi_miio/__init__.py index 2849b249762..7fb489b3467 100644 --- a/homeassistant/components/xiaomi_miio/__init__.py +++ b/homeassistant/components/xiaomi_miio/__init__.py @@ -14,7 +14,6 @@ from miio import ( AirHumidifierMiot, AirHumidifierMjjsq, AirPurifier, - AirPurifierMB4, AirPurifierMiot, CleaningDetails, CleaningSummary, @@ -23,10 +22,8 @@ from miio import ( DNDStatus, Fan, Fan1C, + FanMiot, FanP5, - FanP9, - FanP10, - FanP11, FanZA5, RoborockVacuum, Timer, @@ -52,7 +49,6 @@ from .const import ( KEY_DEVICE, MODEL_AIRFRESH_A1, MODEL_AIRFRESH_T2017, - MODEL_AIRPURIFIER_3C, MODEL_FAN_1C, MODEL_FAN_P5, MODEL_FAN_P9, @@ -111,10 +107,10 @@ AIR_MONITOR_PLATFORMS = [Platform.AIR_QUALITY, Platform.SENSOR] MODEL_TO_CLASS_MAP = { MODEL_FAN_1C: Fan1C, - MODEL_FAN_P10: FanP10, - MODEL_FAN_P11: FanP11, + MODEL_FAN_P9: FanMiot, + MODEL_FAN_P10: FanMiot, + MODEL_FAN_P11: FanMiot, MODEL_FAN_P5: FanP5, - MODEL_FAN_P9: FanP9, MODEL_FAN_ZA5: FanZA5, } @@ -314,8 +310,6 @@ async def async_create_miio_device_and_coordinator( device = AirHumidifier(host, token, model=model) migrate = True # Airpurifiers and Airfresh - elif model == MODEL_AIRPURIFIER_3C: - device = AirPurifierMB4(host, token) elif model in MODELS_PURIFIER_MIOT: device = AirPurifierMiot(host, token) elif model.startswith("zhimi.airpurifier."): From 679ddbd1bed99b207e673d15bcd966d884af58ab Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Fri, 4 Mar 2022 10:03:38 +0100 Subject: [PATCH 05/17] Downgrade Renault warning (#67601) Co-authored-by: epenet --- homeassistant/components/renault/renault_vehicle.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/renault/renault_vehicle.py b/homeassistant/components/renault/renault_vehicle.py index 12860bc6b9a..2d15e9c14a3 100644 --- a/homeassistant/components/renault/renault_vehicle.py +++ b/homeassistant/components/renault/renault_vehicle.py @@ -104,7 +104,7 @@ class RenaultVehicleProxy: coordinator = self.coordinators[key] if coordinator.not_supported: # Remove endpoint as it is not supported for this vehicle. - LOGGER.warning( + LOGGER.info( "Ignoring endpoint %s as it is not supported for this vehicle: %s", coordinator.name, coordinator.last_exception, @@ -112,7 +112,7 @@ class RenaultVehicleProxy: del self.coordinators[key] elif coordinator.access_denied: # Remove endpoint as it is denied for this vehicle. - LOGGER.warning( + LOGGER.info( "Ignoring endpoint %s as it is denied for this vehicle: %s", coordinator.name, coordinator.last_exception, From b290e6217063d3f53a0662dd49e97c0464c864dc Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 4 Mar 2022 12:30:40 -1000 Subject: [PATCH 06/17] Handle elkm1 login case with username and insecure login (#67602) --- homeassistant/components/elkm1/__init__.py | 22 ++++++++++--------- homeassistant/components/elkm1/config_flow.py | 4 +--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/homeassistant/components/elkm1/__init__.py b/homeassistant/components/elkm1/__init__.py index 04a26f2822b..6791c2ec1bb 100644 --- a/homeassistant/components/elkm1/__init__.py +++ b/homeassistant/components/elkm1/__init__.py @@ -279,9 +279,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: keypad.add_callback(_element_changed) try: - if not await async_wait_for_elk_to_sync( - elk, LOGIN_TIMEOUT, SYNC_TIMEOUT, bool(conf[CONF_USERNAME]) - ): + if not await async_wait_for_elk_to_sync(elk, LOGIN_TIMEOUT, SYNC_TIMEOUT): return False except asyncio.TimeoutError as exc: raise ConfigEntryNotReady(f"Timed out connecting to {conf[CONF_HOST]}") from exc @@ -334,7 +332,6 @@ async def async_wait_for_elk_to_sync( elk: elkm1.Elk, login_timeout: int, sync_timeout: int, - password_auth: bool, ) -> bool: """Wait until the elk has finished sync. Can fail login or timeout.""" @@ -354,18 +351,23 @@ async def async_wait_for_elk_to_sync( login_event.set() sync_event.set() + def first_response(*args, **kwargs): + _LOGGER.debug("ElkM1 received first response (VN)") + login_event.set() + def sync_complete(): sync_event.set() success = True elk.add_handler("login", login_status) + # VN is the first command sent for panel, when we get + # it back we now we are logged in either with or without a password + elk.add_handler("VN", first_response) elk.add_handler("sync_complete", sync_complete) - events = [] - if password_auth: - events.append(("login", login_event, login_timeout)) - events.append(("sync_complete", sync_event, sync_timeout)) - - for name, event, timeout in events: + for name, event, timeout in ( + ("login", login_event, login_timeout), + ("sync_complete", sync_event, sync_timeout), + ): _LOGGER.debug("Waiting for %s event for %s seconds", name, timeout) try: async with async_timeout.timeout(timeout): diff --git a/homeassistant/components/elkm1/config_flow.py b/homeassistant/components/elkm1/config_flow.py index a21cf186005..96f9fd5d078 100644 --- a/homeassistant/components/elkm1/config_flow.py +++ b/homeassistant/components/elkm1/config_flow.py @@ -81,9 +81,7 @@ async def validate_input(data: dict[str, str], mac: str | None) -> dict[str, str ) elk.connect() - if not await async_wait_for_elk_to_sync( - elk, LOGIN_TIMEOUT, VALIDATE_TIMEOUT, bool(userid) - ): + if not await async_wait_for_elk_to_sync(elk, LOGIN_TIMEOUT, VALIDATE_TIMEOUT): raise InvalidAuth short_mac = _short_mac(mac) if mac else None From 5657a9e6bd44100105ad4387a23a99f78358fafb Mon Sep 17 00:00:00 2001 From: G Johansson Date: Fri, 4 Mar 2022 19:20:10 +0100 Subject: [PATCH 07/17] Fix sql false warning (#67614) --- homeassistant/components/sql/sensor.py | 2 +- tests/components/sql/test_sensor.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/sql/sensor.py b/homeassistant/components/sql/sensor.py index 1c8514d0d26..0a240469f83 100644 --- a/homeassistant/components/sql/sensor.py +++ b/homeassistant/components/sql/sensor.py @@ -172,7 +172,7 @@ class SQLSensor(SensorEntity): else: self._attr_native_value = data - if not data: + if data is None: _LOGGER.warning("%s returned no results", self._query) sess.close() diff --git a/tests/components/sql/test_sensor.py b/tests/components/sql/test_sensor.py index 0e543f98a21..05f49d553e9 100644 --- a/tests/components/sql/test_sensor.py +++ b/tests/components/sql/test_sensor.py @@ -115,7 +115,9 @@ async def test_query_limit(hass: HomeAssistant) -> None: assert state.attributes["value"] == 5 -async def test_query_no_value(hass: HomeAssistant) -> None: +async def test_query_no_value( + hass: HomeAssistant, caplog: pytest.LogCaptureFixture +) -> None: """Test the SQL sensor with a query that returns no value.""" config = { "sensor": { @@ -137,6 +139,9 @@ async def test_query_no_value(hass: HomeAssistant) -> None: state = hass.states.get("sensor.count_tables") assert state.state == STATE_UNKNOWN + text = "SELECT 5 as value where 1=2 returned no results" + assert text in caplog.text + async def test_invalid_query(hass: HomeAssistant) -> None: """Test the SQL sensor for invalid queries.""" From 5ae83e3c4093477e224a22dd3cf0279b0f3f396f Mon Sep 17 00:00:00 2001 From: Simone Chemelli Date: Fri, 4 Mar 2022 23:38:28 +0100 Subject: [PATCH 08/17] Allign logic for Fritz sensors and binary_sensors (#67623) --- .../components/fritz/binary_sensor.py | 13 ++++++---- homeassistant/components/fritz/common.py | 25 ++++++++++++++++++ homeassistant/components/fritz/sensor.py | 26 +++---------------- 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/homeassistant/components/fritz/binary_sensor.py b/homeassistant/components/fritz/binary_sensor.py index b416e0cfb11..db1aac99c47 100644 --- a/homeassistant/components/fritz/binary_sensor.py +++ b/homeassistant/components/fritz/binary_sensor.py @@ -1,6 +1,7 @@ """AVM FRITZ!Box connectivity sensor.""" from __future__ import annotations +from collections.abc import Callable from dataclasses import dataclass import logging @@ -14,8 +15,8 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback -from .common import AvmWrapper, FritzBoxBaseEntity -from .const import DOMAIN, MeshRoles +from .common import AvmWrapper, ConnectionInfo, FritzBoxBaseEntity +from .const import DOMAIN _LOGGER = logging.getLogger(__name__) @@ -24,7 +25,7 @@ _LOGGER = logging.getLogger(__name__) class FritzBinarySensorEntityDescription(BinarySensorEntityDescription): """Describes Fritz sensor entity.""" - exclude_mesh_role: MeshRoles = MeshRoles.SLAVE + is_suitable: Callable[[ConnectionInfo], bool] = lambda info: info.wan_enabled SENSOR_TYPES: tuple[FritzBinarySensorEntityDescription, ...] = ( @@ -45,7 +46,7 @@ SENSOR_TYPES: tuple[FritzBinarySensorEntityDescription, ...] = ( name="Firmware Update", device_class=BinarySensorDeviceClass.UPDATE, entity_category=EntityCategory.DIAGNOSTIC, - exclude_mesh_role=MeshRoles.NONE, + is_suitable=lambda info: True, ), ) @@ -57,10 +58,12 @@ async def async_setup_entry( _LOGGER.debug("Setting up FRITZ!Box binary sensors") avm_wrapper: AvmWrapper = hass.data[DOMAIN][entry.entry_id] + connection_info = await avm_wrapper.async_get_connection_info() + entities = [ FritzBoxBinarySensor(avm_wrapper, entry.title, description) for description in SENSOR_TYPES - if (description.exclude_mesh_role != avm_wrapper.mesh_role) + if description.is_suitable(connection_info) ] async_add_entities(entities, True) diff --git a/homeassistant/components/fritz/common.py b/homeassistant/components/fritz/common.py index 2fc28433e56..4c307c126cd 100644 --- a/homeassistant/components/fritz/common.py +++ b/homeassistant/components/fritz/common.py @@ -642,6 +642,22 @@ class AvmWrapper(FritzBoxTools): partial(self.get_wan_link_properties) ) + async def async_get_connection_info(self) -> ConnectionInfo: + """Return ConnectionInfo data.""" + + link_properties = await self.async_get_wan_link_properties() + connection_info = ConnectionInfo( + connection=link_properties.get("NewWANAccessType", "").lower(), + mesh_role=self.mesh_role, + wan_enabled=self.device_is_router, + ) + _LOGGER.debug( + "ConnectionInfo for FritzBox %s: %s", + self.host, + connection_info, + ) + return connection_info + async def async_get_port_mapping(self, con_type: str, index: int) -> dict[str, Any]: """Call GetGenericPortMappingEntry action.""" @@ -970,3 +986,12 @@ class FritzBoxBaseEntity: name=self._device_name, sw_version=self._avm_wrapper.current_firmware, ) + + +@dataclass +class ConnectionInfo: + """Fritz sensor connection information class.""" + + connection: str + mesh_role: MeshRoles + wan_enabled: bool diff --git a/homeassistant/components/fritz/sensor.py b/homeassistant/components/fritz/sensor.py index f01966d7114..9811adf6829 100644 --- a/homeassistant/components/fritz/sensor.py +++ b/homeassistant/components/fritz/sensor.py @@ -28,8 +28,8 @@ from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.util.dt import utcnow -from .common import AvmWrapper, FritzBoxBaseEntity -from .const import DOMAIN, DSL_CONNECTION, UPTIME_DEVIATION, MeshRoles +from .common import AvmWrapper, ConnectionInfo, FritzBoxBaseEntity +from .const import DOMAIN, DSL_CONNECTION, UPTIME_DEVIATION _LOGGER = logging.getLogger(__name__) @@ -134,15 +134,6 @@ def _retrieve_link_attenuation_received_state( return status.attenuation[1] / 10 # type: ignore[no-any-return] -@dataclass -class ConnectionInfo: - """Fritz sensor connection information class.""" - - connection: str - mesh_role: MeshRoles - wan_enabled: bool - - @dataclass class FritzRequireKeysMixin: """Fritz sensor data class.""" @@ -283,18 +274,7 @@ async def async_setup_entry( _LOGGER.debug("Setting up FRITZ!Box sensors") avm_wrapper: AvmWrapper = hass.data[DOMAIN][entry.entry_id] - link_properties = await avm_wrapper.async_get_wan_link_properties() - connection_info = ConnectionInfo( - connection=link_properties.get("NewWANAccessType", "").lower(), - mesh_role=avm_wrapper.mesh_role, - wan_enabled=avm_wrapper.device_is_router, - ) - - _LOGGER.debug( - "ConnectionInfo for FritzBox %s: %s", - avm_wrapper.host, - connection_info, - ) + connection_info = await avm_wrapper.async_get_connection_info() entities = [ FritzBoxSensor(avm_wrapper, entry.title, description) From 2a6d5ea7bd16f2e1b9ba131fd3effb2f225bc8d0 Mon Sep 17 00:00:00 2001 From: Simone Chemelli Date: Fri, 4 Mar 2022 15:49:22 +0100 Subject: [PATCH 09/17] Improve logging for Fritz switches creation (#67640) --- homeassistant/components/fritz/const.py | 1 + homeassistant/components/fritz/switch.py | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/homeassistant/components/fritz/const.py b/homeassistant/components/fritz/const.py index f739ccf6858..a3ba907366c 100644 --- a/homeassistant/components/fritz/const.py +++ b/homeassistant/components/fritz/const.py @@ -57,6 +57,7 @@ SERVICE_SET_GUEST_WIFI_PW = "set_guest_wifi_password" SWITCH_TYPE_DEFLECTION = "CallDeflection" SWITCH_TYPE_PORTFORWARD = "PortForward" +SWITCH_TYPE_PROFILE = "Profile" SWITCH_TYPE_WIFINETWORK = "WiFiNetwork" UPTIME_DEVIATION = 5 diff --git a/homeassistant/components/fritz/switch.py b/homeassistant/components/fritz/switch.py index 730ffb7fc0d..cac6e735a81 100644 --- a/homeassistant/components/fritz/switch.py +++ b/homeassistant/components/fritz/switch.py @@ -30,6 +30,7 @@ from .const import ( DOMAIN, SWITCH_TYPE_DEFLECTION, SWITCH_TYPE_PORTFORWARD, + SWITCH_TYPE_PROFILE, SWITCH_TYPE_WIFINETWORK, WIFI_STANDARD, MeshRoles, @@ -185,6 +186,7 @@ def profile_entities_list( data_fritz: FritzData, ) -> list[FritzBoxProfileSwitch]: """Add new tracker entities from the AVM device.""" + _LOGGER.debug("Setting up %s switches", SWITCH_TYPE_PROFILE) new_profiles: list[FritzBoxProfileSwitch] = [] @@ -198,11 +200,15 @@ def profile_entities_list( if device_filter_out_from_trackers( mac, device, data_fritz.profile_switches.values() ): + _LOGGER.debug( + "Skipping profile switch creation for device %s", device.hostname + ) continue new_profiles.append(FritzBoxProfileSwitch(avm_wrapper, device)) data_fritz.profile_switches[avm_wrapper.unique_id].add(mac) + _LOGGER.debug("Creating %s profile switches", len(new_profiles)) return new_profiles From d7348718e02612e73ffbb7e363513fd1d8d05dcb Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Fri, 4 Mar 2022 20:17:11 +0100 Subject: [PATCH 10/17] Fix Fan template loosing percentage/preset (#67648) Co-authored-by: J. Nick Koston --- homeassistant/components/template/fan.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/homeassistant/components/template/fan.py b/homeassistant/components/template/fan.py index 1ddd37ba7bc..1d25c24017f 100644 --- a/homeassistant/components/template/fan.py +++ b/homeassistant/components/template/fan.py @@ -277,8 +277,6 @@ class TemplateFan(TemplateEntity, FanEntity): """Turn off the fan.""" await self._off_script.async_run(context=self._context) self._state = STATE_OFF - self._percentage = 0 - self._preset_mode = None async def async_set_percentage(self, percentage: int) -> None: """Set the percentage speed of the fan.""" From f3c85b3459a3ad20ad0b2059ef2483ce577ccf33 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Fri, 4 Mar 2022 23:17:43 +0100 Subject: [PATCH 11/17] Fix reload of media player groups (#67653) --- homeassistant/components/group/__init__.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/group/__init__.py b/homeassistant/components/group/__init__.py index b36d4f1033f..8e595d75db6 100644 --- a/homeassistant/components/group/__init__.py +++ b/homeassistant/components/group/__init__.py @@ -59,11 +59,12 @@ SERVICE_SET = "set" SERVICE_REMOVE = "remove" PLATFORMS = [ - Platform.LIGHT, - Platform.COVER, - Platform.NOTIFY, - Platform.FAN, Platform.BINARY_SENSOR, + Platform.COVER, + Platform.FAN, + Platform.LIGHT, + Platform.MEDIA_PLAYER, + Platform.NOTIFY, ] REG_KEY = f"{DOMAIN}_registry" From f5aaf44e50c6277c4f1705ec0fe742271a9a6e1c Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Fri, 4 Mar 2022 20:09:49 +0100 Subject: [PATCH 12/17] Bump pydroid-ipcam to 1.3.1 (#67655) * Bump pydroid-ipcam to 1.3.1 * Remove loop and set ssl to False --- homeassistant/components/android_ip_webcam/__init__.py | 2 +- homeassistant/components/android_ip_webcam/manifest.json | 2 +- requirements_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/android_ip_webcam/__init__.py b/homeassistant/components/android_ip_webcam/__init__.py index ca4af7fd68a..67bb00f441d 100644 --- a/homeassistant/components/android_ip_webcam/__init__.py +++ b/homeassistant/components/android_ip_webcam/__init__.py @@ -204,13 +204,13 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # Init ip webcam cam = PyDroidIPCam( - hass.loop, websession, host, cam_config[CONF_PORT], username=username, password=password, timeout=cam_config[CONF_TIMEOUT], + ssl=False, ) if switches is None: diff --git a/homeassistant/components/android_ip_webcam/manifest.json b/homeassistant/components/android_ip_webcam/manifest.json index 637a773ac33..39223e6636d 100644 --- a/homeassistant/components/android_ip_webcam/manifest.json +++ b/homeassistant/components/android_ip_webcam/manifest.json @@ -2,7 +2,7 @@ "domain": "android_ip_webcam", "name": "Android IP Webcam", "documentation": "https://www.home-assistant.io/integrations/android_ip_webcam", - "requirements": ["pydroid-ipcam==0.8"], + "requirements": ["pydroid-ipcam==1.3.1"], "codeowners": [], "iot_class": "local_polling" } diff --git a/requirements_all.txt b/requirements_all.txt index 695842fe244..6447f33b2c5 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1486,7 +1486,7 @@ pydispatcher==2.0.5 pydoods==1.0.2 # homeassistant.components.android_ip_webcam -pydroid-ipcam==0.8 +pydroid-ipcam==1.3.1 # homeassistant.components.ebox pyebox==1.1.4 From 4f8b69d985d239cf5bf36d2747141cbf2b4cbb39 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Mar 2022 22:02:22 -1000 Subject: [PATCH 13/17] Ensure elkm1 can be manually configured when discovered instance is not used (#67712) --- homeassistant/components/elkm1/config_flow.py | 14 +- tests/components/elkm1/test_config_flow.py | 153 +++++++++++++++++- 2 files changed, 161 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/elkm1/config_flow.py b/homeassistant/components/elkm1/config_flow.py index 96f9fd5d078..b8cd89edae4 100644 --- a/homeassistant/components/elkm1/config_flow.py +++ b/homeassistant/components/elkm1/config_flow.py @@ -225,7 +225,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): try: info = await validate_input(user_input, self.unique_id) except asyncio.TimeoutError: - return {CONF_HOST: "cannot_connect"}, None + return {"base": "cannot_connect"}, None except InvalidAuth: return {CONF_PASSWORD: "invalid_auth"}, None except Exception: # pylint: disable=broad-except @@ -285,9 +285,13 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): if device := await async_discover_device( self.hass, user_input[CONF_ADDRESS] ): - await self.async_set_unique_id(dr.format_mac(device.mac_address)) + await self.async_set_unique_id( + dr.format_mac(device.mac_address), raise_on_progress=False + ) self._abort_if_unique_id_configured() - user_input[CONF_ADDRESS] = f"{device.ip_address}:{device.port}" + # Ignore the port from discovery since its always going to be + # 2601 if secure is turned on even though they may want insecure + user_input[CONF_ADDRESS] = device.ip_address errors, result = await self._async_create_or_error(user_input, False) if not errors: return result @@ -322,7 +326,9 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): if is_ip_address(host) and ( device := await async_discover_device(self.hass, host) ): - await self.async_set_unique_id(dr.format_mac(device.mac_address)) + await self.async_set_unique_id( + dr.format_mac(device.mac_address), raise_on_progress=False + ) self._abort_if_unique_id_configured() return (await self._async_create_or_error(user_input, True))[1] diff --git a/tests/components/elkm1/test_config_flow.py b/tests/components/elkm1/test_config_flow.py index 49402d7b4d5..183ab90086c 100644 --- a/tests/components/elkm1/test_config_flow.py +++ b/tests/components/elkm1/test_config_flow.py @@ -73,6 +73,155 @@ async def test_form_user_with_secure_elk_no_discovery(hass): assert len(mock_setup_entry.mock_calls) == 1 +async def test_form_user_with_insecure_elk_skip_discovery(hass): + """Test we can setup a insecure elk with skipping discovery.""" + + with _patch_discovery(), _patch_elk(): + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_DHCP}, data=DHCP_DISCOVERY + ) + await hass.async_block_till_done() + + with _patch_discovery(no_device=True): + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + await hass.async_block_till_done() + + assert result["type"] == "form" + assert result["errors"] == {} + assert result["step_id"] == "manual_connection" + + mocked_elk = mock_elk(invalid_auth=False, sync_complete=True) + + with _patch_discovery(), _patch_elk(elk=mocked_elk), patch( + "homeassistant.components.elkm1.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.elkm1.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + "protocol": "non-secure", + "address": "1.2.3.4", + "username": "test-username", + "password": "test-password", + "prefix": "", + }, + ) + await hass.async_block_till_done() + + assert result2["type"] == "create_entry" + assert result2["title"] == "ElkM1" + assert result2["data"] == { + "auto_configure": True, + "host": "elk://1.2.3.4", + "password": "test-password", + "prefix": "", + "username": "test-username", + } + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_form_user_with_insecure_elk_no_discovery(hass): + """Test we can setup a insecure elk.""" + + with _patch_discovery(), _patch_elk(): + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_DHCP}, data=DHCP_DISCOVERY + ) + await hass.async_block_till_done() + + with _patch_discovery(no_device=True): + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + await hass.async_block_till_done() + + assert result["type"] == "form" + assert result["errors"] == {} + assert result["step_id"] == "manual_connection" + + mocked_elk = mock_elk(invalid_auth=False, sync_complete=True) + + with _patch_discovery(no_device=True), _patch_elk(elk=mocked_elk), patch( + "homeassistant.components.elkm1.async_setup", return_value=True + ) as mock_setup, patch( + "homeassistant.components.elkm1.async_setup_entry", + return_value=True, + ) as mock_setup_entry: + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + "protocol": "non-secure", + "address": "1.2.3.4", + "username": "test-username", + "password": "test-password", + "prefix": "", + }, + ) + await hass.async_block_till_done() + + assert result2["type"] == "create_entry" + assert result2["title"] == "ElkM1" + assert result2["data"] == { + "auto_configure": True, + "host": "elk://1.2.3.4", + "password": "test-password", + "prefix": "", + "username": "test-username", + } + assert len(mock_setup.mock_calls) == 1 + assert len(mock_setup_entry.mock_calls) == 1 + + +async def test_form_user_with_insecure_elk_times_out(hass): + """Test we can setup a insecure elk that times out.""" + + with _patch_discovery(), _patch_elk(): + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_DHCP}, data=DHCP_DISCOVERY + ) + await hass.async_block_till_done() + + with _patch_discovery(no_device=True): + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": config_entries.SOURCE_USER} + ) + await hass.async_block_till_done() + + assert result["type"] == "form" + assert result["errors"] == {} + assert result["step_id"] == "manual_connection" + + mocked_elk = mock_elk(invalid_auth=False, sync_complete=False) + + with patch( + "homeassistant.components.elkm1.config_flow.VALIDATE_TIMEOUT", + 0, + ), patch( + "homeassistant.components.elkm1.config_flow.LOGIN_TIMEOUT", 0 + ), _patch_discovery(), _patch_elk( + elk=mocked_elk + ): + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + { + "protocol": "non-secure", + "address": "1.2.3.4", + "username": "test-username", + "password": "test-password", + "prefix": "", + }, + ) + await hass.async_block_till_done() + + assert result2["type"] == RESULT_TYPE_FORM + assert result2["errors"] == {"base": "cannot_connect"} + + async def test_form_user_with_secure_elk_no_discovery_ip_already_configured(hass): """Test we abort when we try to configure the same ip.""" config_entry = MockConfigEntry( @@ -262,7 +411,7 @@ async def test_form_user_with_secure_elk_with_discovery_pick_manual_direct_disco assert result3["title"] == "ElkM1 ddeeff" assert result3["data"] == { "auto_configure": True, - "host": "elks://127.0.0.1:2601", + "host": "elks://127.0.0.1", "password": "test-password", "prefix": "", "username": "test-username", @@ -434,7 +583,7 @@ async def test_form_cannot_connect(hass): ) assert result2["type"] == "form" - assert result2["errors"] == {CONF_HOST: "cannot_connect"} + assert result2["errors"] == {"base": "cannot_connect"} async def test_unknown_exception(hass): From 92c3c08a106bb40e6a6202f920f922661a2be879 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 5 Mar 2022 22:02:45 -1000 Subject: [PATCH 14/17] Add missing disconnect in elkm1 config flow validation (#67716) --- homeassistant/components/elkm1/config_flow.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/elkm1/config_flow.py b/homeassistant/components/elkm1/config_flow.py index b8cd89edae4..d68fce268a2 100644 --- a/homeassistant/components/elkm1/config_flow.py +++ b/homeassistant/components/elkm1/config_flow.py @@ -81,8 +81,11 @@ async def validate_input(data: dict[str, str], mac: str | None) -> dict[str, str ) elk.connect() - if not await async_wait_for_elk_to_sync(elk, LOGIN_TIMEOUT, VALIDATE_TIMEOUT): - raise InvalidAuth + try: + if not await async_wait_for_elk_to_sync(elk, LOGIN_TIMEOUT, VALIDATE_TIMEOUT): + raise InvalidAuth + finally: + elk.disconnect() short_mac = _short_mac(mac) if mac else None if prefix and prefix != short_mac: From 10a2c97cab4ac83e35f0a0ec38e467f8c63a1d65 Mon Sep 17 00:00:00 2001 From: Avi Miller Date: Sun, 6 Mar 2022 19:03:52 +1100 Subject: [PATCH 15/17] Update aiolifx dependency to resolve log flood (#67721) --- homeassistant/components/lifx/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/lifx/manifest.json b/homeassistant/components/lifx/manifest.json index b034745ee31..9251bcb1f50 100644 --- a/homeassistant/components/lifx/manifest.json +++ b/homeassistant/components/lifx/manifest.json @@ -3,7 +3,7 @@ "name": "LIFX", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/lifx", - "requirements": ["aiolifx==0.7.0", "aiolifx_effects==0.2.2"], + "requirements": ["aiolifx==0.7.1", "aiolifx_effects==0.2.2"], "homekit": { "models": ["LIFX"] }, diff --git a/requirements_all.txt b/requirements_all.txt index 6447f33b2c5..973cfb19c59 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -206,7 +206,7 @@ aiokafka==0.6.0 aiokef==0.2.16 # homeassistant.components.lifx -aiolifx==0.7.0 +aiolifx==0.7.1 # homeassistant.components.lifx aiolifx_effects==0.2.2 From 88e0380aa21b2de7a6b668831bde7089c509ac89 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 6 Mar 2022 00:07:45 -0800 Subject: [PATCH 16/17] Bumped version to 2022.3.2 --- homeassistant/const.py | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 9c546af49f8..e91d5cf3725 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -7,7 +7,7 @@ from .backports.enum import StrEnum MAJOR_VERSION: Final = 2022 MINOR_VERSION: Final = 3 -PATCH_VERSION: Final = "1" +PATCH_VERSION: Final = "2" __short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__: Final = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 9, 0) diff --git a/setup.cfg b/setup.cfg index 1d731bfdb9c..e9a6dbb8ee5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = homeassistant -version = 2022.3.1 +version = 2022.3.2 author = The Home Assistant Authors author_email = hello@home-assistant.io license = Apache-2.0 From 76336df91acd09563ec7581496c8cac1c77a3be8 Mon Sep 17 00:00:00 2001 From: Jc2k Date: Sun, 6 Mar 2022 16:45:41 +0000 Subject: [PATCH 17/17] Fix regression with homekit_controller + Aqara motion/vibration sensors (#67740) --- homeassistant/components/homekit_controller/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/homekit_controller/manifest.json b/homeassistant/components/homekit_controller/manifest.json index dfd45991b3f..9ca447ad2fe 100644 --- a/homeassistant/components/homekit_controller/manifest.json +++ b/homeassistant/components/homekit_controller/manifest.json @@ -3,7 +3,7 @@ "name": "HomeKit Controller", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/homekit_controller", - "requirements": ["aiohomekit==0.7.15"], + "requirements": ["aiohomekit==0.7.16"], "zeroconf": ["_hap._tcp.local."], "after_dependencies": ["zeroconf"], "codeowners": ["@Jc2k", "@bdraco"], diff --git a/requirements_all.txt b/requirements_all.txt index 973cfb19c59..2ec33b35621 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -184,7 +184,7 @@ aioguardian==2021.11.0 aioharmony==0.2.9 # homeassistant.components.homekit_controller -aiohomekit==0.7.15 +aiohomekit==0.7.16 # homeassistant.components.emulated_hue # homeassistant.components.http diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 37b96d4f8ac..070b4e3b10b 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -134,7 +134,7 @@ aioguardian==2021.11.0 aioharmony==0.2.9 # homeassistant.components.homekit_controller -aiohomekit==0.7.15 +aiohomekit==0.7.16 # homeassistant.components.emulated_hue # homeassistant.components.http