diff --git a/homeassistant/components/bmw_connected_drive/notify.py b/homeassistant/components/bmw_connected_drive/notify.py index 14f6c94dff6..b48441ae5fe 100644 --- a/homeassistant/components/bmw_connected_drive/notify.py +++ b/homeassistant/components/bmw_connected_drive/notify.py @@ -56,7 +56,7 @@ class BMWNotificationService(BaseNotificationService): """Set up the notification service.""" self.targets: dict[str, MyBMWVehicle] = targets - def send_message(self, message: str = "", **kwargs: Any) -> None: + async def async_send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message or POI to the car.""" for vehicle in kwargs[ATTR_TARGET]: vehicle = cast(MyBMWVehicle, vehicle) @@ -81,6 +81,6 @@ class BMWNotificationService(BaseNotificationService): } ) - vehicle.remote_services.trigger_send_poi(location_dict) + await vehicle.remote_services.trigger_send_poi(location_dict) else: raise ValueError(f"'data.{ATTR_LOCATION}' is required.") diff --git a/homeassistant/components/evohome/climate.py b/homeassistant/components/evohome/climate.py index c1a630d0d05..e9eab8c2ae3 100644 --- a/homeassistant/components/evohome/climate.py +++ b/homeassistant/components/evohome/climate.py @@ -128,26 +128,17 @@ class EvoClimateEntity(EvoDevice, ClimateEntity): _attr_temperature_unit = TEMP_CELSIUS - def __init__(self, evo_broker, evo_device) -> None: - """Initialize a Climate device.""" - super().__init__(evo_broker, evo_device) - - self._preset_modes = None - @property def hvac_modes(self) -> list[str]: """Return a list of available hvac operation modes.""" return list(HA_HVAC_TO_TCS) - @property - def preset_modes(self) -> list[str] | None: - """Return a list of available preset modes.""" - return self._preset_modes - class EvoZone(EvoChild, EvoClimateEntity): """Base for a Honeywell TCC Zone.""" + _attr_preset_modes = list(HA_PRESET_TO_EVO) + def __init__(self, evo_broker, evo_device) -> None: """Initialize a Honeywell TCC Zone.""" super().__init__(evo_broker, evo_device) @@ -233,7 +224,7 @@ class EvoZone(EvoChild, EvoClimateEntity): """ return self._evo_device.setpointCapabilities["maxHeatSetpoint"] - async def async_set_temperature(self, **kwargs) -> None: + async def async_set_temperature(self, **kwargs: Any) -> None: """Set a new target temperature.""" temperature = kwargs["temperature"] @@ -249,7 +240,7 @@ class EvoZone(EvoChild, EvoClimateEntity): self._evo_device.set_temperature(temperature, until=until) ) - async def async_set_hvac_mode(self, hvac_mode: str) -> None: + async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: """Set a Zone to one of its native EVO_* operating modes. Zones inherit their _effective_ operating mode from their Controller. @@ -387,7 +378,7 @@ class EvoController(EvoClimateEntity): """Return the current preset mode, e.g., home, away, temp.""" return TCS_PRESET_TO_HA.get(self._evo_tcs.systemModeStatus["mode"]) - async def async_set_temperature(self, **kwargs) -> None: + async def async_set_temperature(self, **kwargs: Any) -> None: """Raise exception as Controllers don't have a target temperature.""" raise NotImplementedError("Evohome Controllers don't have target temperatures.") diff --git a/homeassistant/components/govee_ble/config_flow.py b/homeassistant/components/govee_ble/config_flow.py index 1e3a5566bfd..47d73f2779a 100644 --- a/homeassistant/components/govee_ble/config_flow.py +++ b/homeassistant/components/govee_ble/config_flow.py @@ -67,6 +67,7 @@ class GoveeConfigFlow(ConfigFlow, domain=DOMAIN): if user_input is not None: address = user_input[CONF_ADDRESS] await self.async_set_unique_id(address, raise_on_progress=False) + self._abort_if_unique_id_configured() return self.async_create_entry( title=self._discovered_devices[address], data={} ) diff --git a/homeassistant/components/govee_ble/manifest.json b/homeassistant/components/govee_ble/manifest.json index 2ba97b95d08..74917e3ca14 100644 --- a/homeassistant/components/govee_ble/manifest.json +++ b/homeassistant/components/govee_ble/manifest.json @@ -19,6 +19,10 @@ "manufacturer_id": 818, "service_uuid": "00008551-0000-1000-8000-00805f9b34fb" }, + { + "manufacturer_id": 59970, + "service_uuid": "00008151-0000-1000-8000-00805f9b34fb" + }, { "manufacturer_id": 14474, "service_uuid": "00008151-0000-1000-8000-00805f9b34fb" @@ -28,7 +32,7 @@ "service_uuid": "00008251-0000-1000-8000-00805f9b34fb" } ], - "requirements": ["govee-ble==0.14.0"], + "requirements": ["govee-ble==0.14.1"], "dependencies": ["bluetooth"], "codeowners": ["@bdraco"], "iot_class": "local_push" diff --git a/homeassistant/components/homekit_controller/manifest.json b/homeassistant/components/homekit_controller/manifest.json index cf3069e3b0d..4bd9a0b70f9 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==1.2.8"], + "requirements": ["aiohomekit==1.2.9"], "zeroconf": ["_hap._tcp.local.", "_hap._udp.local."], "bluetooth": [{ "manufacturer_id": 76, "manufacturer_data_start": [6] }], "dependencies": ["bluetooth", "zeroconf"], diff --git a/homeassistant/components/huawei_lte/__init__.py b/homeassistant/components/huawei_lte/__init__.py index bace633f128..565286c4505 100644 --- a/homeassistant/components/huawei_lte/__init__.py +++ b/homeassistant/components/huawei_lte/__init__.py @@ -279,11 +279,12 @@ class Router: self._get_data( KEY_WLAN_WIFI_GUEST_NETWORK_SWITCH, lambda: next( - filter( - lambda ssid: ssid.get("wifiisguestnetwork") == "1", - self.client.wlan.multi_basic_settings() + ( + ssid + for ssid in self.client.wlan.multi_basic_settings() .get("Ssids", {}) - .get("Ssid", []), + .get("Ssid", []) + if isinstance(ssid, dict) and ssid.get("wifiisguestnetwork") == "1" ), {}, ), diff --git a/homeassistant/components/huawei_lte/switch.py b/homeassistant/components/huawei_lte/switch.py index 78579d62698..261b77987cf 100644 --- a/homeassistant/components/huawei_lte/switch.py +++ b/homeassistant/components/huawei_lte/switch.py @@ -37,7 +37,7 @@ async def async_setup_entry( if router.data.get(KEY_DIALUP_MOBILE_DATASWITCH): switches.append(HuaweiLteMobileDataSwitch(router)) - if router.data.get(KEY_WLAN_WIFI_GUEST_NETWORK_SWITCH).get("WifiEnable"): + if router.data.get(KEY_WLAN_WIFI_GUEST_NETWORK_SWITCH, {}).get("WifiEnable"): switches.append(HuaweiLteWifiGuestNetworkSwitch(router)) async_add_entities(switches, True) @@ -151,6 +151,6 @@ class HuaweiLteWifiGuestNetworkSwitch(HuaweiLteBaseSwitch): return "mdi:wifi" if self.is_on else "mdi:wifi-off" @property - def extra_state_attributes(self) -> dict[str, str]: + def extra_state_attributes(self) -> dict[str, str | None]: """Return the state attributes.""" return {"ssid": self.router.data[self.key].get("WifiSsid")} diff --git a/homeassistant/components/inkbird/config_flow.py b/homeassistant/components/inkbird/config_flow.py index 21ed85e117e..524471bbcc7 100644 --- a/homeassistant/components/inkbird/config_flow.py +++ b/homeassistant/components/inkbird/config_flow.py @@ -67,6 +67,7 @@ class INKBIRDConfigFlow(ConfigFlow, domain=DOMAIN): if user_input is not None: address = user_input[CONF_ADDRESS] await self.async_set_unique_id(address, raise_on_progress=False) + self._abort_if_unique_id_configured() return self.async_create_entry( title=self._discovered_devices[address], data={} ) diff --git a/homeassistant/components/moat/config_flow.py b/homeassistant/components/moat/config_flow.py index 6f51b62d110..0e1b4f89568 100644 --- a/homeassistant/components/moat/config_flow.py +++ b/homeassistant/components/moat/config_flow.py @@ -67,6 +67,7 @@ class MoatConfigFlow(ConfigFlow, domain=DOMAIN): if user_input is not None: address = user_input[CONF_ADDRESS] await self.async_set_unique_id(address, raise_on_progress=False) + self._abort_if_unique_id_configured() return self.async_create_entry( title=self._discovered_devices[address], data={} ) diff --git a/homeassistant/components/sensorpush/config_flow.py b/homeassistant/components/sensorpush/config_flow.py index d10c2f481a6..63edd59a5b7 100644 --- a/homeassistant/components/sensorpush/config_flow.py +++ b/homeassistant/components/sensorpush/config_flow.py @@ -67,6 +67,7 @@ class SensorPushConfigFlow(ConfigFlow, domain=DOMAIN): if user_input is not None: address = user_input[CONF_ADDRESS] await self.async_set_unique_id(address, raise_on_progress=False) + self._abort_if_unique_id_configured() return self.async_create_entry( title=self._discovered_devices[address], data={} ) diff --git a/homeassistant/components/spotify/media_player.py b/homeassistant/components/spotify/media_player.py index 04f523c2d4b..5fcb5f28264 100644 --- a/homeassistant/components/spotify/media_player.py +++ b/homeassistant/components/spotify/media_player.py @@ -180,7 +180,10 @@ class SpotifyMediaPlayer(MediaPlayerEntity): @property def media_position(self) -> int | None: """Position of current playing media in seconds.""" - if not self._currently_playing: + if ( + not self._currently_playing + or self._currently_playing.get("progress_ms") is None + ): return None return self._currently_playing["progress_ms"] / 1000 diff --git a/homeassistant/components/swisscom/device_tracker.py b/homeassistant/components/swisscom/device_tracker.py index 3c8e7341be2..d95067e6b33 100644 --- a/homeassistant/components/swisscom/device_tracker.py +++ b/homeassistant/components/swisscom/device_tracker.py @@ -4,7 +4,6 @@ from __future__ import annotations from contextlib import suppress import logging -from aiohttp.hdrs import CONTENT_TYPE import requests import voluptuous as vol @@ -79,7 +78,7 @@ class SwisscomDeviceScanner(DeviceScanner): def get_swisscom_data(self): """Retrieve data from Swisscom and return parsed result.""" url = f"http://{self.host}/ws" - headers = {CONTENT_TYPE: "application/x-sah-ws-4-call+json"} + headers = {"Content-Type": "application/x-sah-ws-4-call+json"} data = """ {"service":"Devices", "method":"get", "parameters":{"expression":"lan and not self"}}""" diff --git a/homeassistant/components/xiaomi_ble/config_flow.py b/homeassistant/components/xiaomi_ble/config_flow.py index a05e703db6a..4ec3b66d0f9 100644 --- a/homeassistant/components/xiaomi_ble/config_flow.py +++ b/homeassistant/components/xiaomi_ble/config_flow.py @@ -205,6 +205,7 @@ class XiaomiConfigFlow(ConfigFlow, domain=DOMAIN): if user_input is not None: address = user_input[CONF_ADDRESS] await self.async_set_unique_id(address, raise_on_progress=False) + self._abort_if_unique_id_configured() discovery = self._discovered_devices[address] self.context["title_placeholders"] = {"name": discovery.title} diff --git a/homeassistant/components/zha/manifest.json b/homeassistant/components/zha/manifest.json index bad84054f1f..1eb2536fed6 100644 --- a/homeassistant/components/zha/manifest.json +++ b/homeassistant/components/zha/manifest.json @@ -4,12 +4,12 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/zha", "requirements": [ - "bellows==0.31.3", + "bellows==0.32.0", "pyserial==3.5", "pyserial-asyncio==0.6", "zha-quirks==0.0.78", "zigpy-deconz==0.18.0", - "zigpy==0.49.0", + "zigpy==0.49.1", "zigpy-xbee==0.15.0", "zigpy-zigate==0.9.1", "zigpy-znp==0.8.1" diff --git a/homeassistant/const.py b/homeassistant/const.py index f877b3f34f5..e79c132519d 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 = 8 -PATCH_VERSION: Final = "3" +PATCH_VERSION: Final = "4" __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/homeassistant/generated/bluetooth.py b/homeassistant/generated/bluetooth.py index 15a822599c6..4f46ded6936 100644 --- a/homeassistant/generated/bluetooth.py +++ b/homeassistant/generated/bluetooth.py @@ -46,6 +46,11 @@ BLUETOOTH: list[dict[str, str | int | list[int]]] = [ "manufacturer_id": 818, "service_uuid": "00008551-0000-1000-8000-00805f9b34fb" }, + { + "domain": "govee_ble", + "manufacturer_id": 59970, + "service_uuid": "00008151-0000-1000-8000-00805f9b34fb" + }, { "domain": "govee_ble", "manufacturer_id": 14474, diff --git a/pyproject.toml b/pyproject.toml index 61f6b20af07..6c6b88feb4a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "homeassistant" -version = "2022.8.3" +version = "2022.8.4" license = {text = "Apache-2.0"} description = "Open-source home automation platform running on Python 3." readme = "README.rst" diff --git a/requirements_all.txt b/requirements_all.txt index c5254b61842..96be4dae1b1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -168,7 +168,7 @@ aioguardian==2022.07.0 aioharmony==0.2.9 # homeassistant.components.homekit_controller -aiohomekit==1.2.8 +aiohomekit==1.2.9 # homeassistant.components.emulated_hue # homeassistant.components.http @@ -396,7 +396,7 @@ beautifulsoup4==4.11.1 # beewi_smartclim==0.0.10 # homeassistant.components.zha -bellows==0.31.3 +bellows==0.32.0 # homeassistant.components.bmw_connected_drive bimmer_connected==0.10.1 @@ -760,7 +760,7 @@ googlemaps==2.5.1 goslide-api==0.5.1 # homeassistant.components.govee_ble -govee-ble==0.14.0 +govee-ble==0.14.1 # homeassistant.components.remote_rpi_gpio gpiozero==1.6.2 @@ -2535,7 +2535,7 @@ zigpy-zigate==0.9.1 zigpy-znp==0.8.1 # homeassistant.components.zha -zigpy==0.49.0 +zigpy==0.49.1 # homeassistant.components.zoneminder zm-py==0.5.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index c64f4506850..59b922c4ef1 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -152,7 +152,7 @@ aioguardian==2022.07.0 aioharmony==0.2.9 # homeassistant.components.homekit_controller -aiohomekit==1.2.8 +aiohomekit==1.2.9 # homeassistant.components.emulated_hue # homeassistant.components.http @@ -320,7 +320,7 @@ base36==0.1.1 beautifulsoup4==4.11.1 # homeassistant.components.zha -bellows==0.31.3 +bellows==0.32.0 # homeassistant.components.bmw_connected_drive bimmer_connected==0.10.1 @@ -561,7 +561,7 @@ google-nest-sdm==2.0.0 googlemaps==2.5.1 # homeassistant.components.govee_ble -govee-ble==0.14.0 +govee-ble==0.14.1 # homeassistant.components.gree greeclimate==1.3.0 @@ -1709,7 +1709,7 @@ zigpy-zigate==0.9.1 zigpy-znp==0.8.1 # homeassistant.components.zha -zigpy==0.49.0 +zigpy==0.49.1 # homeassistant.components.zwave_js zwave-js-server-python==0.39.0 diff --git a/tests/components/govee_ble/test_config_flow.py b/tests/components/govee_ble/test_config_flow.py index a1b9fed3cd7..188672cdf18 100644 --- a/tests/components/govee_ble/test_config_flow.py +++ b/tests/components/govee_ble/test_config_flow.py @@ -78,6 +78,36 @@ async def test_async_step_user_with_found_devices(hass): assert result2["result"].unique_id == "4125DDBA-2774-4851-9889-6AADDD4CAC3D" +async def test_async_step_user_device_added_between_steps(hass): + """Test the device gets added via another flow between steps.""" + with patch( + "homeassistant.components.govee_ble.config_flow.async_discovered_service_info", + return_value=[GVH5177_SERVICE_INFO], + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": config_entries.SOURCE_USER}, + ) + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "user" + + entry = MockConfigEntry( + domain=DOMAIN, + unique_id="4125DDBA-2774-4851-9889-6AADDD4CAC3D", + ) + entry.add_to_hass(hass) + + with patch( + "homeassistant.components.govee_ble.async_setup_entry", return_value=True + ): + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={"address": "4125DDBA-2774-4851-9889-6AADDD4CAC3D"}, + ) + assert result2["type"] == FlowResultType.ABORT + assert result2["reason"] == "already_configured" + + async def test_async_step_user_with_found_devices_already_setup(hass): """Test setup from service info cache with devices found.""" entry = MockConfigEntry( diff --git a/tests/components/huawei_lte/test_switches.py b/tests/components/huawei_lte/test_switches.py index 5bafed27e70..4b0b81a86cd 100644 --- a/tests/components/huawei_lte/test_switches.py +++ b/tests/components/huawei_lte/test_switches.py @@ -2,7 +2,6 @@ from unittest.mock import MagicMock, patch from huawei_lte_api.enums.cradle import ConnectionStatusEnum -from pytest import fixture from homeassistant.components.huawei_lte.const import DOMAIN from homeassistant.components.switch import ( @@ -20,94 +19,70 @@ from tests.common import MockConfigEntry SWITCH_WIFI_GUEST_NETWORK = "switch.lte_wifi_guest_network" -@fixture +def magic_client(multi_basic_settings_value: dict) -> MagicMock: + """Mock huawei_lte.Client.""" + information = MagicMock(return_value={"SerialNumber": "test-serial-number"}) + check_notifications = MagicMock(return_value={"SmsStorageFull": 0}) + status = MagicMock( + return_value={"ConnectionStatus": ConnectionStatusEnum.CONNECTED.value} + ) + multi_basic_settings = MagicMock(return_value=multi_basic_settings_value) + wifi_feature_switch = MagicMock(return_value={"wifi24g_switch_enable": 1}) + device = MagicMock(information=information) + monitoring = MagicMock(check_notifications=check_notifications, status=status) + wlan = MagicMock( + multi_basic_settings=multi_basic_settings, + wifi_feature_switch=wifi_feature_switch, + ) + return MagicMock(device=device, monitoring=monitoring, wlan=wlan) + + @patch("homeassistant.components.huawei_lte.Connection", MagicMock()) -@patch( - "homeassistant.components.huawei_lte.Client", - return_value=MagicMock( - device=MagicMock( - information=MagicMock(return_value={"SerialNumber": "test-serial-number"}) - ), - monitoring=MagicMock( - check_notifications=MagicMock(return_value={"SmsStorageFull": 0}), - status=MagicMock( - return_value={"ConnectionStatus": ConnectionStatusEnum.CONNECTED.value} - ), - ), - wlan=MagicMock( - multi_basic_settings=MagicMock( - return_value={ - "Ssids": {"Ssid": [{"wifiisguestnetwork": "1", "WifiEnable": "0"}]} - } - ), - wifi_feature_switch=MagicMock(return_value={"wifi24g_switch_enable": 1}), - ), - ), -) -async def setup_component_with_wifi_guest_network( - client: MagicMock, hass: HomeAssistant -) -> None: - """Initialize huawei_lte components.""" - assert client - huawei_lte = MockConfigEntry(domain=DOMAIN, data={CONF_URL: "http://huawei-lte"}) - huawei_lte.add_to_hass(hass) - assert await hass.config_entries.async_setup(huawei_lte.entry_id) - await hass.async_block_till_done() - - -@fixture -@patch("homeassistant.components.huawei_lte.Connection", MagicMock()) -@patch( - "homeassistant.components.huawei_lte.Client", - return_value=MagicMock( - device=MagicMock( - information=MagicMock(return_value={"SerialNumber": "test-serial-number"}) - ), - monitoring=MagicMock( - check_notifications=MagicMock(return_value={"SmsStorageFull": 0}), - status=MagicMock( - return_value={"ConnectionStatus": ConnectionStatusEnum.CONNECTED.value} - ), - ), - wlan=MagicMock( - multi_basic_settings=MagicMock(return_value={}), - wifi_feature_switch=MagicMock(return_value={"wifi24g_switch_enable": 1}), - ), - ), -) -async def setup_component_without_wifi_guest_network( - client: MagicMock, hass: HomeAssistant -) -> None: - """Initialize huawei_lte components.""" - assert client - huawei_lte = MockConfigEntry(domain=DOMAIN, data={CONF_URL: "http://huawei-lte"}) - huawei_lte.add_to_hass(hass) - assert await hass.config_entries.async_setup(huawei_lte.entry_id) - await hass.async_block_till_done() - - -def test_huawei_lte_wifi_guest_network_config_entry_when_network_is_not_present( +@patch("homeassistant.components.huawei_lte.Client", return_value=magic_client({})) +async def test_huawei_lte_wifi_guest_network_config_entry_when_network_is_not_present( + client, hass: HomeAssistant, - setup_component_without_wifi_guest_network, ) -> None: """Test switch wifi guest network config entry when network is not present.""" + huawei_lte = MockConfigEntry(domain=DOMAIN, data={CONF_URL: "http://huawei-lte"}) + huawei_lte.add_to_hass(hass) + await hass.config_entries.async_setup(huawei_lte.entry_id) + await hass.async_block_till_done() entity_registry: EntityRegistry = er.async_get(hass) assert not entity_registry.async_is_registered(SWITCH_WIFI_GUEST_NETWORK) -def test_huawei_lte_wifi_guest_network_config_entry_when_network_is_present( +@patch("homeassistant.components.huawei_lte.Connection", MagicMock()) +@patch( + "homeassistant.components.huawei_lte.Client", + return_value=magic_client( + {"Ssids": {"Ssid": [{"wifiisguestnetwork": "1", "WifiEnable": "0"}]}} + ), +) +async def test_huawei_lte_wifi_guest_network_config_entry_when_network_is_present( + client, hass: HomeAssistant, - setup_component_with_wifi_guest_network, ) -> None: """Test switch wifi guest network config entry when network is present.""" + huawei_lte = MockConfigEntry(domain=DOMAIN, data={CONF_URL: "http://huawei-lte"}) + huawei_lte.add_to_hass(hass) + await hass.config_entries.async_setup(huawei_lte.entry_id) + await hass.async_block_till_done() entity_registry: EntityRegistry = er.async_get(hass) assert entity_registry.async_is_registered(SWITCH_WIFI_GUEST_NETWORK) -async def test_turn_on_switch_wifi_guest_network( - hass: HomeAssistant, setup_component_with_wifi_guest_network -) -> None: +@patch("homeassistant.components.huawei_lte.Connection", MagicMock()) +@patch("homeassistant.components.huawei_lte.Client") +async def test_turn_on_switch_wifi_guest_network(client, hass: HomeAssistant) -> None: """Test switch wifi guest network turn on method.""" + client.return_value = magic_client( + {"Ssids": {"Ssid": [{"wifiisguestnetwork": "1", "WifiEnable": "0"}]}} + ) + huawei_lte = MockConfigEntry(domain=DOMAIN, data={CONF_URL: "http://huawei-lte"}) + huawei_lte.add_to_hass(hass) + await hass.config_entries.async_setup(huawei_lte.entry_id) + await hass.async_block_till_done() await hass.services.async_call( SWITCH_DOMAIN, SERVICE_TURN_ON, @@ -116,15 +91,20 @@ async def test_turn_on_switch_wifi_guest_network( ) await hass.async_block_till_done() assert hass.states.is_state(SWITCH_WIFI_GUEST_NETWORK, STATE_ON) - hass.data[DOMAIN].routers[ - "test-serial-number" - ].client.wlan.wifi_guest_network_switch.assert_called_once_with(True) + client.return_value.wlan.wifi_guest_network_switch.assert_called_once_with(True) -async def test_turn_off_switch_wifi_guest_network( - hass: HomeAssistant, setup_component_with_wifi_guest_network -) -> None: +@patch("homeassistant.components.huawei_lte.Connection", MagicMock()) +@patch("homeassistant.components.huawei_lte.Client") +async def test_turn_off_switch_wifi_guest_network(client, hass: HomeAssistant) -> None: """Test switch wifi guest network turn off method.""" + client.return_value = magic_client( + {"Ssids": {"Ssid": [{"wifiisguestnetwork": "1", "WifiEnable": "1"}]}} + ) + huawei_lte = MockConfigEntry(domain=DOMAIN, data={CONF_URL: "http://huawei-lte"}) + huawei_lte.add_to_hass(hass) + await hass.config_entries.async_setup(huawei_lte.entry_id) + await hass.async_block_till_done() await hass.services.async_call( SWITCH_DOMAIN, SERVICE_TURN_OFF, @@ -133,6 +113,44 @@ async def test_turn_off_switch_wifi_guest_network( ) await hass.async_block_till_done() assert hass.states.is_state(SWITCH_WIFI_GUEST_NETWORK, STATE_OFF) - hass.data[DOMAIN].routers[ - "test-serial-number" - ].client.wlan.wifi_guest_network_switch.assert_called_with(False) + client.return_value.wlan.wifi_guest_network_switch.assert_called_with(False) + + +@patch("homeassistant.components.huawei_lte.Connection", MagicMock()) +@patch( + "homeassistant.components.huawei_lte.Client", + return_value=magic_client({"Ssids": {"Ssid": "str"}}), +) +async def test_huawei_lte_wifi_guest_network_config_entry_when_ssid_is_str( + client, hass: HomeAssistant +): + """Test switch wifi guest network config entry when ssid is a str. + + Issue #76244. Huawai models: H312-371, E5372 and E8372. + """ + huawei_lte = MockConfigEntry(domain=DOMAIN, data={CONF_URL: "http://huawei-lte"}) + huawei_lte.add_to_hass(hass) + await hass.config_entries.async_setup(huawei_lte.entry_id) + await hass.async_block_till_done() + entity_registry: EntityRegistry = er.async_get(hass) + assert not entity_registry.async_is_registered(SWITCH_WIFI_GUEST_NETWORK) + + +@patch("homeassistant.components.huawei_lte.Connection", MagicMock()) +@patch( + "homeassistant.components.huawei_lte.Client", + return_value=magic_client({"Ssids": {"Ssid": None}}), +) +async def test_huawei_lte_wifi_guest_network_config_entry_when_ssid_is_none( + client, hass: HomeAssistant +): + """Test switch wifi guest network config entry when ssid is a None. + + Issue #76244. + """ + huawei_lte = MockConfigEntry(domain=DOMAIN, data={CONF_URL: "http://huawei-lte"}) + huawei_lte.add_to_hass(hass) + await hass.config_entries.async_setup(huawei_lte.entry_id) + await hass.async_block_till_done() + entity_registry: EntityRegistry = er.async_get(hass) + assert not entity_registry.async_is_registered(SWITCH_WIFI_GUEST_NETWORK) diff --git a/tests/components/inkbird/test_config_flow.py b/tests/components/inkbird/test_config_flow.py index c1f8b3ef545..fe210f75f4b 100644 --- a/tests/components/inkbird/test_config_flow.py +++ b/tests/components/inkbird/test_config_flow.py @@ -74,6 +74,34 @@ async def test_async_step_user_with_found_devices(hass): assert result2["result"].unique_id == "61DE521B-F0BF-9F44-64D4-75BBE1738105" +async def test_async_step_user_device_added_between_steps(hass): + """Test the device gets added via another flow between steps.""" + with patch( + "homeassistant.components.inkbird.config_flow.async_discovered_service_info", + return_value=[SPS_SERVICE_INFO], + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": config_entries.SOURCE_USER}, + ) + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "user" + + entry = MockConfigEntry( + domain=DOMAIN, + unique_id="61DE521B-F0BF-9F44-64D4-75BBE1738105", + ) + entry.add_to_hass(hass) + + with patch("homeassistant.components.inkbird.async_setup_entry", return_value=True): + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={"address": "61DE521B-F0BF-9F44-64D4-75BBE1738105"}, + ) + assert result2["type"] == FlowResultType.ABORT + assert result2["reason"] == "already_configured" + + async def test_async_step_user_with_found_devices_already_setup(hass): """Test setup from service info cache with devices found.""" entry = MockConfigEntry( diff --git a/tests/components/moat/test_config_flow.py b/tests/components/moat/test_config_flow.py index 7ceeb2ad73f..6e92be703a2 100644 --- a/tests/components/moat/test_config_flow.py +++ b/tests/components/moat/test_config_flow.py @@ -74,6 +74,34 @@ async def test_async_step_user_with_found_devices(hass): assert result2["result"].unique_id == "aa:bb:cc:dd:ee:ff" +async def test_async_step_user_device_added_between_steps(hass): + """Test the device gets added via another flow between steps.""" + with patch( + "homeassistant.components.moat.config_flow.async_discovered_service_info", + return_value=[MOAT_S2_SERVICE_INFO], + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": config_entries.SOURCE_USER}, + ) + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "user" + + entry = MockConfigEntry( + domain=DOMAIN, + unique_id="aa:bb:cc:dd:ee:ff", + ) + entry.add_to_hass(hass) + + with patch("homeassistant.components.moat.async_setup_entry", return_value=True): + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={"address": "aa:bb:cc:dd:ee:ff"}, + ) + assert result2["type"] == FlowResultType.ABORT + assert result2["reason"] == "already_configured" + + async def test_async_step_user_with_found_devices_already_setup(hass): """Test setup from service info cache with devices found.""" entry = MockConfigEntry( diff --git a/tests/components/sensorpush/test_config_flow.py b/tests/components/sensorpush/test_config_flow.py index 1c825640603..244787eecb9 100644 --- a/tests/components/sensorpush/test_config_flow.py +++ b/tests/components/sensorpush/test_config_flow.py @@ -78,6 +78,36 @@ async def test_async_step_user_with_found_devices(hass): assert result2["result"].unique_id == "61DE521B-F0BF-9F44-64D4-75BBE1738105" +async def test_async_step_user_device_added_between_steps(hass): + """Test the device gets added via another flow between steps.""" + with patch( + "homeassistant.components.sensorpush.config_flow.async_discovered_service_info", + return_value=[HTW_SERVICE_INFO], + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": config_entries.SOURCE_USER}, + ) + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "user" + + entry = MockConfigEntry( + domain=DOMAIN, + unique_id="61DE521B-F0BF-9F44-64D4-75BBE1738105", + ) + entry.add_to_hass(hass) + + with patch( + "homeassistant.components.sensorpush.async_setup_entry", return_value=True + ): + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={"address": "61DE521B-F0BF-9F44-64D4-75BBE1738105"}, + ) + assert result2["type"] == FlowResultType.ABORT + assert result2["reason"] == "already_configured" + + async def test_async_step_user_with_found_devices_already_setup(hass): """Test setup from service info cache with devices found.""" entry = MockConfigEntry( diff --git a/tests/components/xiaomi_ble/test_config_flow.py b/tests/components/xiaomi_ble/test_config_flow.py index 32ba6be3322..2da3ce7140d 100644 --- a/tests/components/xiaomi_ble/test_config_flow.py +++ b/tests/components/xiaomi_ble/test_config_flow.py @@ -708,6 +708,36 @@ async def test_async_step_user_with_found_devices_legacy_encryption_wrong_key_le assert result2["result"].unique_id == "F8:24:41:C5:98:8B" +async def test_async_step_user_device_added_between_steps(hass): + """Test the device gets added via another flow between steps.""" + with patch( + "homeassistant.components.xiaomi_ble.config_flow.async_discovered_service_info", + return_value=[LYWSDCGQ_SERVICE_INFO], + ): + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={"source": config_entries.SOURCE_USER}, + ) + assert result["type"] == FlowResultType.FORM + assert result["step_id"] == "user" + + entry = MockConfigEntry( + domain=DOMAIN, + unique_id="58:2D:34:35:93:21", + ) + entry.add_to_hass(hass) + + with patch( + "homeassistant.components.xiaomi_ble.async_setup_entry", return_value=True + ): + result2 = await hass.config_entries.flow.async_configure( + result["flow_id"], + user_input={"address": "58:2D:34:35:93:21"}, + ) + assert result2["type"] == FlowResultType.ABORT + assert result2["reason"] == "already_configured" + + async def test_async_step_user_with_found_devices_already_setup(hass): """Test setup from service info cache with devices found.""" entry = MockConfigEntry(