diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 19cc8bd3af7..c5491df0021 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -37,7 +37,7 @@ on: type: boolean env: - CACHE_VERSION: 3 + CACHE_VERSION: 4 UV_CACHE_VERSION: 1 MYPY_CACHE_VERSION: 1 HA_SHORT_VERSION: "2025.7" diff --git a/homeassistant/components/alexa_devices/manifest.json b/homeassistant/components/alexa_devices/manifest.json index 7c23edd92ce..70281390436 100644 --- a/homeassistant/components/alexa_devices/manifest.json +++ b/homeassistant/components/alexa_devices/manifest.json @@ -8,5 +8,5 @@ "iot_class": "cloud_polling", "loggers": ["aioamazondevices"], "quality_scale": "bronze", - "requirements": ["aioamazondevices==3.2.2"] + "requirements": ["aioamazondevices==3.2.3"] } diff --git a/homeassistant/components/cloud/manifest.json b/homeassistant/components/cloud/manifest.json index 70cf6a2c072..0d44d57ac5e 100644 --- a/homeassistant/components/cloud/manifest.json +++ b/homeassistant/components/cloud/manifest.json @@ -13,6 +13,6 @@ "integration_type": "system", "iot_class": "cloud_push", "loggers": ["acme", "hass_nabucasa", "snitun"], - "requirements": ["hass-nabucasa==0.104.0"], + "requirements": ["hass-nabucasa==0.105.0"], "single_config_entry": true } diff --git a/homeassistant/components/enphase_envoy/__init__.py b/homeassistant/components/enphase_envoy/__init__.py index eee6cb85e6d..f43d89aa098 100644 --- a/homeassistant/components/enphase_envoy/__init__.py +++ b/homeassistant/components/enphase_envoy/__init__.py @@ -63,6 +63,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: EnphaseConfigEntry) -> coordinator = entry.runtime_data coordinator.async_cancel_token_refresh() coordinator.async_cancel_firmware_refresh() + coordinator.async_cancel_mac_verification() return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) diff --git a/homeassistant/components/enphase_envoy/manifest.json b/homeassistant/components/enphase_envoy/manifest.json index 5f74da954a0..8387ecc9c9f 100644 --- a/homeassistant/components/enphase_envoy/manifest.json +++ b/homeassistant/components/enphase_envoy/manifest.json @@ -7,7 +7,7 @@ "iot_class": "local_polling", "loggers": ["pyenphase"], "quality_scale": "platinum", - "requirements": ["pyenphase==2.1.0"], + "requirements": ["pyenphase==2.2.0"], "zeroconf": [ { "type": "_enphase-envoy._tcp.local." diff --git a/homeassistant/components/frontend/manifest.json b/homeassistant/components/frontend/manifest.json index bfd868a5334..748d8f0c6f0 100644 --- a/homeassistant/components/frontend/manifest.json +++ b/homeassistant/components/frontend/manifest.json @@ -20,5 +20,5 @@ "documentation": "https://www.home-assistant.io/integrations/frontend", "integration_type": "system", "quality_scale": "internal", - "requirements": ["home-assistant-frontend==20250702.0"] + "requirements": ["home-assistant-frontend==20250702.1"] } diff --git a/homeassistant/components/http/ban.py b/homeassistant/components/http/ban.py index 71f3d54bef6..7e55191639b 100644 --- a/homeassistant/components/http/ban.py +++ b/homeassistant/components/http/ban.py @@ -64,7 +64,7 @@ def setup_bans(hass: HomeAssistant, app: Application, login_threshold: int) -> N """Initialize bans when app starts up.""" await app[KEY_BAN_MANAGER].async_load() - app.on_startup.append(ban_startup) + app.on_startup.append(ban_startup) # type: ignore[arg-type] @middleware diff --git a/homeassistant/components/music_assistant/manifest.json b/homeassistant/components/music_assistant/manifest.json index e29491e2b21..4b28a1029a4 100644 --- a/homeassistant/components/music_assistant/manifest.json +++ b/homeassistant/components/music_assistant/manifest.json @@ -7,6 +7,6 @@ "documentation": "https://www.home-assistant.io/integrations/music_assistant", "iot_class": "local_push", "loggers": ["music_assistant"], - "requirements": ["music-assistant-client==1.2.3"], + "requirements": ["music-assistant-client==1.2.4"], "zeroconf": ["_mass._tcp.local."] } diff --git a/homeassistant/components/music_assistant/media_player.py b/homeassistant/components/music_assistant/media_player.py index b748aad241c..3a210856391 100644 --- a/homeassistant/components/music_assistant/media_player.py +++ b/homeassistant/components/music_assistant/media_player.py @@ -248,8 +248,6 @@ class MusicAssistantPlayer(MusicAssistantEntity, MediaPlayerEntity): player = self.player active_queue = self.active_queue # update generic attributes - if player.powered and active_queue is not None: - self._attr_state = MediaPlayerState(active_queue.state.value) if player.powered and player.playback_state is not None: self._attr_state = MediaPlayerState(player.playback_state.value) else: diff --git a/homeassistant/components/remote_calendar/client.py b/homeassistant/components/remote_calendar/client.py new file mode 100644 index 00000000000..f0f243ca386 --- /dev/null +++ b/homeassistant/components/remote_calendar/client.py @@ -0,0 +1,12 @@ +"""Specifies the parameter for the httpx download.""" + +from httpx import AsyncClient, Response, Timeout + + +async def get_calendar(client: AsyncClient, url: str) -> Response: + """Make an HTTP GET request using Home Assistant's async HTTPX client with timeout.""" + return await client.get( + url, + follow_redirects=True, + timeout=Timeout(5, read=30, write=5, pool=5), + ) diff --git a/homeassistant/components/remote_calendar/config_flow.py b/homeassistant/components/remote_calendar/config_flow.py index 558a3d668ae..3f835b5d82b 100644 --- a/homeassistant/components/remote_calendar/config_flow.py +++ b/homeassistant/components/remote_calendar/config_flow.py @@ -4,13 +4,14 @@ from http import HTTPStatus import logging from typing import Any -from httpx import HTTPError, InvalidURL +from httpx import HTTPError, InvalidURL, TimeoutException import voluptuous as vol from homeassistant.config_entries import ConfigFlow, ConfigFlowResult from homeassistant.const import CONF_URL from homeassistant.helpers.httpx_client import get_async_client +from .client import get_calendar from .const import CONF_CALENDAR_NAME, DOMAIN from .ics import InvalidIcsException, parse_calendar @@ -49,7 +50,7 @@ class RemoteCalendarConfigFlow(ConfigFlow, domain=DOMAIN): self._async_abort_entries_match({CONF_URL: user_input[CONF_URL]}) client = get_async_client(self.hass) try: - res = await client.get(user_input[CONF_URL], follow_redirects=True) + res = await get_calendar(client, user_input[CONF_URL]) if res.status_code == HTTPStatus.FORBIDDEN: errors["base"] = "forbidden" return self.async_show_form( @@ -58,9 +59,14 @@ class RemoteCalendarConfigFlow(ConfigFlow, domain=DOMAIN): errors=errors, ) res.raise_for_status() + except TimeoutException as err: + errors["base"] = "timeout_connect" + _LOGGER.debug( + "A timeout error occurred: %s", str(err) or type(err).__name__ + ) except (HTTPError, InvalidURL) as err: errors["base"] = "cannot_connect" - _LOGGER.debug("An error occurred: %s", err) + _LOGGER.debug("An error occurred: %s", str(err) or type(err).__name__) else: try: await parse_calendar(self.hass, res.text) diff --git a/homeassistant/components/remote_calendar/coordinator.py b/homeassistant/components/remote_calendar/coordinator.py index 1eead7682d3..26876b53224 100644 --- a/homeassistant/components/remote_calendar/coordinator.py +++ b/homeassistant/components/remote_calendar/coordinator.py @@ -3,7 +3,7 @@ from datetime import timedelta import logging -from httpx import HTTPError, InvalidURL +from httpx import HTTPError, InvalidURL, TimeoutException from ical.calendar import Calendar from homeassistant.config_entries import ConfigEntry @@ -12,6 +12,7 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers.httpx_client import get_async_client from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed +from .client import get_calendar from .const import DOMAIN from .ics import InvalidIcsException, parse_calendar @@ -36,7 +37,7 @@ class RemoteCalendarDataUpdateCoordinator(DataUpdateCoordinator[Calendar]): super().__init__( hass, _LOGGER, - name=DOMAIN, + name=f"{DOMAIN}_{config_entry.title}", update_interval=SCAN_INTERVAL, always_update=True, ) @@ -46,13 +47,19 @@ class RemoteCalendarDataUpdateCoordinator(DataUpdateCoordinator[Calendar]): async def _async_update_data(self) -> Calendar: """Update data from the url.""" try: - res = await self._client.get(self._url, follow_redirects=True) + res = await get_calendar(self._client, self._url) res.raise_for_status() + except TimeoutException as err: + _LOGGER.debug("%s: %s", self._url, str(err) or type(err).__name__) + raise UpdateFailed( + translation_domain=DOMAIN, + translation_key="timeout", + ) from err except (HTTPError, InvalidURL) as err: + _LOGGER.debug("%s: %s", self._url, str(err) or type(err).__name__) raise UpdateFailed( translation_domain=DOMAIN, translation_key="unable_to_fetch", - translation_placeholders={"err": str(err)}, ) from err try: self.ics = res.text diff --git a/homeassistant/components/remote_calendar/strings.json b/homeassistant/components/remote_calendar/strings.json index ef7f20d4699..48ef6080bdb 100644 --- a/homeassistant/components/remote_calendar/strings.json +++ b/homeassistant/components/remote_calendar/strings.json @@ -18,14 +18,18 @@ "already_configured": "[%key:common::config_flow::abort::already_configured_service%]" }, "error": { + "timeout_connect": "[%key:common::config_flow::error::timeout_connect%]", "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "forbidden": "The server understood the request but refuses to authorize it.", "invalid_ics_file": "There was a problem reading the calendar information. See the error log for additional details." } }, "exceptions": { + "timeout": { + "message": "The connection timed out. See the debug log for additional details." + }, "unable_to_fetch": { - "message": "Unable to fetch calendar data: {err}" + "message": "Unable to fetch calendar data. See the debug log for additional details." }, "unable_to_parse": { "message": "Unable to parse calendar data: {err}" diff --git a/homeassistant/components/samsungtv/config_flow.py b/homeassistant/components/samsungtv/config_flow.py index dbde1ee1ef3..e2b9f8631d8 100644 --- a/homeassistant/components/samsungtv/config_flow.py +++ b/homeassistant/components/samsungtv/config_flow.py @@ -124,6 +124,7 @@ class SamsungTVConfigFlow(ConfigFlow, domain=DOMAIN): self._model: str | None = None self._connect_result: str | None = None self._method: str | None = None + self._port: int | None = None self._name: str | None = None self._title: str = "" self._id: int | None = None @@ -199,33 +200,37 @@ class SamsungTVConfigFlow(ConfigFlow, domain=DOMAIN): async def _async_create_bridge(self) -> None: """Create the bridge.""" - result, method, _info = await self._async_get_device_info_and_method() + result = await self._async_load_device_info() if result not in SUCCESSFUL_RESULTS: LOGGER.debug("No working config found for %s", self._host) raise AbortFlow(result) - assert method is not None - self._bridge = SamsungTVBridge.get_bridge(self.hass, method, self._host) + assert self._method is not None + self._bridge = SamsungTVBridge.get_bridge( + self.hass, self._method, self._host, self._port + ) - async def _async_get_device_info_and_method( + async def _async_load_device_info( self, - ) -> tuple[str, str | None, dict[str, Any] | None]: + ) -> str: """Get device info and method only once.""" if self._connect_result is None: - result, _, method, info = await async_get_device_info(self.hass, self._host) + result, port, method, info = await async_get_device_info( + self.hass, self._host + ) self._connect_result = result self._method = method + self._port = port self._device_info = info if not method: LOGGER.debug("Host:%s did not return device info", self._host) - return result, None, None - return self._connect_result, self._method, self._device_info + return self._connect_result async def _async_get_and_check_device_info(self) -> bool: """Try to get the device info.""" - result, _method, info = await self._async_get_device_info_and_method() + result = await self._async_load_device_info() if result not in SUCCESSFUL_RESULTS: raise AbortFlow(result) - if not info: + if not (info := self._device_info): return False dev_info = info.get("device", {}) assert dev_info is not None diff --git a/homeassistant/components/telegram_bot/bot.py b/homeassistant/components/telegram_bot/bot.py index a3feb120460..c57648c9551 100644 --- a/homeassistant/components/telegram_bot/bot.py +++ b/homeassistant/components/telegram_bot/bot.py @@ -374,9 +374,7 @@ class TelegramNotificationService: } if data is not None: if ATTR_PARSER in data: - params[ATTR_PARSER] = self._parsers.get( - data[ATTR_PARSER], self.parse_mode - ) + params[ATTR_PARSER] = data[ATTR_PARSER] if ATTR_TIMEOUT in data: params[ATTR_TIMEOUT] = data[ATTR_TIMEOUT] if ATTR_DISABLE_NOTIF in data: @@ -408,6 +406,8 @@ class TelegramNotificationService: params[ATTR_REPLYMARKUP] = InlineKeyboardMarkup( [_make_row_inline_keyboard(row) for row in keys] ) + if params[ATTR_PARSER] == PARSER_PLAIN_TEXT: + params[ATTR_PARSER] = None return params async def _send_msg( diff --git a/homeassistant/components/telegram_bot/config_flow.py b/homeassistant/components/telegram_bot/config_flow.py index 41f26ccd48d..8d3d9b0cd7b 100644 --- a/homeassistant/components/telegram_bot/config_flow.py +++ b/homeassistant/components/telegram_bot/config_flow.py @@ -159,8 +159,6 @@ class OptionsFlowHandler(OptionsFlow): """Manage the options.""" if user_input is not None: - if user_input[ATTR_PARSER] == PARSER_PLAIN_TEXT: - user_input[ATTR_PARSER] = None return self.async_create_entry(data=user_input) return self.async_show_form( diff --git a/homeassistant/components/telegram_bot/services.yaml b/homeassistant/components/telegram_bot/services.yaml index d5fc0e134d5..b1d94d381ac 100644 --- a/homeassistant/components/telegram_bot/services.yaml +++ b/homeassistant/components/telegram_bot/services.yaml @@ -109,6 +109,7 @@ send_photo: - "markdown" - "markdownv2" - "plain_text" + translation_key: "parse_mode" disable_notification: selector: boolean: @@ -261,6 +262,7 @@ send_animation: - "markdown" - "markdownv2" - "plain_text" + translation_key: "parse_mode" disable_notification: selector: boolean: @@ -341,6 +343,7 @@ send_video: - "markdown" - "markdownv2" - "plain_text" + translation_key: "parse_mode" disable_notification: selector: boolean: @@ -493,6 +496,7 @@ send_document: - "markdown" - "markdownv2" - "plain_text" + translation_key: "parse_mode" disable_notification: selector: boolean: @@ -670,6 +674,7 @@ edit_message: - "markdown" - "markdownv2" - "plain_text" + translation_key: "parse_mode" disable_web_page_preview: selector: boolean: diff --git a/homeassistant/components/unifi/manifest.json b/homeassistant/components/unifi/manifest.json index dd255c57c13..d13b180d62d 100644 --- a/homeassistant/components/unifi/manifest.json +++ b/homeassistant/components/unifi/manifest.json @@ -7,7 +7,7 @@ "integration_type": "hub", "iot_class": "local_push", "loggers": ["aiounifi"], - "requirements": ["aiounifi==83"], + "requirements": ["aiounifi==84"], "ssdp": [ { "manufacturer": "Ubiquiti Networks", diff --git a/homeassistant/components/venstar/manifest.json b/homeassistant/components/venstar/manifest.json index f3045fe49e8..5991dc8fe51 100644 --- a/homeassistant/components/venstar/manifest.json +++ b/homeassistant/components/venstar/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/venstar", "iot_class": "local_polling", "loggers": ["venstarcolortouch"], - "requirements": ["venstarcolortouch==0.19"] + "requirements": ["venstarcolortouch==0.21"] } diff --git a/homeassistant/components/zha/manifest.json b/homeassistant/components/zha/manifest.json index 4fb5f57320f..2cbc962a305 100644 --- a/homeassistant/components/zha/manifest.json +++ b/homeassistant/components/zha/manifest.json @@ -21,7 +21,7 @@ "zha", "universal_silabs_flasher" ], - "requirements": ["zha==0.0.61"], + "requirements": ["zha==0.0.62"], "usb": [ { "vid": "10C4", diff --git a/homeassistant/const.py b/homeassistant/const.py index f1a9f7f79c2..258a9c9a48f 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -25,7 +25,7 @@ if TYPE_CHECKING: APPLICATION_NAME: Final = "HomeAssistant" MAJOR_VERSION: Final = 2025 MINOR_VERSION: Final = 7 -PATCH_VERSION: Final = "0" +PATCH_VERSION: Final = "1" __short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__: Final = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 13, 2) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index f0fa428fbb3..824c3d945fe 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -35,10 +35,10 @@ fnv-hash-fast==1.5.0 go2rtc-client==0.2.1 ha-ffmpeg==3.2.2 habluetooth==3.49.0 -hass-nabucasa==0.104.0 +hass-nabucasa==0.105.0 hassil==2.2.3 home-assistant-bluetooth==1.13.1 -home-assistant-frontend==20250702.0 +home-assistant-frontend==20250702.1 home-assistant-intents==2025.6.23 httpx==0.28.1 ifaddr==0.2.0 diff --git a/pyproject.toml b/pyproject.toml index c34a268e347..b4478a69d53 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "homeassistant" -version = "2025.7.0" +version = "2025.7.1" license = "Apache-2.0" license-files = ["LICENSE*", "homeassistant/backports/LICENSE*"] description = "Open-source home automation platform running on Python 3." @@ -47,7 +47,7 @@ dependencies = [ "fnv-hash-fast==1.5.0", # hass-nabucasa is imported by helpers which don't depend on the cloud # integration - "hass-nabucasa==0.104.0", + "hass-nabucasa==0.105.0", # When bumping httpx, please check the version pins of # httpcore, anyio, and h11 in gen_requirements_all "httpx==0.28.1", diff --git a/requirements.txt b/requirements.txt index 1791d12268b..011d76e66b5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,7 +22,7 @@ certifi>=2021.5.30 ciso8601==2.3.2 cronsim==2.6 fnv-hash-fast==1.5.0 -hass-nabucasa==0.104.0 +hass-nabucasa==0.105.0 httpx==0.28.1 home-assistant-bluetooth==1.13.1 ifaddr==0.2.0 diff --git a/requirements_all.txt b/requirements_all.txt index 04b3f0eaa2f..fcd97e305fc 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -185,7 +185,7 @@ aioairzone-cloud==0.6.12 aioairzone==1.0.0 # homeassistant.components.alexa_devices -aioamazondevices==3.2.2 +aioamazondevices==3.2.3 # homeassistant.components.ambient_network # homeassistant.components.ambient_station @@ -414,7 +414,7 @@ aiotedee==0.2.25 aiotractive==0.6.0 # homeassistant.components.unifi -aiounifi==83 +aiounifi==84 # homeassistant.components.usb aiousbwatcher==1.1.1 @@ -1127,7 +1127,7 @@ habiticalib==0.4.0 habluetooth==3.49.0 # homeassistant.components.cloud -hass-nabucasa==0.104.0 +hass-nabucasa==0.105.0 # homeassistant.components.splunk hass-splunk==0.1.1 @@ -1168,7 +1168,7 @@ hole==0.8.0 holidays==0.75 # homeassistant.components.frontend -home-assistant-frontend==20250702.0 +home-assistant-frontend==20250702.1 # homeassistant.components.conversation home-assistant-intents==2025.6.23 @@ -1467,7 +1467,7 @@ mozart-api==4.1.1.116.4 mullvad-api==1.0.0 # homeassistant.components.music_assistant -music-assistant-client==1.2.3 +music-assistant-client==1.2.4 # homeassistant.components.tts mutagen==1.47.0 @@ -1962,7 +1962,7 @@ pyeiscp==0.0.7 pyemoncms==0.1.1 # homeassistant.components.enphase_envoy -pyenphase==2.1.0 +pyenphase==2.2.0 # homeassistant.components.envisalink pyenvisalink==4.7 @@ -3041,7 +3041,7 @@ vehicle==2.2.2 velbus-aio==2025.5.0 # homeassistant.components.venstar -venstarcolortouch==0.19 +venstarcolortouch==0.21 # homeassistant.components.vilfo vilfo-api-client==0.5.0 @@ -3190,7 +3190,7 @@ zeroconf==0.147.0 zeversolar==0.3.2 # homeassistant.components.zha -zha==0.0.61 +zha==0.0.62 # homeassistant.components.zhong_hong zhong-hong-hvac==1.0.13 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index ea925412def..a234822689c 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -173,7 +173,7 @@ aioairzone-cloud==0.6.12 aioairzone==1.0.0 # homeassistant.components.alexa_devices -aioamazondevices==3.2.2 +aioamazondevices==3.2.3 # homeassistant.components.ambient_network # homeassistant.components.ambient_station @@ -396,7 +396,7 @@ aiotedee==0.2.25 aiotractive==0.6.0 # homeassistant.components.unifi -aiounifi==83 +aiounifi==84 # homeassistant.components.usb aiousbwatcher==1.1.1 @@ -988,7 +988,7 @@ habiticalib==0.4.0 habluetooth==3.49.0 # homeassistant.components.cloud -hass-nabucasa==0.104.0 +hass-nabucasa==0.105.0 # homeassistant.components.assist_satellite # homeassistant.components.conversation @@ -1017,7 +1017,7 @@ hole==0.8.0 holidays==0.75 # homeassistant.components.frontend -home-assistant-frontend==20250702.0 +home-assistant-frontend==20250702.1 # homeassistant.components.conversation home-assistant-intents==2025.6.23 @@ -1259,7 +1259,7 @@ mozart-api==4.1.1.116.4 mullvad-api==1.0.0 # homeassistant.components.music_assistant -music-assistant-client==1.2.3 +music-assistant-client==1.2.4 # homeassistant.components.tts mutagen==1.47.0 @@ -1637,7 +1637,7 @@ pyeiscp==0.0.7 pyemoncms==0.1.1 # homeassistant.components.enphase_envoy -pyenphase==2.1.0 +pyenphase==2.2.0 # homeassistant.components.everlights pyeverlights==0.1.0 @@ -2509,7 +2509,7 @@ vehicle==2.2.2 velbus-aio==2025.5.0 # homeassistant.components.venstar -venstarcolortouch==0.19 +venstarcolortouch==0.21 # homeassistant.components.vilfo vilfo-api-client==0.5.0 @@ -2634,7 +2634,7 @@ zeroconf==0.147.0 zeversolar==0.3.2 # homeassistant.components.zha -zha==0.0.61 +zha==0.0.62 # homeassistant.components.zwave_js zwave-js-server-python==0.65.0 diff --git a/tests/components/remote_calendar/test_config_flow.py b/tests/components/remote_calendar/test_config_flow.py index 9aff1594db3..9bea46ab27e 100644 --- a/tests/components/remote_calendar/test_config_flow.py +++ b/tests/components/remote_calendar/test_config_flow.py @@ -1,6 +1,6 @@ """Test the Remote Calendar config flow.""" -from httpx import ConnectError, Response, UnsupportedProtocol +from httpx import HTTPError, InvalidURL, Response, TimeoutException import pytest import respx @@ -75,10 +75,11 @@ async def test_form_import_webcal(hass: HomeAssistant, ics_content: str) -> None @pytest.mark.parametrize( - ("side_effect"), + ("side_effect", "base_error"), [ - ConnectError("Connection failed"), - UnsupportedProtocol("Unsupported protocol"), + (TimeoutException("Connection timed out"), "timeout_connect"), + (HTTPError("Connection failed"), "cannot_connect"), + (InvalidURL("Unsupported protocol"), "cannot_connect"), ], ) @respx.mock @@ -86,6 +87,7 @@ async def test_form_inavild_url( hass: HomeAssistant, side_effect: Exception, ics_content: str, + base_error: str, ) -> None: """Test we get the import form.""" result = await hass.config_entries.flow.async_init( @@ -102,7 +104,7 @@ async def test_form_inavild_url( }, ) assert result2["type"] is FlowResultType.FORM - assert result2["errors"] == {"base": "cannot_connect"} + assert result2["errors"] == {"base": base_error} respx.get(CALENDER_URL).mock( return_value=Response( status_code=200, diff --git a/tests/components/remote_calendar/test_init.py b/tests/components/remote_calendar/test_init.py index f4ca500b2e1..d3e6b439805 100644 --- a/tests/components/remote_calendar/test_init.py +++ b/tests/components/remote_calendar/test_init.py @@ -1,6 +1,6 @@ """Tests for init platform of Remote Calendar.""" -from httpx import ConnectError, Response, UnsupportedProtocol +from httpx import HTTPError, InvalidURL, Response, TimeoutException import pytest import respx @@ -56,8 +56,9 @@ async def test_raise_for_status( @pytest.mark.parametrize( "side_effect", [ - ConnectError("Connection failed"), - UnsupportedProtocol("Unsupported protocol"), + TimeoutException("Connection timed out"), + HTTPError("Connection failed"), + InvalidURL("Unsupported protocol"), ValueError("Invalid response"), ], ) diff --git a/tests/components/samsungtv/test_config_flow.py b/tests/components/samsungtv/test_config_flow.py index d63e5a7ae2a..dd6b21ab5e5 100644 --- a/tests/components/samsungtv/test_config_flow.py +++ b/tests/components/samsungtv/test_config_flow.py @@ -161,6 +161,7 @@ async def test_user_legacy(hass: HomeAssistant) -> None: assert result["data"][CONF_METHOD] == METHOD_LEGACY assert result["data"][CONF_MANUFACTURER] == DEFAULT_MANUFACTURER assert result["data"][CONF_MODEL] is None + assert result["data"][CONF_PORT] == 55000 assert result["result"].unique_id is None @@ -195,6 +196,7 @@ async def test_user_legacy_does_not_ok_first_time(hass: HomeAssistant) -> None: assert result3["data"][CONF_METHOD] == METHOD_LEGACY assert result3["data"][CONF_MANUFACTURER] == DEFAULT_MANUFACTURER assert result3["data"][CONF_MODEL] is None + assert result3["data"][CONF_PORT] == 55000 assert result3["result"].unique_id is None @@ -224,6 +226,7 @@ async def test_user_websocket(hass: HomeAssistant) -> None: assert result["data"][CONF_METHOD] == "websocket" assert result["data"][CONF_MANUFACTURER] == "Samsung" assert result["data"][CONF_MODEL] == "82GXARRS" + assert result["data"][CONF_PORT] == 8002 assert result["result"].unique_id == "be9554b9-c9fb-41f4-8920-22da015376a4" @@ -272,6 +275,7 @@ async def test_user_encrypted_websocket( assert result4["data"][CONF_MAC] == "aa:bb:aa:aa:aa:aa" assert result4["data"][CONF_MANUFACTURER] == "Samsung" assert result4["data"][CONF_MODEL] == "UE48JU6400" + assert result4["data"][CONF_PORT] == 8000 assert result4["data"][CONF_SSDP_RENDERING_CONTROL_LOCATION] is None assert result4["data"][CONF_TOKEN] == "037739871315caef138547b03e348b72" assert result4["data"][CONF_SESSION_ID] == "1" @@ -402,6 +406,7 @@ async def test_user_websocket_auth_retry(hass: HomeAssistant) -> None: assert result["data"][CONF_HOST] == "10.20.43.21" assert result["data"][CONF_MANUFACTURER] == "Samsung" assert result["data"][CONF_MODEL] == "82GXARRS" + assert result["data"][CONF_PORT] == 8002 assert result["result"].unique_id == "be9554b9-c9fb-41f4-8920-22da015376a4" @@ -464,6 +469,7 @@ async def test_ssdp(hass: HomeAssistant) -> None: assert result["data"][CONF_HOST] == "10.10.12.34" assert result["data"][CONF_MANUFACTURER] == "Samsung Electronics" assert result["data"][CONF_MODEL] == "UE55H6400" + assert result["data"][CONF_PORT] == 55000 assert result["result"].unique_id == "068e7781-006e-1000-bbbf-84a4668d8423" @@ -522,6 +528,7 @@ async def test_ssdp_noprefix(hass: HomeAssistant) -> None: assert result["data"][CONF_HOST] == "10.10.12.34" assert result["data"][CONF_MANUFACTURER] == "Samsung Electronics" assert result["data"][CONF_MODEL] == "UE55H6400" + assert result["data"][CONF_PORT] == 55000 assert result["result"].unique_id == "068e7781-006e-1000-bbbf-84a4668d8423" @@ -557,6 +564,7 @@ async def test_ssdp_legacy_missing_auth(hass: HomeAssistant) -> None: assert result["data"][CONF_HOST] == "10.10.12.34" assert result["data"][CONF_MANUFACTURER] == "Samsung Electronics" assert result["data"][CONF_MODEL] == "UE55H6400" + assert result["data"][CONF_PORT] == 55000 assert result["result"].unique_id == "068e7781-006e-1000-bbbf-84a4668d8423" @@ -599,6 +607,7 @@ async def test_ssdp_websocket_success_populates_mac_address_and_ssdp_location( assert result["data"][CONF_MAC] == "aa:bb:aa:aa:aa:aa" assert result["data"][CONF_MANUFACTURER] == "Samsung Electronics" assert result["data"][CONF_MODEL] == "82GXARRS" + assert result["data"][CONF_PORT] == 8002 assert ( result["data"][CONF_SSDP_RENDERING_CONTROL_LOCATION] == "http://10.10.12.34:7676/smp_15_" @@ -630,6 +639,7 @@ async def test_ssdp_websocket_success_populates_mac_address_and_main_tv_ssdp_loc assert result["data"][CONF_MAC] == "aa:bb:aa:aa:aa:aa" assert result["data"][CONF_MANUFACTURER] == "Samsung Electronics" assert result["data"][CONF_MODEL] == "82GXARRS" + assert result["data"][CONF_PORT] == 8002 assert ( result["data"][CONF_SSDP_MAIN_TV_AGENT_LOCATION] == "http://10.10.12.34:7676/smp_2_" @@ -681,6 +691,7 @@ async def test_ssdp_encrypted_websocket_success_populates_mac_address_and_ssdp_l assert result4["data"][CONF_MAC] == "aa:bb:aa:aa:aa:aa" assert result4["data"][CONF_MANUFACTURER] == "Samsung Electronics" assert result4["data"][CONF_MODEL] == "UE48JU6400" + assert result4["data"][CONF_PORT] == 8000 assert ( result4["data"][CONF_SSDP_RENDERING_CONTROL_LOCATION] == "http://10.10.12.34:7676/smp_15_" @@ -887,6 +898,7 @@ async def test_dhcp_wireless(hass: HomeAssistant) -> None: assert result["data"][CONF_MAC] == "aa:bb:aa:aa:aa:aa" assert result["data"][CONF_MANUFACTURER] == "Samsung" assert result["data"][CONF_MODEL] == "UE48JU6400" + assert result["data"][CONF_PORT] == 8002 assert result["result"].unique_id == "223da676-497a-4e06-9507-5e27ec4f0fb3" @@ -919,6 +931,7 @@ async def test_dhcp_wired(hass: HomeAssistant, rest_api: Mock) -> None: assert result["data"][CONF_MAC] == "aa:ee:tt:hh:ee:rr" assert result["data"][CONF_MANUFACTURER] == "Samsung" assert result["data"][CONF_MODEL] == "UE43LS003" + assert result["data"][CONF_PORT] == 8002 assert result["result"].unique_id == "be9554b9-c9fb-41f4-8920-22da015376a4" @@ -1020,6 +1033,7 @@ async def test_zeroconf(hass: HomeAssistant) -> None: assert result["data"][CONF_MAC] == "aa:bb:aa:aa:aa:aa" assert result["data"][CONF_MANUFACTURER] == "Samsung" assert result["data"][CONF_MODEL] == "82GXARRS" + assert result["data"][CONF_PORT] == 8002 assert result["result"].unique_id == "be9554b9-c9fb-41f4-8920-22da015376a4" @@ -1129,6 +1143,7 @@ async def test_autodetect_websocket(hass: HomeAssistant) -> None: assert result["type"] is FlowResultType.CREATE_ENTRY assert result["data"][CONF_METHOD] == "websocket" assert result["data"][CONF_TOKEN] == "123456789" + assert result["data"][CONF_PORT] == 8002 remote_websocket.assert_called_once_with(**AUTODETECT_WEBSOCKET_SSL) rest_api_class.assert_called_once_with(**DEVICEINFO_WEBSOCKET_SSL) await hass.async_block_till_done() @@ -1180,6 +1195,7 @@ async def test_websocket_no_mac(hass: HomeAssistant, mac_address: Mock) -> None: assert result["data"][CONF_METHOD] == "websocket" assert result["data"][CONF_TOKEN] == "123456789" assert result["data"][CONF_MAC] == "gg:ee:tt:mm:aa:cc" + assert result["data"][CONF_PORT] == 8002 remote_websocket.assert_called_once_with(**AUTODETECT_WEBSOCKET_SSL) rest_api_class.assert_called_once_with(**DEVICEINFO_WEBSOCKET_SSL) await hass.async_block_till_done() @@ -2091,6 +2107,7 @@ async def test_ssdp_update_mac(hass: HomeAssistant) -> None: assert entry.data[CONF_MANUFACTURER] == DEFAULT_MANUFACTURER assert entry.data[CONF_MODEL] == "fake_model" assert entry.data[CONF_MAC] is None + assert entry.data[CONF_PORT] == 8002 assert entry.unique_id == "123" device_info = deepcopy(MOCK_DEVICE_INFO) diff --git a/tests/components/telegram_bot/test_config_flow.py b/tests/components/telegram_bot/test_config_flow.py index 2586761b584..9a076016a32 100644 --- a/tests/components/telegram_bot/test_config_flow.py +++ b/tests/components/telegram_bot/test_config_flow.py @@ -63,7 +63,7 @@ async def test_options_flow( await hass.async_block_till_done() assert result["type"] == FlowResultType.CREATE_ENTRY - assert result["data"][ATTR_PARSER] is None + assert result["data"][ATTR_PARSER] == PARSER_PLAIN_TEXT async def test_reconfigure_flow_broadcast( diff --git a/tests/components/telegram_bot/test_telegram_bot.py b/tests/components/telegram_bot/test_telegram_bot.py index 6590bbed1cf..73dd9e27763 100644 --- a/tests/components/telegram_bot/test_telegram_bot.py +++ b/tests/components/telegram_bot/test_telegram_bot.py @@ -50,6 +50,7 @@ from homeassistant.components.telegram_bot.const import ( ATTR_VERIFY_SSL, CONF_CONFIG_ENTRY_ID, DOMAIN, + PARSER_PLAIN_TEXT, PLATFORM_BROADCAST, SECTION_ADVANCED_SETTINGS, SERVICE_ANSWER_CALLBACK_QUERY, @@ -183,6 +184,7 @@ async def test_send_message( ( { ATTR_MESSAGE: "test_message", + ATTR_PARSER: PARSER_PLAIN_TEXT, ATTR_KEYBOARD_INLINE: "command1:/cmd1,/cmd2,mock_link:https://mock_link", }, InlineKeyboardMarkup( @@ -199,6 +201,7 @@ async def test_send_message( ( { ATTR_MESSAGE: "test_message", + ATTR_PARSER: PARSER_PLAIN_TEXT, ATTR_KEYBOARD_INLINE: [ [["command1", "/cmd1"]], [["mock_link", "https://mock_link"]], @@ -250,7 +253,7 @@ async def test_send_message_with_inline_keyboard( mock_send_message.assert_called_once_with( 12345678, "test_message", - parse_mode=ParseMode.MARKDOWN, + parse_mode=None, disable_web_page_preview=None, disable_notification=False, reply_to_message_id=None, diff --git a/tests/components/zha/snapshots/test_diagnostics.ambr b/tests/components/zha/snapshots/test_diagnostics.ambr index 44fb913489d..35eb320893f 100644 --- a/tests/components/zha/snapshots/test_diagnostics.ambr +++ b/tests/components/zha/snapshots/test_diagnostics.ambr @@ -168,7 +168,6 @@ dict({ 'id': '0x0010', 'name': 'cie_addr', - 'unsupported': False, 'value': list([ 50, 79, @@ -181,68 +180,18 @@ ]), 'zcl_type': 'EUI64', }), - dict({ - 'id': '0x0013', - 'name': 'current_zone_sensitivity_level', - 'unsupported': False, - 'value': None, - 'zcl_type': 'uint8', - }), dict({ 'id': '0x0012', 'name': 'num_zone_sensitivity_levels_supported', 'unsupported': True, - 'value': None, 'zcl_type': 'uint8', }), - dict({ - 'id': '0x0011', - 'name': 'zone_id', - 'unsupported': False, - 'value': None, - 'zcl_type': 'uint8', - }), - dict({ - 'id': '0x0000', - 'name': 'zone_state', - 'unsupported': False, - 'value': None, - 'zcl_type': 'enum8', - }), - dict({ - 'id': '0x0002', - 'name': 'zone_status', - 'unsupported': False, - 'value': None, - 'zcl_type': 'map16', - }), - dict({ - 'id': '0x0001', - 'name': 'zone_type', - 'unsupported': False, - 'value': None, - 'zcl_type': 'uint16', - }), ]), 'cluster_id': '0x0500', 'endpoint_attribute': 'ias_zone', }), dict({ 'attributes': list([ - dict({ - 'id': '0xfffd', - 'name': 'cluster_revision', - 'unsupported': False, - 'value': None, - 'zcl_type': 'uint16', - }), - dict({ - 'id': '0xfffe', - 'name': 'reporting_status', - 'unsupported': False, - 'value': None, - 'zcl_type': 'enum8', - }), ]), 'cluster_id': '0x0501', 'endpoint_attribute': 'ias_ace',