This commit is contained in:
Franck Nijhof 2025-07-04 22:00:18 +02:00 committed by GitHub
commit 5d6b02f470
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 126 additions and 118 deletions

View File

@ -37,7 +37,7 @@ on:
type: boolean type: boolean
env: env:
CACHE_VERSION: 3 CACHE_VERSION: 4
UV_CACHE_VERSION: 1 UV_CACHE_VERSION: 1
MYPY_CACHE_VERSION: 1 MYPY_CACHE_VERSION: 1
HA_SHORT_VERSION: "2025.7" HA_SHORT_VERSION: "2025.7"

View File

@ -8,5 +8,5 @@
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"loggers": ["aioamazondevices"], "loggers": ["aioamazondevices"],
"quality_scale": "bronze", "quality_scale": "bronze",
"requirements": ["aioamazondevices==3.2.2"] "requirements": ["aioamazondevices==3.2.3"]
} }

View File

@ -13,6 +13,6 @@
"integration_type": "system", "integration_type": "system",
"iot_class": "cloud_push", "iot_class": "cloud_push",
"loggers": ["acme", "hass_nabucasa", "snitun"], "loggers": ["acme", "hass_nabucasa", "snitun"],
"requirements": ["hass-nabucasa==0.104.0"], "requirements": ["hass-nabucasa==0.105.0"],
"single_config_entry": true "single_config_entry": true
} }

View File

@ -63,6 +63,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: EnphaseConfigEntry) ->
coordinator = entry.runtime_data coordinator = entry.runtime_data
coordinator.async_cancel_token_refresh() coordinator.async_cancel_token_refresh()
coordinator.async_cancel_firmware_refresh() coordinator.async_cancel_firmware_refresh()
coordinator.async_cancel_mac_verification()
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

View File

@ -7,7 +7,7 @@
"iot_class": "local_polling", "iot_class": "local_polling",
"loggers": ["pyenphase"], "loggers": ["pyenphase"],
"quality_scale": "platinum", "quality_scale": "platinum",
"requirements": ["pyenphase==2.1.0"], "requirements": ["pyenphase==2.2.0"],
"zeroconf": [ "zeroconf": [
{ {
"type": "_enphase-envoy._tcp.local." "type": "_enphase-envoy._tcp.local."

View File

@ -20,5 +20,5 @@
"documentation": "https://www.home-assistant.io/integrations/frontend", "documentation": "https://www.home-assistant.io/integrations/frontend",
"integration_type": "system", "integration_type": "system",
"quality_scale": "internal", "quality_scale": "internal",
"requirements": ["home-assistant-frontend==20250702.0"] "requirements": ["home-assistant-frontend==20250702.1"]
} }

View File

@ -64,7 +64,7 @@ def setup_bans(hass: HomeAssistant, app: Application, login_threshold: int) -> N
"""Initialize bans when app starts up.""" """Initialize bans when app starts up."""
await app[KEY_BAN_MANAGER].async_load() await app[KEY_BAN_MANAGER].async_load()
app.on_startup.append(ban_startup) app.on_startup.append(ban_startup) # type: ignore[arg-type]
@middleware @middleware

View File

@ -7,6 +7,6 @@
"documentation": "https://www.home-assistant.io/integrations/music_assistant", "documentation": "https://www.home-assistant.io/integrations/music_assistant",
"iot_class": "local_push", "iot_class": "local_push",
"loggers": ["music_assistant"], "loggers": ["music_assistant"],
"requirements": ["music-assistant-client==1.2.3"], "requirements": ["music-assistant-client==1.2.4"],
"zeroconf": ["_mass._tcp.local."] "zeroconf": ["_mass._tcp.local."]
} }

View File

@ -248,8 +248,6 @@ class MusicAssistantPlayer(MusicAssistantEntity, MediaPlayerEntity):
player = self.player player = self.player
active_queue = self.active_queue active_queue = self.active_queue
# update generic attributes # 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: if player.powered and player.playback_state is not None:
self._attr_state = MediaPlayerState(player.playback_state.value) self._attr_state = MediaPlayerState(player.playback_state.value)
else: else:

View File

@ -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),
)

View File

@ -4,13 +4,14 @@ from http import HTTPStatus
import logging import logging
from typing import Any from typing import Any
from httpx import HTTPError, InvalidURL from httpx import HTTPError, InvalidURL, TimeoutException
import voluptuous as vol import voluptuous as vol
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_URL from homeassistant.const import CONF_URL
from homeassistant.helpers.httpx_client import get_async_client from homeassistant.helpers.httpx_client import get_async_client
from .client import get_calendar
from .const import CONF_CALENDAR_NAME, DOMAIN from .const import CONF_CALENDAR_NAME, DOMAIN
from .ics import InvalidIcsException, parse_calendar 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]}) self._async_abort_entries_match({CONF_URL: user_input[CONF_URL]})
client = get_async_client(self.hass) client = get_async_client(self.hass)
try: 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: if res.status_code == HTTPStatus.FORBIDDEN:
errors["base"] = "forbidden" errors["base"] = "forbidden"
return self.async_show_form( return self.async_show_form(
@ -58,9 +59,14 @@ class RemoteCalendarConfigFlow(ConfigFlow, domain=DOMAIN):
errors=errors, errors=errors,
) )
res.raise_for_status() 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: except (HTTPError, InvalidURL) as err:
errors["base"] = "cannot_connect" errors["base"] = "cannot_connect"
_LOGGER.debug("An error occurred: %s", err) _LOGGER.debug("An error occurred: %s", str(err) or type(err).__name__)
else: else:
try: try:
await parse_calendar(self.hass, res.text) await parse_calendar(self.hass, res.text)

View File

@ -3,7 +3,7 @@
from datetime import timedelta from datetime import timedelta
import logging import logging
from httpx import HTTPError, InvalidURL from httpx import HTTPError, InvalidURL, TimeoutException
from ical.calendar import Calendar from ical.calendar import Calendar
from homeassistant.config_entries import ConfigEntry 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.httpx_client import get_async_client
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .client import get_calendar
from .const import DOMAIN from .const import DOMAIN
from .ics import InvalidIcsException, parse_calendar from .ics import InvalidIcsException, parse_calendar
@ -36,7 +37,7 @@ class RemoteCalendarDataUpdateCoordinator(DataUpdateCoordinator[Calendar]):
super().__init__( super().__init__(
hass, hass,
_LOGGER, _LOGGER,
name=DOMAIN, name=f"{DOMAIN}_{config_entry.title}",
update_interval=SCAN_INTERVAL, update_interval=SCAN_INTERVAL,
always_update=True, always_update=True,
) )
@ -46,13 +47,19 @@ class RemoteCalendarDataUpdateCoordinator(DataUpdateCoordinator[Calendar]):
async def _async_update_data(self) -> Calendar: async def _async_update_data(self) -> Calendar:
"""Update data from the url.""" """Update data from the url."""
try: try:
res = await self._client.get(self._url, follow_redirects=True) res = await get_calendar(self._client, self._url)
res.raise_for_status() 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: except (HTTPError, InvalidURL) as err:
_LOGGER.debug("%s: %s", self._url, str(err) or type(err).__name__)
raise UpdateFailed( raise UpdateFailed(
translation_domain=DOMAIN, translation_domain=DOMAIN,
translation_key="unable_to_fetch", translation_key="unable_to_fetch",
translation_placeholders={"err": str(err)},
) from err ) from err
try: try:
self.ics = res.text self.ics = res.text

View File

@ -18,14 +18,18 @@
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]" "already_configured": "[%key:common::config_flow::abort::already_configured_service%]"
}, },
"error": { "error": {
"timeout_connect": "[%key:common::config_flow::error::timeout_connect%]",
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"forbidden": "The server understood the request but refuses to authorize it.", "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." "invalid_ics_file": "There was a problem reading the calendar information. See the error log for additional details."
} }
}, },
"exceptions": { "exceptions": {
"timeout": {
"message": "The connection timed out. See the debug log for additional details."
},
"unable_to_fetch": { "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": { "unable_to_parse": {
"message": "Unable to parse calendar data: {err}" "message": "Unable to parse calendar data: {err}"

View File

@ -124,6 +124,7 @@ class SamsungTVConfigFlow(ConfigFlow, domain=DOMAIN):
self._model: str | None = None self._model: str | None = None
self._connect_result: str | None = None self._connect_result: str | None = None
self._method: str | None = None self._method: str | None = None
self._port: int | None = None
self._name: str | None = None self._name: str | None = None
self._title: str = "" self._title: str = ""
self._id: int | None = None self._id: int | None = None
@ -199,33 +200,37 @@ class SamsungTVConfigFlow(ConfigFlow, domain=DOMAIN):
async def _async_create_bridge(self) -> None: async def _async_create_bridge(self) -> None:
"""Create the bridge.""" """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: if result not in SUCCESSFUL_RESULTS:
LOGGER.debug("No working config found for %s", self._host) LOGGER.debug("No working config found for %s", self._host)
raise AbortFlow(result) raise AbortFlow(result)
assert method is not None assert self._method is not None
self._bridge = SamsungTVBridge.get_bridge(self.hass, method, self._host) 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, self,
) -> tuple[str, str | None, dict[str, Any] | None]: ) -> str:
"""Get device info and method only once.""" """Get device info and method only once."""
if self._connect_result is None: 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._connect_result = result
self._method = method self._method = method
self._port = port
self._device_info = info self._device_info = info
if not method: if not method:
LOGGER.debug("Host:%s did not return device info", self._host) LOGGER.debug("Host:%s did not return device info", self._host)
return result, None, None return self._connect_result
return self._connect_result, self._method, self._device_info
async def _async_get_and_check_device_info(self) -> bool: async def _async_get_and_check_device_info(self) -> bool:
"""Try to get the device info.""" """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: if result not in SUCCESSFUL_RESULTS:
raise AbortFlow(result) raise AbortFlow(result)
if not info: if not (info := self._device_info):
return False return False
dev_info = info.get("device", {}) dev_info = info.get("device", {})
assert dev_info is not None assert dev_info is not None

View File

@ -374,9 +374,7 @@ class TelegramNotificationService:
} }
if data is not None: if data is not None:
if ATTR_PARSER in data: if ATTR_PARSER in data:
params[ATTR_PARSER] = self._parsers.get( params[ATTR_PARSER] = data[ATTR_PARSER]
data[ATTR_PARSER], self.parse_mode
)
if ATTR_TIMEOUT in data: if ATTR_TIMEOUT in data:
params[ATTR_TIMEOUT] = data[ATTR_TIMEOUT] params[ATTR_TIMEOUT] = data[ATTR_TIMEOUT]
if ATTR_DISABLE_NOTIF in data: if ATTR_DISABLE_NOTIF in data:
@ -408,6 +406,8 @@ class TelegramNotificationService:
params[ATTR_REPLYMARKUP] = InlineKeyboardMarkup( params[ATTR_REPLYMARKUP] = InlineKeyboardMarkup(
[_make_row_inline_keyboard(row) for row in keys] [_make_row_inline_keyboard(row) for row in keys]
) )
if params[ATTR_PARSER] == PARSER_PLAIN_TEXT:
params[ATTR_PARSER] = None
return params return params
async def _send_msg( async def _send_msg(

View File

@ -159,8 +159,6 @@ class OptionsFlowHandler(OptionsFlow):
"""Manage the options.""" """Manage the options."""
if user_input is not None: 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_create_entry(data=user_input)
return self.async_show_form( return self.async_show_form(

View File

@ -109,6 +109,7 @@ send_photo:
- "markdown" - "markdown"
- "markdownv2" - "markdownv2"
- "plain_text" - "plain_text"
translation_key: "parse_mode"
disable_notification: disable_notification:
selector: selector:
boolean: boolean:
@ -261,6 +262,7 @@ send_animation:
- "markdown" - "markdown"
- "markdownv2" - "markdownv2"
- "plain_text" - "plain_text"
translation_key: "parse_mode"
disable_notification: disable_notification:
selector: selector:
boolean: boolean:
@ -341,6 +343,7 @@ send_video:
- "markdown" - "markdown"
- "markdownv2" - "markdownv2"
- "plain_text" - "plain_text"
translation_key: "parse_mode"
disable_notification: disable_notification:
selector: selector:
boolean: boolean:
@ -493,6 +496,7 @@ send_document:
- "markdown" - "markdown"
- "markdownv2" - "markdownv2"
- "plain_text" - "plain_text"
translation_key: "parse_mode"
disable_notification: disable_notification:
selector: selector:
boolean: boolean:
@ -670,6 +674,7 @@ edit_message:
- "markdown" - "markdown"
- "markdownv2" - "markdownv2"
- "plain_text" - "plain_text"
translation_key: "parse_mode"
disable_web_page_preview: disable_web_page_preview:
selector: selector:
boolean: boolean:

View File

@ -7,7 +7,7 @@
"integration_type": "hub", "integration_type": "hub",
"iot_class": "local_push", "iot_class": "local_push",
"loggers": ["aiounifi"], "loggers": ["aiounifi"],
"requirements": ["aiounifi==83"], "requirements": ["aiounifi==84"],
"ssdp": [ "ssdp": [
{ {
"manufacturer": "Ubiquiti Networks", "manufacturer": "Ubiquiti Networks",

View File

@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/venstar", "documentation": "https://www.home-assistant.io/integrations/venstar",
"iot_class": "local_polling", "iot_class": "local_polling",
"loggers": ["venstarcolortouch"], "loggers": ["venstarcolortouch"],
"requirements": ["venstarcolortouch==0.19"] "requirements": ["venstarcolortouch==0.21"]
} }

View File

@ -21,7 +21,7 @@
"zha", "zha",
"universal_silabs_flasher" "universal_silabs_flasher"
], ],
"requirements": ["zha==0.0.61"], "requirements": ["zha==0.0.62"],
"usb": [ "usb": [
{ {
"vid": "10C4", "vid": "10C4",

View File

@ -25,7 +25,7 @@ if TYPE_CHECKING:
APPLICATION_NAME: Final = "HomeAssistant" APPLICATION_NAME: Final = "HomeAssistant"
MAJOR_VERSION: Final = 2025 MAJOR_VERSION: Final = 2025
MINOR_VERSION: Final = 7 MINOR_VERSION: Final = 7
PATCH_VERSION: Final = "0" PATCH_VERSION: Final = "1"
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}" __short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__: Final = f"{__short_version__}.{PATCH_VERSION}" __version__: Final = f"{__short_version__}.{PATCH_VERSION}"
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 13, 2) REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 13, 2)

View File

@ -35,10 +35,10 @@ fnv-hash-fast==1.5.0
go2rtc-client==0.2.1 go2rtc-client==0.2.1
ha-ffmpeg==3.2.2 ha-ffmpeg==3.2.2
habluetooth==3.49.0 habluetooth==3.49.0
hass-nabucasa==0.104.0 hass-nabucasa==0.105.0
hassil==2.2.3 hassil==2.2.3
home-assistant-bluetooth==1.13.1 home-assistant-bluetooth==1.13.1
home-assistant-frontend==20250702.0 home-assistant-frontend==20250702.1
home-assistant-intents==2025.6.23 home-assistant-intents==2025.6.23
httpx==0.28.1 httpx==0.28.1
ifaddr==0.2.0 ifaddr==0.2.0

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "homeassistant" name = "homeassistant"
version = "2025.7.0" version = "2025.7.1"
license = "Apache-2.0" license = "Apache-2.0"
license-files = ["LICENSE*", "homeassistant/backports/LICENSE*"] license-files = ["LICENSE*", "homeassistant/backports/LICENSE*"]
description = "Open-source home automation platform running on Python 3." description = "Open-source home automation platform running on Python 3."
@ -47,7 +47,7 @@ dependencies = [
"fnv-hash-fast==1.5.0", "fnv-hash-fast==1.5.0",
# hass-nabucasa is imported by helpers which don't depend on the cloud # hass-nabucasa is imported by helpers which don't depend on the cloud
# integration # integration
"hass-nabucasa==0.104.0", "hass-nabucasa==0.105.0",
# When bumping httpx, please check the version pins of # When bumping httpx, please check the version pins of
# httpcore, anyio, and h11 in gen_requirements_all # httpcore, anyio, and h11 in gen_requirements_all
"httpx==0.28.1", "httpx==0.28.1",

2
requirements.txt generated
View File

@ -22,7 +22,7 @@ certifi>=2021.5.30
ciso8601==2.3.2 ciso8601==2.3.2
cronsim==2.6 cronsim==2.6
fnv-hash-fast==1.5.0 fnv-hash-fast==1.5.0
hass-nabucasa==0.104.0 hass-nabucasa==0.105.0
httpx==0.28.1 httpx==0.28.1
home-assistant-bluetooth==1.13.1 home-assistant-bluetooth==1.13.1
ifaddr==0.2.0 ifaddr==0.2.0

16
requirements_all.txt generated
View File

@ -185,7 +185,7 @@ aioairzone-cloud==0.6.12
aioairzone==1.0.0 aioairzone==1.0.0
# homeassistant.components.alexa_devices # homeassistant.components.alexa_devices
aioamazondevices==3.2.2 aioamazondevices==3.2.3
# homeassistant.components.ambient_network # homeassistant.components.ambient_network
# homeassistant.components.ambient_station # homeassistant.components.ambient_station
@ -414,7 +414,7 @@ aiotedee==0.2.25
aiotractive==0.6.0 aiotractive==0.6.0
# homeassistant.components.unifi # homeassistant.components.unifi
aiounifi==83 aiounifi==84
# homeassistant.components.usb # homeassistant.components.usb
aiousbwatcher==1.1.1 aiousbwatcher==1.1.1
@ -1127,7 +1127,7 @@ habiticalib==0.4.0
habluetooth==3.49.0 habluetooth==3.49.0
# homeassistant.components.cloud # homeassistant.components.cloud
hass-nabucasa==0.104.0 hass-nabucasa==0.105.0
# homeassistant.components.splunk # homeassistant.components.splunk
hass-splunk==0.1.1 hass-splunk==0.1.1
@ -1168,7 +1168,7 @@ hole==0.8.0
holidays==0.75 holidays==0.75
# homeassistant.components.frontend # homeassistant.components.frontend
home-assistant-frontend==20250702.0 home-assistant-frontend==20250702.1
# homeassistant.components.conversation # homeassistant.components.conversation
home-assistant-intents==2025.6.23 home-assistant-intents==2025.6.23
@ -1467,7 +1467,7 @@ mozart-api==4.1.1.116.4
mullvad-api==1.0.0 mullvad-api==1.0.0
# homeassistant.components.music_assistant # homeassistant.components.music_assistant
music-assistant-client==1.2.3 music-assistant-client==1.2.4
# homeassistant.components.tts # homeassistant.components.tts
mutagen==1.47.0 mutagen==1.47.0
@ -1962,7 +1962,7 @@ pyeiscp==0.0.7
pyemoncms==0.1.1 pyemoncms==0.1.1
# homeassistant.components.enphase_envoy # homeassistant.components.enphase_envoy
pyenphase==2.1.0 pyenphase==2.2.0
# homeassistant.components.envisalink # homeassistant.components.envisalink
pyenvisalink==4.7 pyenvisalink==4.7
@ -3041,7 +3041,7 @@ vehicle==2.2.2
velbus-aio==2025.5.0 velbus-aio==2025.5.0
# homeassistant.components.venstar # homeassistant.components.venstar
venstarcolortouch==0.19 venstarcolortouch==0.21
# homeassistant.components.vilfo # homeassistant.components.vilfo
vilfo-api-client==0.5.0 vilfo-api-client==0.5.0
@ -3190,7 +3190,7 @@ zeroconf==0.147.0
zeversolar==0.3.2 zeversolar==0.3.2
# homeassistant.components.zha # homeassistant.components.zha
zha==0.0.61 zha==0.0.62
# homeassistant.components.zhong_hong # homeassistant.components.zhong_hong
zhong-hong-hvac==1.0.13 zhong-hong-hvac==1.0.13

View File

@ -173,7 +173,7 @@ aioairzone-cloud==0.6.12
aioairzone==1.0.0 aioairzone==1.0.0
# homeassistant.components.alexa_devices # homeassistant.components.alexa_devices
aioamazondevices==3.2.2 aioamazondevices==3.2.3
# homeassistant.components.ambient_network # homeassistant.components.ambient_network
# homeassistant.components.ambient_station # homeassistant.components.ambient_station
@ -396,7 +396,7 @@ aiotedee==0.2.25
aiotractive==0.6.0 aiotractive==0.6.0
# homeassistant.components.unifi # homeassistant.components.unifi
aiounifi==83 aiounifi==84
# homeassistant.components.usb # homeassistant.components.usb
aiousbwatcher==1.1.1 aiousbwatcher==1.1.1
@ -988,7 +988,7 @@ habiticalib==0.4.0
habluetooth==3.49.0 habluetooth==3.49.0
# homeassistant.components.cloud # homeassistant.components.cloud
hass-nabucasa==0.104.0 hass-nabucasa==0.105.0
# homeassistant.components.assist_satellite # homeassistant.components.assist_satellite
# homeassistant.components.conversation # homeassistant.components.conversation
@ -1017,7 +1017,7 @@ hole==0.8.0
holidays==0.75 holidays==0.75
# homeassistant.components.frontend # homeassistant.components.frontend
home-assistant-frontend==20250702.0 home-assistant-frontend==20250702.1
# homeassistant.components.conversation # homeassistant.components.conversation
home-assistant-intents==2025.6.23 home-assistant-intents==2025.6.23
@ -1259,7 +1259,7 @@ mozart-api==4.1.1.116.4
mullvad-api==1.0.0 mullvad-api==1.0.0
# homeassistant.components.music_assistant # homeassistant.components.music_assistant
music-assistant-client==1.2.3 music-assistant-client==1.2.4
# homeassistant.components.tts # homeassistant.components.tts
mutagen==1.47.0 mutagen==1.47.0
@ -1637,7 +1637,7 @@ pyeiscp==0.0.7
pyemoncms==0.1.1 pyemoncms==0.1.1
# homeassistant.components.enphase_envoy # homeassistant.components.enphase_envoy
pyenphase==2.1.0 pyenphase==2.2.0
# homeassistant.components.everlights # homeassistant.components.everlights
pyeverlights==0.1.0 pyeverlights==0.1.0
@ -2509,7 +2509,7 @@ vehicle==2.2.2
velbus-aio==2025.5.0 velbus-aio==2025.5.0
# homeassistant.components.venstar # homeassistant.components.venstar
venstarcolortouch==0.19 venstarcolortouch==0.21
# homeassistant.components.vilfo # homeassistant.components.vilfo
vilfo-api-client==0.5.0 vilfo-api-client==0.5.0
@ -2634,7 +2634,7 @@ zeroconf==0.147.0
zeversolar==0.3.2 zeversolar==0.3.2
# homeassistant.components.zha # homeassistant.components.zha
zha==0.0.61 zha==0.0.62
# homeassistant.components.zwave_js # homeassistant.components.zwave_js
zwave-js-server-python==0.65.0 zwave-js-server-python==0.65.0

View File

@ -1,6 +1,6 @@
"""Test the Remote Calendar config flow.""" """Test the Remote Calendar config flow."""
from httpx import ConnectError, Response, UnsupportedProtocol from httpx import HTTPError, InvalidURL, Response, TimeoutException
import pytest import pytest
import respx import respx
@ -75,10 +75,11 @@ async def test_form_import_webcal(hass: HomeAssistant, ics_content: str) -> None
@pytest.mark.parametrize( @pytest.mark.parametrize(
("side_effect"), ("side_effect", "base_error"),
[ [
ConnectError("Connection failed"), (TimeoutException("Connection timed out"), "timeout_connect"),
UnsupportedProtocol("Unsupported protocol"), (HTTPError("Connection failed"), "cannot_connect"),
(InvalidURL("Unsupported protocol"), "cannot_connect"),
], ],
) )
@respx.mock @respx.mock
@ -86,6 +87,7 @@ async def test_form_inavild_url(
hass: HomeAssistant, hass: HomeAssistant,
side_effect: Exception, side_effect: Exception,
ics_content: str, ics_content: str,
base_error: str,
) -> None: ) -> None:
"""Test we get the import form.""" """Test we get the import form."""
result = await hass.config_entries.flow.async_init( 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["type"] is FlowResultType.FORM
assert result2["errors"] == {"base": "cannot_connect"} assert result2["errors"] == {"base": base_error}
respx.get(CALENDER_URL).mock( respx.get(CALENDER_URL).mock(
return_value=Response( return_value=Response(
status_code=200, status_code=200,

View File

@ -1,6 +1,6 @@
"""Tests for init platform of Remote Calendar.""" """Tests for init platform of Remote Calendar."""
from httpx import ConnectError, Response, UnsupportedProtocol from httpx import HTTPError, InvalidURL, Response, TimeoutException
import pytest import pytest
import respx import respx
@ -56,8 +56,9 @@ async def test_raise_for_status(
@pytest.mark.parametrize( @pytest.mark.parametrize(
"side_effect", "side_effect",
[ [
ConnectError("Connection failed"), TimeoutException("Connection timed out"),
UnsupportedProtocol("Unsupported protocol"), HTTPError("Connection failed"),
InvalidURL("Unsupported protocol"),
ValueError("Invalid response"), ValueError("Invalid response"),
], ],
) )

View File

@ -161,6 +161,7 @@ async def test_user_legacy(hass: HomeAssistant) -> None:
assert result["data"][CONF_METHOD] == METHOD_LEGACY assert result["data"][CONF_METHOD] == METHOD_LEGACY
assert result["data"][CONF_MANUFACTURER] == DEFAULT_MANUFACTURER assert result["data"][CONF_MANUFACTURER] == DEFAULT_MANUFACTURER
assert result["data"][CONF_MODEL] is None assert result["data"][CONF_MODEL] is None
assert result["data"][CONF_PORT] == 55000
assert result["result"].unique_id is None 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_METHOD] == METHOD_LEGACY
assert result3["data"][CONF_MANUFACTURER] == DEFAULT_MANUFACTURER assert result3["data"][CONF_MANUFACTURER] == DEFAULT_MANUFACTURER
assert result3["data"][CONF_MODEL] is None assert result3["data"][CONF_MODEL] is None
assert result3["data"][CONF_PORT] == 55000
assert result3["result"].unique_id is None 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_METHOD] == "websocket"
assert result["data"][CONF_MANUFACTURER] == "Samsung" assert result["data"][CONF_MANUFACTURER] == "Samsung"
assert result["data"][CONF_MODEL] == "82GXARRS" assert result["data"][CONF_MODEL] == "82GXARRS"
assert result["data"][CONF_PORT] == 8002
assert result["result"].unique_id == "be9554b9-c9fb-41f4-8920-22da015376a4" 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_MAC] == "aa:bb:aa:aa:aa:aa"
assert result4["data"][CONF_MANUFACTURER] == "Samsung" assert result4["data"][CONF_MANUFACTURER] == "Samsung"
assert result4["data"][CONF_MODEL] == "UE48JU6400" 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_SSDP_RENDERING_CONTROL_LOCATION] is None
assert result4["data"][CONF_TOKEN] == "037739871315caef138547b03e348b72" assert result4["data"][CONF_TOKEN] == "037739871315caef138547b03e348b72"
assert result4["data"][CONF_SESSION_ID] == "1" 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_HOST] == "10.20.43.21"
assert result["data"][CONF_MANUFACTURER] == "Samsung" assert result["data"][CONF_MANUFACTURER] == "Samsung"
assert result["data"][CONF_MODEL] == "82GXARRS" assert result["data"][CONF_MODEL] == "82GXARRS"
assert result["data"][CONF_PORT] == 8002
assert result["result"].unique_id == "be9554b9-c9fb-41f4-8920-22da015376a4" 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_HOST] == "10.10.12.34"
assert result["data"][CONF_MANUFACTURER] == "Samsung Electronics" assert result["data"][CONF_MANUFACTURER] == "Samsung Electronics"
assert result["data"][CONF_MODEL] == "UE55H6400" assert result["data"][CONF_MODEL] == "UE55H6400"
assert result["data"][CONF_PORT] == 55000
assert result["result"].unique_id == "068e7781-006e-1000-bbbf-84a4668d8423" 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_HOST] == "10.10.12.34"
assert result["data"][CONF_MANUFACTURER] == "Samsung Electronics" assert result["data"][CONF_MANUFACTURER] == "Samsung Electronics"
assert result["data"][CONF_MODEL] == "UE55H6400" assert result["data"][CONF_MODEL] == "UE55H6400"
assert result["data"][CONF_PORT] == 55000
assert result["result"].unique_id == "068e7781-006e-1000-bbbf-84a4668d8423" 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_HOST] == "10.10.12.34"
assert result["data"][CONF_MANUFACTURER] == "Samsung Electronics" assert result["data"][CONF_MANUFACTURER] == "Samsung Electronics"
assert result["data"][CONF_MODEL] == "UE55H6400" assert result["data"][CONF_MODEL] == "UE55H6400"
assert result["data"][CONF_PORT] == 55000
assert result["result"].unique_id == "068e7781-006e-1000-bbbf-84a4668d8423" 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_MAC] == "aa:bb:aa:aa:aa:aa"
assert result["data"][CONF_MANUFACTURER] == "Samsung Electronics" assert result["data"][CONF_MANUFACTURER] == "Samsung Electronics"
assert result["data"][CONF_MODEL] == "82GXARRS" assert result["data"][CONF_MODEL] == "82GXARRS"
assert result["data"][CONF_PORT] == 8002
assert ( assert (
result["data"][CONF_SSDP_RENDERING_CONTROL_LOCATION] result["data"][CONF_SSDP_RENDERING_CONTROL_LOCATION]
== "http://10.10.12.34:7676/smp_15_" == "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_MAC] == "aa:bb:aa:aa:aa:aa"
assert result["data"][CONF_MANUFACTURER] == "Samsung Electronics" assert result["data"][CONF_MANUFACTURER] == "Samsung Electronics"
assert result["data"][CONF_MODEL] == "82GXARRS" assert result["data"][CONF_MODEL] == "82GXARRS"
assert result["data"][CONF_PORT] == 8002
assert ( assert (
result["data"][CONF_SSDP_MAIN_TV_AGENT_LOCATION] result["data"][CONF_SSDP_MAIN_TV_AGENT_LOCATION]
== "http://10.10.12.34:7676/smp_2_" == "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_MAC] == "aa:bb:aa:aa:aa:aa"
assert result4["data"][CONF_MANUFACTURER] == "Samsung Electronics" assert result4["data"][CONF_MANUFACTURER] == "Samsung Electronics"
assert result4["data"][CONF_MODEL] == "UE48JU6400" assert result4["data"][CONF_MODEL] == "UE48JU6400"
assert result4["data"][CONF_PORT] == 8000
assert ( assert (
result4["data"][CONF_SSDP_RENDERING_CONTROL_LOCATION] result4["data"][CONF_SSDP_RENDERING_CONTROL_LOCATION]
== "http://10.10.12.34:7676/smp_15_" == "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_MAC] == "aa:bb:aa:aa:aa:aa"
assert result["data"][CONF_MANUFACTURER] == "Samsung" assert result["data"][CONF_MANUFACTURER] == "Samsung"
assert result["data"][CONF_MODEL] == "UE48JU6400" assert result["data"][CONF_MODEL] == "UE48JU6400"
assert result["data"][CONF_PORT] == 8002
assert result["result"].unique_id == "223da676-497a-4e06-9507-5e27ec4f0fb3" 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_MAC] == "aa:ee:tt:hh:ee:rr"
assert result["data"][CONF_MANUFACTURER] == "Samsung" assert result["data"][CONF_MANUFACTURER] == "Samsung"
assert result["data"][CONF_MODEL] == "UE43LS003" assert result["data"][CONF_MODEL] == "UE43LS003"
assert result["data"][CONF_PORT] == 8002
assert result["result"].unique_id == "be9554b9-c9fb-41f4-8920-22da015376a4" 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_MAC] == "aa:bb:aa:aa:aa:aa"
assert result["data"][CONF_MANUFACTURER] == "Samsung" assert result["data"][CONF_MANUFACTURER] == "Samsung"
assert result["data"][CONF_MODEL] == "82GXARRS" assert result["data"][CONF_MODEL] == "82GXARRS"
assert result["data"][CONF_PORT] == 8002
assert result["result"].unique_id == "be9554b9-c9fb-41f4-8920-22da015376a4" 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["type"] is FlowResultType.CREATE_ENTRY
assert result["data"][CONF_METHOD] == "websocket" assert result["data"][CONF_METHOD] == "websocket"
assert result["data"][CONF_TOKEN] == "123456789" assert result["data"][CONF_TOKEN] == "123456789"
assert result["data"][CONF_PORT] == 8002
remote_websocket.assert_called_once_with(**AUTODETECT_WEBSOCKET_SSL) remote_websocket.assert_called_once_with(**AUTODETECT_WEBSOCKET_SSL)
rest_api_class.assert_called_once_with(**DEVICEINFO_WEBSOCKET_SSL) rest_api_class.assert_called_once_with(**DEVICEINFO_WEBSOCKET_SSL)
await hass.async_block_till_done() 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_METHOD] == "websocket"
assert result["data"][CONF_TOKEN] == "123456789" assert result["data"][CONF_TOKEN] == "123456789"
assert result["data"][CONF_MAC] == "gg:ee:tt:mm:aa:cc" 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) remote_websocket.assert_called_once_with(**AUTODETECT_WEBSOCKET_SSL)
rest_api_class.assert_called_once_with(**DEVICEINFO_WEBSOCKET_SSL) rest_api_class.assert_called_once_with(**DEVICEINFO_WEBSOCKET_SSL)
await hass.async_block_till_done() 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_MANUFACTURER] == DEFAULT_MANUFACTURER
assert entry.data[CONF_MODEL] == "fake_model" assert entry.data[CONF_MODEL] == "fake_model"
assert entry.data[CONF_MAC] is None assert entry.data[CONF_MAC] is None
assert entry.data[CONF_PORT] == 8002
assert entry.unique_id == "123" assert entry.unique_id == "123"
device_info = deepcopy(MOCK_DEVICE_INFO) device_info = deepcopy(MOCK_DEVICE_INFO)

View File

@ -63,7 +63,7 @@ async def test_options_flow(
await hass.async_block_till_done() await hass.async_block_till_done()
assert result["type"] == FlowResultType.CREATE_ENTRY 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( async def test_reconfigure_flow_broadcast(

View File

@ -50,6 +50,7 @@ from homeassistant.components.telegram_bot.const import (
ATTR_VERIFY_SSL, ATTR_VERIFY_SSL,
CONF_CONFIG_ENTRY_ID, CONF_CONFIG_ENTRY_ID,
DOMAIN, DOMAIN,
PARSER_PLAIN_TEXT,
PLATFORM_BROADCAST, PLATFORM_BROADCAST,
SECTION_ADVANCED_SETTINGS, SECTION_ADVANCED_SETTINGS,
SERVICE_ANSWER_CALLBACK_QUERY, SERVICE_ANSWER_CALLBACK_QUERY,
@ -183,6 +184,7 @@ async def test_send_message(
( (
{ {
ATTR_MESSAGE: "test_message", ATTR_MESSAGE: "test_message",
ATTR_PARSER: PARSER_PLAIN_TEXT,
ATTR_KEYBOARD_INLINE: "command1:/cmd1,/cmd2,mock_link:https://mock_link", ATTR_KEYBOARD_INLINE: "command1:/cmd1,/cmd2,mock_link:https://mock_link",
}, },
InlineKeyboardMarkup( InlineKeyboardMarkup(
@ -199,6 +201,7 @@ async def test_send_message(
( (
{ {
ATTR_MESSAGE: "test_message", ATTR_MESSAGE: "test_message",
ATTR_PARSER: PARSER_PLAIN_TEXT,
ATTR_KEYBOARD_INLINE: [ ATTR_KEYBOARD_INLINE: [
[["command1", "/cmd1"]], [["command1", "/cmd1"]],
[["mock_link", "https://mock_link"]], [["mock_link", "https://mock_link"]],
@ -250,7 +253,7 @@ async def test_send_message_with_inline_keyboard(
mock_send_message.assert_called_once_with( mock_send_message.assert_called_once_with(
12345678, 12345678,
"test_message", "test_message",
parse_mode=ParseMode.MARKDOWN, parse_mode=None,
disable_web_page_preview=None, disable_web_page_preview=None,
disable_notification=False, disable_notification=False,
reply_to_message_id=None, reply_to_message_id=None,

View File

@ -168,7 +168,6 @@
dict({ dict({
'id': '0x0010', 'id': '0x0010',
'name': 'cie_addr', 'name': 'cie_addr',
'unsupported': False,
'value': list([ 'value': list([
50, 50,
79, 79,
@ -181,68 +180,18 @@
]), ]),
'zcl_type': 'EUI64', 'zcl_type': 'EUI64',
}), }),
dict({
'id': '0x0013',
'name': 'current_zone_sensitivity_level',
'unsupported': False,
'value': None,
'zcl_type': 'uint8',
}),
dict({ dict({
'id': '0x0012', 'id': '0x0012',
'name': 'num_zone_sensitivity_levels_supported', 'name': 'num_zone_sensitivity_levels_supported',
'unsupported': True, 'unsupported': True,
'value': None,
'zcl_type': 'uint8', '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', 'cluster_id': '0x0500',
'endpoint_attribute': 'ias_zone', 'endpoint_attribute': 'ias_zone',
}), }),
dict({ dict({
'attributes': list([ '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', 'cluster_id': '0x0501',
'endpoint_attribute': 'ias_ace', 'endpoint_attribute': 'ias_ace',