Merge branch 'dev' into epenet-20250602-1736

This commit is contained in:
epenet 2025-06-03 10:19:47 +02:00 committed by GitHub
commit ac367bc343
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 201 additions and 207 deletions

View File

@ -360,7 +360,7 @@ jobs:
- name: Run ruff
run: |
. venv/bin/activate
pre-commit run --hook-stage manual ruff --all-files --show-diff-on-failure
pre-commit run --hook-stage manual ruff-check --all-files --show-diff-on-failure
env:
RUFF_OUTPUT_FORMAT: github

View File

@ -1,8 +1,8 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.0
rev: v0.11.12
hooks:
- id: ruff
- id: ruff-check
args:
- --fix
- id: ruff-format
@ -30,7 +30,7 @@ repos:
- --branch=master
- --branch=rc
- repo: https://github.com/adrienverge/yamllint.git
rev: v1.35.1
rev: v1.37.1
hooks:
- id: yamllint
- repo: https://github.com/pre-commit/mirrors-prettier

2
.vscode/tasks.json vendored
View File

@ -45,7 +45,7 @@
{
"label": "Ruff",
"type": "shell",
"command": "pre-commit run ruff --all-files",
"command": "pre-commit run ruff-check --all-files",
"group": {
"kind": "test",
"isDefault": true

View File

@ -118,5 +118,5 @@
"iot_class": "cloud_polling",
"loggers": ["aioamazondevices"],
"quality_scale": "bronze",
"requirements": ["aioamazondevices==3.0.4"]
"requirements": ["aioamazondevices==3.0.5"]
}

View File

@ -8,6 +8,6 @@
"integration_type": "system",
"iot_class": "local_polling",
"quality_scale": "internal",
"requirements": ["go2rtc-client==0.1.3b0"],
"requirements": ["go2rtc-client==0.2.1"],
"single_config_entry": true
}

View File

@ -24,9 +24,11 @@ CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Google Mail platform."""
"""Set up the Google Mail integration."""
hass.data.setdefault(DOMAIN, {})[DATA_HASS_CONFIG] = config
await async_setup_services(hass)
return True
@ -52,8 +54,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: GoogleMailConfigEntry) -
entry, [platform for platform in PLATFORMS if platform != Platform.NOTIFY]
)
await async_setup_services(hass)
return True

View File

@ -7,17 +7,26 @@ from google_photos_library_api.api import GooglePhotosLibraryApi
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers import config_entry_oauth2_flow
from homeassistant.helpers import config_entry_oauth2_flow, config_validation as cv
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.typing import ConfigType
from . import api
from .const import DOMAIN
from .coordinator import GooglePhotosConfigEntry, GooglePhotosUpdateCoordinator
from .services import async_register_services
__all__ = [
"DOMAIN",
]
__all__ = ["DOMAIN"]
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up Google Photos integration."""
async_register_services(hass)
return True
async def async_setup_entry(
@ -48,8 +57,6 @@ async def async_setup_entry(
await coordinator.async_config_entry_first_refresh()
entry.runtime_data = coordinator
async_register_services(hass)
return True

View File

@ -152,11 +152,10 @@ def async_register_services(hass: HomeAssistant) -> None:
}
return None
if not hass.services.has_service(DOMAIN, UPLOAD_SERVICE):
hass.services.async_register(
DOMAIN,
UPLOAD_SERVICE,
async_handle_upload,
schema=UPLOAD_SERVICE_SCHEMA,
supports_response=SupportsResponse.OPTIONAL,
)
hass.services.async_register(
DOMAIN,
UPLOAD_SERVICE,
async_handle_upload,
schema=UPLOAD_SERVICE_SCHEMA,
supports_response=SupportsResponse.OPTIONAL,
)

View File

@ -14,6 +14,6 @@
"documentation": "https://www.home-assistant.io/integrations/homekit_controller",
"iot_class": "local_push",
"loggers": ["aiohomekit", "commentjson"],
"requirements": ["aiohomekit==3.2.14"],
"requirements": ["aiohomekit==3.2.15"],
"zeroconf": ["_hap._tcp.local.", "_hap._udp.local."]
}

View File

@ -63,6 +63,8 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
)
)
await async_setup_services(hass)
return True
@ -83,7 +85,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: HomematicIPConfigEntry)
if not await hap.async_setup():
return False
await async_setup_services(hass)
_async_remove_obsolete_entities(hass, entry, hap)
# Register on HA stop event to gracefully shutdown HomematicIP Cloud connection

View File

@ -12,6 +12,6 @@
"iot_class": "local_polling",
"loggers": ["homewizard_energy"],
"quality_scale": "platinum",
"requirements": ["python-homewizard-energy==v8.3.2"],
"requirements": ["python-homewizard-energy==8.3.3"],
"zeroconf": ["_hwenergy._tcp.local.", "_homewizard._tcp.local."]
}

View File

@ -5,13 +5,24 @@ from aiohue.util import normalize_bridge_id
from homeassistant.components import persistent_notification
from homeassistant.config_entries import SOURCE_IGNORE
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers import config_validation as cv, device_registry as dr
from homeassistant.helpers.typing import ConfigType
from .bridge import HueBridge, HueConfigEntry
from .const import DOMAIN, SERVICE_HUE_ACTIVATE_SCENE
from .const import DOMAIN
from .migration import check_migration
from .services import async_register_services
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up Hue integration."""
async_register_services(hass)
return True
async def async_setup_entry(hass: HomeAssistant, entry: HueConfigEntry) -> bool:
"""Set up a bridge from a config entry."""
@ -23,9 +34,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: HueConfigEntry) -> bool:
if not await bridge.async_initialize_bridge():
return False
# register Hue domain services
async_register_services(hass)
api = bridge.api
# For backwards compat
@ -106,7 +114,4 @@ async def async_setup_entry(hass: HomeAssistant, entry: HueConfigEntry) -> bool:
async def async_unload_entry(hass: HomeAssistant, entry: HueConfigEntry) -> bool:
"""Unload a config entry."""
unload_success = await entry.runtime_data.async_reset()
if not hass.config_entries.async_loaded_entries(DOMAIN):
hass.services.async_remove(DOMAIN, SERVICE_HUE_ACTIVATE_SCENE)
return unload_success
return await entry.runtime_data.async_reset()

View File

@ -59,21 +59,20 @@ def async_register_services(hass: HomeAssistant) -> None:
group_name,
)
if not hass.services.has_service(DOMAIN, SERVICE_HUE_ACTIVATE_SCENE):
# Register a local handler for scene activation
hass.services.async_register(
DOMAIN,
SERVICE_HUE_ACTIVATE_SCENE,
verify_domain_entity_control(DOMAIN)(hue_activate_scene),
schema=vol.Schema(
{
vol.Required(ATTR_GROUP_NAME): cv.string,
vol.Required(ATTR_SCENE_NAME): cv.string,
vol.Optional(ATTR_TRANSITION): cv.positive_int,
vol.Optional(ATTR_DYNAMIC): cv.boolean,
}
),
)
# Register a local handler for scene activation
hass.services.async_register(
DOMAIN,
SERVICE_HUE_ACTIVATE_SCENE,
verify_domain_control(hass, DOMAIN)(hue_activate_scene),
schema=vol.Schema(
{
vol.Required(ATTR_GROUP_NAME): cv.string,
vol.Required(ATTR_SCENE_NAME): cv.string,
vol.Optional(ATTR_TRANSITION): cv.positive_int,
vol.Optional(ATTR_DYNAMIC): cv.boolean,
}
),
)
async def hue_activate_scene_v1(

View File

@ -153,49 +153,40 @@ class ImmichMediaSource(MediaSource):
except ImmichError:
return []
ret = [
BrowseMediaSource(
domain=DOMAIN,
identifier=(
f"{identifier.unique_id}|albums|"
f"{identifier.collection_id}|"
f"{asset.asset_id}|"
f"{asset.original_file_name}|"
f"{mime_type}"
),
media_class=MediaClass.IMAGE,
media_content_type=mime_type,
title=asset.original_file_name,
can_play=False,
can_expand=False,
thumbnail=f"/immich/{identifier.unique_id}/{asset.asset_id}/thumbnail/{mime_type}",
)
for asset in album_info.assets
if (mime_type := asset.original_mime_type)
and mime_type.startswith("image/")
]
ret: list[BrowseMediaSource] = []
for asset in album_info.assets:
if not (mime_type := asset.original_mime_type) or not mime_type.startswith(
("image/", "video/")
):
continue
ret.extend(
BrowseMediaSource(
domain=DOMAIN,
identifier=(
f"{identifier.unique_id}|albums|"
f"{identifier.collection_id}|"
f"{asset.asset_id}|"
f"{asset.original_file_name}|"
f"{mime_type}"
),
media_class=MediaClass.VIDEO,
media_content_type=mime_type,
title=asset.original_file_name,
can_play=True,
can_expand=False,
thumbnail=f"/immich/{identifier.unique_id}/{asset.asset_id}/thumbnail/image/jpeg",
if mime_type.startswith("image/"):
media_class = MediaClass.IMAGE
can_play = False
thumb_mime_type = mime_type
else:
media_class = MediaClass.VIDEO
can_play = True
thumb_mime_type = "image/jpeg"
ret.append(
BrowseMediaSource(
domain=DOMAIN,
identifier=(
f"{identifier.unique_id}|albums|"
f"{identifier.collection_id}|"
f"{asset.asset_id}|"
f"{asset.original_file_name}|"
f"{mime_type}"
),
media_class=media_class,
media_content_type=mime_type,
title=asset.original_file_name,
can_play=can_play,
can_expand=False,
thumbnail=f"/immich/{identifier.unique_id}/{asset.asset_id}/thumbnail/{thumb_mime_type}",
)
)
for asset in album_info.assets
if (mime_type := asset.original_mime_type)
and mime_type.startswith("video/")
)
return ret

View File

@ -26,6 +26,7 @@ from homeassistant.helpers import (
device_registry as dr,
)
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.typing import ConfigType
from .const import (
_LOGGER,
@ -46,7 +47,7 @@ from .const import (
)
from .helpers import _categorize_nodes, _categorize_programs
from .models import IsyConfigEntry, IsyData
from .services import async_setup_services, async_unload_services
from .services import async_setup_services
from .util import _async_cleanup_registry_entries
CONFIG_SCHEMA = vol.Schema(
@ -55,6 +56,14 @@ CONFIG_SCHEMA = vol.Schema(
)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the ISY 994 integration."""
async_setup_services(hass)
return True
async def async_setup_entry(hass: HomeAssistant, entry: IsyConfigEntry) -> bool:
"""Set up the ISY 994 integration."""
isy_config = entry.data
@ -167,9 +176,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: IsyConfigEntry) -> bool:
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _async_stop_auto_update)
)
# Register Integration-wide Services:
async_setup_services(hass)
return True
@ -221,9 +227,6 @@ async def async_unload_entry(hass: HomeAssistant, entry: IsyConfigEntry) -> bool
_LOGGER.debug("ISY Stopping Event Stream and automatic updates")
entry.runtime_data.root.websocket.stop()
if not hass.config_entries.async_loaded_entries(DOMAIN):
async_unload_services(hass)
return unload_ok

View File

@ -137,10 +137,6 @@ def async_get_entities(hass: HomeAssistant) -> dict[str, Entity]:
@callback
def async_setup_services(hass: HomeAssistant) -> None:
"""Create and register services for the ISY integration."""
existing_services = hass.services.async_services_for_domain(DOMAIN)
if existing_services and SERVICE_SEND_PROGRAM_COMMAND in existing_services:
# Integration-level services have already been added. Return.
return
async def async_send_program_command_service_handler(service: ServiceCall) -> None:
"""Handle a send program command service call."""
@ -230,18 +226,3 @@ def async_setup_services(hass: HomeAssistant) -> None:
schema=cv.make_entity_service_schema(SERVICE_RENAME_NODE_SCHEMA),
service_func=_async_rename_node,
)
@callback
def async_unload_services(hass: HomeAssistant) -> None:
"""Unload services for the ISY integration."""
existing_services = hass.services.async_services_for_domain(DOMAIN)
if not existing_services or SERVICE_SEND_PROGRAM_COMMAND not in existing_services:
return
_LOGGER.debug("Unloading ISY994 Services")
hass.services.async_remove(domain=DOMAIN, service=SERVICE_SEND_PROGRAM_COMMAND)
hass.services.async_remove(domain=DOMAIN, service=SERVICE_SEND_RAW_NODE_COMMAND)
hass.services.async_remove(domain=DOMAIN, service=SERVICE_SEND_NODE_COMMAND)
hass.services.async_remove(domain=DOMAIN, service=SERVICE_GET_ZWAVE_PARAMETER)
hass.services.async_remove(domain=DOMAIN, service=SERVICE_SET_ZWAVE_PARAMETER)

View File

@ -30,7 +30,7 @@ from .const import (
DOMAIN,
)
from .entity import JewishCalendarConfigEntry, JewishCalendarData
from .service import async_setup_services
from .services import async_setup_services
_LOGGER = logging.getLogger(__name__)
PLATFORMS: list[Platform] = [Platform.BINARY_SENSOR, Platform.SENSOR]

View File

@ -12,5 +12,5 @@
"integration_type": "hub",
"iot_class": "cloud_polling",
"loggers": ["pyatmo"],
"requirements": ["pyatmo==9.2.0"]
"requirements": ["pyatmo==9.2.1"]
}

View File

@ -8,5 +8,5 @@
"documentation": "https://www.home-assistant.io/integrations/ollama",
"integration_type": "service",
"iot_class": "local_polling",
"requirements": ["ollama==0.4.7"]
"requirements": ["ollama==0.5.1"]
}

View File

@ -121,11 +121,10 @@ def async_register_services(hass: HomeAssistant) -> None:
return {"files": [asdict(item_result) for item_result in upload_results]}
return None
if not hass.services.has_service(DOMAIN, UPLOAD_SERVICE):
hass.services.async_register(
DOMAIN,
UPLOAD_SERVICE,
async_handle_upload,
schema=UPLOAD_SERVICE_SCHEMA,
supports_response=SupportsResponse.OPTIONAL,
)
hass.services.async_register(
DOMAIN,
UPLOAD_SERVICE,
async_handle_upload,
schema=UPLOAD_SERVICE_SCHEMA,
supports_response=SupportsResponse.OPTIONAL,
)

View File

@ -13,7 +13,7 @@
"integration_type": "hub",
"iot_class": "local_polling",
"loggers": ["boto3", "botocore", "pyhumps", "pyoverkiz", "s3transfer"],
"requirements": ["pyoverkiz==1.17.1"],
"requirements": ["pyoverkiz==1.17.2"],
"zeroconf": [
{
"type": "_kizbox._tcp.local.",

View File

@ -5,14 +5,25 @@ from python_picnic_api2 import PicnicAPI
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_COUNTRY_CODE, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.typing import ConfigType
from .const import CONF_API, CONF_COORDINATOR, DOMAIN
from .coordinator import PicnicUpdateCoordinator
from .services import async_register_services
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
PLATFORMS = [Platform.SENSOR, Platform.TODO]
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up Picnic integration."""
await async_register_services(hass)
return True
def create_picnic_client(entry: ConfigEntry):
"""Create an instance of the PicnicAPI client."""
return PicnicAPI(
@ -37,9 +48,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
# Register the services
await async_register_services(hass)
return True

View File

@ -29,9 +29,6 @@ class PicnicServiceException(Exception):
async def async_register_services(hass: HomeAssistant) -> None:
"""Register services for the Picnic integration, if not registered yet."""
if hass.services.has_service(DOMAIN, SERVICE_ADD_PRODUCT_TO_CART):
return
async def async_add_product_service(call: ServiceCall):
api_client = await get_api_client(hass, call.data[ATTR_CONFIG_ENTRY_ID])
await handle_add_product(hass, api_client, call)

View File

@ -13,5 +13,5 @@
"iot_class": "cloud_polling",
"loggers": ["aiokem"],
"quality_scale": "silver",
"requirements": ["aiokem==0.5.12"]
"requirements": ["aiokem==1.0.1"]
}

View File

@ -7,7 +7,7 @@ from dataclasses import dataclass
from functools import partial
from typing import TYPE_CHECKING, Any, Final
from aioshelly.const import BLU_TRV_IDENTIFIER, MODEL_BLU_GATEWAY, RPC_GENERATIONS
from aioshelly.const import BLU_TRV_IDENTIFIER, MODEL_BLU_GATEWAY_G3, RPC_GENERATIONS
from aioshelly.exceptions import DeviceConnectionError, InvalidAuthError, RpcCallError
from homeassistant.components.button import (
@ -62,7 +62,7 @@ BUTTONS: Final[list[ShellyButtonDescription[Any]]] = [
translation_key="self_test",
entity_category=EntityCategory.DIAGNOSTIC,
press_action="trigger_shelly_gas_self_test",
supported=lambda coordinator: coordinator.device.model in SHELLY_GAS_MODELS,
supported=lambda coordinator: coordinator.model in SHELLY_GAS_MODELS,
),
ShellyButtonDescription[ShellyBlockCoordinator](
key="mute",
@ -70,7 +70,7 @@ BUTTONS: Final[list[ShellyButtonDescription[Any]]] = [
translation_key="mute",
entity_category=EntityCategory.CONFIG,
press_action="trigger_shelly_gas_mute",
supported=lambda coordinator: coordinator.device.model in SHELLY_GAS_MODELS,
supported=lambda coordinator: coordinator.model in SHELLY_GAS_MODELS,
),
ShellyButtonDescription[ShellyBlockCoordinator](
key="unmute",
@ -78,7 +78,7 @@ BUTTONS: Final[list[ShellyButtonDescription[Any]]] = [
translation_key="unmute",
entity_category=EntityCategory.CONFIG,
press_action="trigger_shelly_gas_unmute",
supported=lambda coordinator: coordinator.device.model in SHELLY_GAS_MODELS,
supported=lambda coordinator: coordinator.model in SHELLY_GAS_MODELS,
),
]
@ -89,7 +89,7 @@ BLU_TRV_BUTTONS: Final[list[ShellyButtonDescription]] = [
translation_key="calibrate",
entity_category=EntityCategory.CONFIG,
press_action="trigger_blu_trv_calibration",
supported=lambda coordinator: coordinator.device.model == MODEL_BLU_GATEWAY,
supported=lambda coordinator: coordinator.model == MODEL_BLU_GATEWAY_G3,
),
]
@ -160,6 +160,7 @@ async def async_setup_entry(
ShellyBluTrvButton(coordinator, button, id_)
for id_ in blutrv_key_ids
for button in BLU_TRV_BUTTONS
if button.supported(coordinator)
)
async_add_entities(entities)

View File

@ -12,7 +12,8 @@ from synology_dsm.exceptions import SynologyDSMNotLoggedInException
from homeassistant.const import CONF_MAC, CONF_SCAN_INTERVAL, CONF_VERIFY_SSL
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers import config_validation as cv, device_registry as dr
from homeassistant.helpers.typing import ConfigType
from .common import SynoApi, raise_config_entry_auth_error
from .const import (
@ -34,10 +35,20 @@ from .coordinator import (
SynologyDSMData,
SynologyDSMSwitchUpdateCoordinator,
)
from .service import async_setup_services
from .services import async_setup_services
_LOGGER = logging.getLogger(__name__)
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Synology DSM component."""
await async_setup_services(hass)
return True
async def async_setup_entry(hass: HomeAssistant, entry: SynologyDSMConfigEntry) -> bool:
"""Set up Synology DSM sensors."""
@ -89,9 +100,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: SynologyDSMConfigEntry)
details = EXCEPTION_UNKNOWN
raise ConfigEntryNotReady(details) from err
# Services
await async_setup_services(hass)
# For SSDP compat
if not entry.data.get(CONF_MAC):
hass.config_entries.async_update_entry(

View File

@ -6,7 +6,7 @@ aiodns==3.4.0
aiohasupervisor==0.3.1
aiohttp-asyncmdnsresolver==0.1.1
aiohttp-fast-zlib==0.2.3
aiohttp==3.12.6
aiohttp==3.12.7
aiohttp_cors==0.8.1
aiousbwatcher==1.1.1
aiozoneinfo==0.2.3
@ -32,7 +32,7 @@ cronsim==2.6
cryptography==45.0.3
dbus-fast==2.43.0
fnv-hash-fast==1.5.0
go2rtc-client==0.1.3b0
go2rtc-client==0.2.1
ha-ffmpeg==3.2.2
habluetooth==3.48.2
hass-nabucasa==0.101.0
@ -66,7 +66,7 @@ securetar==2025.2.1
SQLAlchemy==2.0.41
standard-aifc==3.13.0
standard-telnetlib==3.13.0
typing-extensions>=4.13.0,<5.0
typing-extensions>=4.14.0,<5.0
ulid-transform==1.4.0
urllib3>=1.26.5,<2
uv==0.7.1

View File

@ -28,7 +28,7 @@ dependencies = [
# change behavior based on presence of supervisor. Deprecated with #127228
# Lib can be removed with 2025.11
"aiohasupervisor==0.3.1",
"aiohttp==3.12.6",
"aiohttp==3.12.7",
"aiohttp_cors==0.8.1",
"aiohttp-fast-zlib==0.2.3",
"aiohttp-asyncmdnsresolver==0.1.1",
@ -111,7 +111,7 @@ dependencies = [
"SQLAlchemy==2.0.41",
"standard-aifc==3.13.0",
"standard-telnetlib==3.13.0",
"typing-extensions>=4.13.0,<5.0",
"typing-extensions>=4.14.0,<5.0",
"ulid-transform==1.4.0",
# Constrain urllib3 to ensure we deal with CVE-2020-26137 and CVE-2021-33503
# Temporary setting an upper bound, to prevent compat issues with urllib3>=2
@ -530,18 +530,20 @@ filterwarnings = [
# https://github.com/DataDog/datadogpy/pull/290 - >=0.23.0
"ignore:invalid escape sequence:SyntaxWarning:.*datadog.dogstatsd.base",
# https://github.com/DataDog/datadogpy/pull/566/files - >=0.37.0
"ignore:pkg_resources is deprecated as an API:DeprecationWarning:datadog.util.compat",
"ignore:pkg_resources is deprecated as an API:UserWarning:datadog.util.compat",
# https://github.com/httplib2/httplib2/pull/226 - >=0.21.0
"ignore:ssl.PROTOCOL_TLS is deprecated:DeprecationWarning:httplib2",
# https://github.com/influxdata/influxdb-client-python/issues/603 >=1.45.0
# https://github.com/influxdata/influxdb-client-python/pull/652
"ignore:datetime.*utcfromtimestamp\\(\\) is deprecated and scheduled for removal:DeprecationWarning:influxdb_client.client.write.point",
# https://github.com/majuss/lupupy/pull/15 - >0.3.2
"ignore:\"is not\" with 'str' literal. Did you mean \"!=\"?:SyntaxWarning:.*lupupy.devices.alarm",
# https://github.com/nextcord/nextcord/pull/1095 - >=3.0.0
"ignore:pkg_resources is deprecated as an API:DeprecationWarning:nextcord.health_check",
"ignore:pkg_resources is deprecated as an API:UserWarning:nextcord.health_check",
# https://github.com/vacanza/python-holidays/discussions/1800 - >1.0.0
"ignore::DeprecationWarning:holidays",
# https://github.com/ReactiveX/RxPY/pull/716 - >4.0.4
"ignore:datetime.*utcfromtimestamp\\(\\) is deprecated and scheduled for removal:DeprecationWarning:reactivex.internal.constants",
# https://github.com/postlund/pyatv/issues/2645 - >0.16.0
# https://github.com/postlund/pyatv/pull/2664
"ignore:Protobuf gencode .* exactly one major version older than the runtime version 6.* at pyatv:UserWarning:google.protobuf.runtime_version",
# https://github.com/rytilahti/python-miio/pull/1809 - >=0.6.0.dev0
"ignore:datetime.*utcnow\\(\\) is deprecated and scheduled for removal:DeprecationWarning:miio.protocol",
"ignore:datetime.*utcnow\\(\\) is deprecated and scheduled for removal:DeprecationWarning:miio.miioprotocol",
@ -549,6 +551,8 @@ filterwarnings = [
"ignore:functools.partial will be a method descriptor in future Python versions; wrap it in enum.member\\(\\) if you want to preserve the old behavior:FutureWarning:miio.miot_device",
# https://github.com/okunishinishi/python-stringcase/commit/6a5c5bbd3fe5337862abc7fd0853a0f36e18b2e1 - >1.2.0
"ignore:invalid escape sequence:SyntaxWarning:.*stringcase",
# https://github.com/xchwarze/samsung-tv-ws-api/pull/151 - >2.7.2 - 2024-12-06 # wrong stacklevel in aiohttp
"ignore:verify_ssl is deprecated, use ssl=False instead:DeprecationWarning:aiohttp.client",
# -- other
# Locale changes might take some time to resolve upstream
@ -580,6 +584,8 @@ filterwarnings = [
"ignore:getReadersFromUrls is deprecated. Please use get_readers_from_urls instead:DeprecationWarning:pysnmp.smi.compiler",
# https://github.com/Python-roborock/python-roborock/issues/305 - 2.18.0 - 2025-04-06
"ignore:Callback API version 1 is deprecated, update to latest version:DeprecationWarning:roborock.cloud_api",
# https://github.com/Teslemetry/python-tesla-fleet-api - v1.1.1 - 2025-05-29
"ignore:Protobuf gencode .* exactly one major version older than the runtime version 6.* at (car_server|common|errors|keys|managed_charging|signatures|universal_message|vcsec|vehicle):UserWarning:google.protobuf.runtime_version",
# https://github.com/briis/pyweatherflowudp/blob/v1.4.5/pyweatherflowudp/const.py#L20 - v1.4.5 - 2023-10-10
"ignore:This function will be removed in future versions of pint:DeprecationWarning:pyweatherflowudp.const",
# New in aiohttp - v3.9.0
@ -602,14 +608,12 @@ filterwarnings = [
# https://pypi.org/project/sleekxmppfs/ - v1.4.1 - 2022-08-18
"ignore:invalid escape sequence:SyntaxWarning:.*sleekxmppfs.thirdparty.mini_dateutil", # codespell:ignore thirdparty
# - pkg_resources
# https://pypi.org/project/aiomusiccast/ - v0.14.8 - 2023-03-20
"ignore:pkg_resources is deprecated as an API:DeprecationWarning:aiomusiccast",
# https://github.com/eavanvalkenburg/pysiaalarm/blob/v3.1.1/src/pysiaalarm/data/data.py#L7 - v3.1.1 - 2023-04-17
"ignore:pkg_resources is deprecated as an API:DeprecationWarning:pysiaalarm.data.data",
"ignore:pkg_resources is deprecated as an API:UserWarning:pysiaalarm.data.data",
# https://pypi.org/project/pybotvac/ - v0.0.26 - 2025-02-26
"ignore:pkg_resources is deprecated as an API:DeprecationWarning:pybotvac.version",
"ignore:pkg_resources is deprecated as an API:UserWarning:pybotvac.version",
# https://github.com/home-assistant-ecosystem/python-mystrom/blob/2.2.0/pymystrom/__init__.py#L10 - v2.2.0 - 2023-05-21
"ignore:pkg_resources is deprecated as an API:DeprecationWarning:pymystrom",
"ignore:pkg_resources is deprecated as an API:UserWarning:pymystrom",
# -- New in Python 3.13
# https://github.com/kurtmckee/feedparser/pull/389 - >6.0.11
@ -640,8 +644,6 @@ filterwarnings = [
"ignore:datetime.*utcnow\\(\\) is deprecated and scheduled for removal:DeprecationWarning:directv.models",
# https://pypi.org/project/enocean/ - v0.50.1 (installed) -> v0.60.1 - 2021-06-18
"ignore:It looks like you're using an HTML parser to parse an XML document:UserWarning:enocean.protocol.eep",
# https://pypi.org/project/httpsig/ - v1.3.0 - 2018-11-28
"ignore:pkg_resources is deprecated as an API:DeprecationWarning:httpsig",
# https://pypi.org/project/influxdb/ - v5.3.2 - 2024-04-18 (archived)
"ignore:datetime.*utcfromtimestamp\\(\\) is deprecated and scheduled for removal:DeprecationWarning:influxdb.line_protocol",
# https://pypi.org/project/lark-parser/ - v0.12.0 - 2021-08-30 -> moved to `lark`
@ -657,7 +659,7 @@ filterwarnings = [
# https://pypi.org/project/opuslib/ - v3.0.1 - 2018-01-16
"ignore:\"is not\" with 'int' literal. Did you mean \"!=\"?:SyntaxWarning:.*opuslib.api.decoder",
# https://pypi.org/project/pilight/ - v0.1.1 - 2016-10-19
"ignore:pkg_resources is deprecated as an API:DeprecationWarning:pilight",
"ignore:pkg_resources is deprecated as an API:UserWarning:pilight",
# https://pypi.org/project/plumlightpad/ - v0.0.11 - 2018-10-16
"ignore:invalid escape sequence:SyntaxWarning:.*plumlightpad.plumdiscovery",
"ignore:\"is\" with 'int' literal. Did you mean \"==\"?:SyntaxWarning:.*plumlightpad.(lightpad|logicalload)",
@ -672,8 +674,6 @@ filterwarnings = [
# https://pypi.org/project/pyqwikswitch/ - v0.94 - 2019-08-19
"ignore:client.loop property is deprecated:DeprecationWarning:pyqwikswitch.async_",
"ignore:with timeout\\(\\) is deprecated:DeprecationWarning:pyqwikswitch.async_",
# https://pypi.org/project/Rx/ - v3.2.0 - 2021-04-25
"ignore:datetime.*utcfromtimestamp\\(\\) is deprecated and scheduled for removal:DeprecationWarning:rx.internal.constants",
# https://pypi.org/project/rxv/ - v0.7.0 - 2021-10-10
"ignore:defusedxml.cElementTree is deprecated, import from defusedxml.ElementTree instead:DeprecationWarning:rxv.ssdp",
]

4
requirements.txt generated
View File

@ -5,7 +5,7 @@
# Home Assistant Core
aiodns==3.4.0
aiohasupervisor==0.3.1
aiohttp==3.12.6
aiohttp==3.12.7
aiohttp_cors==0.8.1
aiohttp-fast-zlib==0.2.3
aiohttp-asyncmdnsresolver==0.1.1
@ -51,7 +51,7 @@ securetar==2025.2.1
SQLAlchemy==2.0.41
standard-aifc==3.13.0
standard-telnetlib==3.13.0
typing-extensions>=4.13.0,<5.0
typing-extensions>=4.14.0,<5.0
ulid-transform==1.4.0
urllib3>=1.26.5,<2
uv==0.7.1

16
requirements_all.txt generated
View File

@ -182,7 +182,7 @@ aioairzone-cloud==0.6.12
aioairzone==1.0.0
# homeassistant.components.amazon_devices
aioamazondevices==3.0.4
aioamazondevices==3.0.5
# homeassistant.components.ambient_network
# homeassistant.components.ambient_station
@ -268,7 +268,7 @@ aiohasupervisor==0.3.1
aiohomeconnect==0.17.1
# homeassistant.components.homekit_controller
aiohomekit==3.2.14
aiohomekit==3.2.15
# homeassistant.components.mcp_server
aiohttp_sse==2.2.0
@ -289,7 +289,7 @@ aiokafka==0.10.0
aiokef==0.2.16
# homeassistant.components.rehlko
aiokem==0.5.12
aiokem==1.0.1
# homeassistant.components.lifx
aiolifx-effects==0.3.2
@ -1026,7 +1026,7 @@ gitterpy==0.1.7
glances-api==0.8.0
# homeassistant.components.go2rtc
go2rtc-client==0.1.3b0
go2rtc-client==0.2.1
# homeassistant.components.goalzero
goalzero==0.2.2
@ -1572,7 +1572,7 @@ oemthermostat==1.1.1
ohme==1.5.1
# homeassistant.components.ollama
ollama==0.4.7
ollama==0.5.1
# homeassistant.components.omnilogic
omnilogic==0.4.5
@ -1841,7 +1841,7 @@ pyasuswrt==0.1.21
pyatag==0.3.5.3
# homeassistant.components.netatmo
pyatmo==9.2.0
pyatmo==9.2.1
# homeassistant.components.apple_tv
pyatv==0.16.0
@ -2221,7 +2221,7 @@ pyotgw==2.2.2
pyotp==2.8.0
# homeassistant.components.overkiz
pyoverkiz==1.17.1
pyoverkiz==1.17.2
# homeassistant.components.onewire
pyownet==0.10.0.post1
@ -2434,7 +2434,7 @@ python-google-drive-api==0.1.0
python-homeassistant-analytics==0.9.0
# homeassistant.components.homewizard
python-homewizard-energy==v8.3.2
python-homewizard-energy==8.3.3
# homeassistant.components.hp_ilo
python-hpilo==4.4.3

View File

@ -10,7 +10,7 @@
astroid==3.3.10
coverage==7.8.2
freezegun==1.5.2
go2rtc-client==0.1.3b0
go2rtc-client==0.2.1
license-expression==30.4.1
mock-open==1.4.0
mypy-dev==1.17.0a2

View File

@ -170,7 +170,7 @@ aioairzone-cloud==0.6.12
aioairzone==1.0.0
# homeassistant.components.amazon_devices
aioamazondevices==3.0.4
aioamazondevices==3.0.5
# homeassistant.components.ambient_network
# homeassistant.components.ambient_station
@ -253,7 +253,7 @@ aiohasupervisor==0.3.1
aiohomeconnect==0.17.1
# homeassistant.components.homekit_controller
aiohomekit==3.2.14
aiohomekit==3.2.15
# homeassistant.components.mcp_server
aiohttp_sse==2.2.0
@ -271,7 +271,7 @@ aioimmich==0.8.0
aiokafka==0.10.0
# homeassistant.components.rehlko
aiokem==0.5.12
aiokem==1.0.1
# homeassistant.components.lifx
aiolifx-effects==0.3.2
@ -887,7 +887,7 @@ gios==6.0.0
glances-api==0.8.0
# homeassistant.components.go2rtc
go2rtc-client==0.1.3b0
go2rtc-client==0.2.1
# homeassistant.components.goalzero
goalzero==0.2.2
@ -1334,7 +1334,7 @@ odp-amsterdam==6.1.1
ohme==1.5.1
# homeassistant.components.ollama
ollama==0.4.7
ollama==0.5.1
# homeassistant.components.omnilogic
omnilogic==0.4.5
@ -1540,7 +1540,7 @@ pyasuswrt==0.1.21
pyatag==0.3.5.3
# homeassistant.components.netatmo
pyatmo==9.2.0
pyatmo==9.2.1
# homeassistant.components.apple_tv
pyatv==0.16.0
@ -1842,7 +1842,7 @@ pyotgw==2.2.2
pyotp==2.8.0
# homeassistant.components.overkiz
pyoverkiz==1.17.1
pyoverkiz==1.17.2
# homeassistant.components.onewire
pyownet==0.10.0.post1
@ -2007,7 +2007,7 @@ python-google-drive-api==0.1.0
python-homeassistant-analytics==0.9.0
# homeassistant.components.homewizard
python-homewizard-energy==v8.3.2
python-homewizard-energy==8.3.3
# homeassistant.components.izone
python-izone==1.2.9

View File

@ -1,5 +1,5 @@
# Automatically generated from .pre-commit-config.yaml by gen_requirements_all.py, do not edit
codespell==2.4.1
ruff==0.11.0
yamllint==1.35.1
ruff==0.11.12
yamllint==1.37.1

View File

@ -249,6 +249,10 @@ GENERATED_MESSAGE = (
f"# Automatically generated by {Path(__file__).name}, do not edit\n\n"
)
MAP_HOOK_ID_TO_PACKAGE = {
"ruff-check": "ruff",
}
IGNORE_PRE_COMMIT_HOOK_ID = (
"check-executables-have-shebangs",
"check-json",
@ -523,7 +527,8 @@ def requirements_pre_commit_output() -> str:
rev: str = repo["rev"]
for hook in repo["hooks"]:
if hook["id"] not in IGNORE_PRE_COMMIT_HOOK_ID:
reqs.append(f"{hook['id']}=={rev.lstrip('v')}")
pkg = MAP_HOOK_ID_TO_PACKAGE.get(hook["id"]) or hook["id"]
reqs.append(f"{pkg}=={rev.lstrip('v')}")
reqs.extend(x for x in hook.get("additional_dependencies", ()))
output = [
f"# Automatically generated "

View File

@ -24,8 +24,8 @@ RUN --mount=from=ghcr.io/astral-sh/uv:0.7.1,source=/uv,target=/bin/uv \
--no-cache \
-c /usr/src/homeassistant/homeassistant/package_constraints.txt \
-r /usr/src/homeassistant/requirements.txt \
stdlib-list==0.10.0 pipdeptree==2.26.1 tqdm==4.67.1 ruff==0.11.0 \
PyTurboJPEG==1.8.0 go2rtc-client==0.1.3b0 ha-ffmpeg==3.2.2 hassil==2.2.3 home-assistant-intents==2025.5.28 mutagen==1.47.0 pymicro-vad==1.0.1 pyspeex-noise==1.0.2
stdlib-list==0.10.0 pipdeptree==2.26.1 tqdm==4.67.1 ruff==0.11.12 \
PyTurboJPEG==1.8.0 go2rtc-client==0.2.1 ha-ffmpeg==3.2.2 hassil==2.2.3 home-assistant-intents==2025.5.28 mutagen==1.47.0 pymicro-vad==1.0.1 pyspeex-noise==1.0.2
LABEL "name"="hassfest"
LABEL "maintainer"="Home Assistant <hello@home-assistant.io>"

View File

@ -26,6 +26,7 @@ from .model import Config, Integration
PACKAGE_CHECK_VERSION_RANGE = {
"aiohttp": "SemVer",
"attrs": "CalVer",
"awesomeversion": "CalVer",
"grpcio": "SemVer",
"httpx": "SemVer",
"mashumaro": "SemVer",
@ -40,13 +41,9 @@ PACKAGE_CHECK_VERSION_RANGE_EXCEPTIONS: dict[str, dict[str, set[str]]] = {
# - domain is the integration domain
# - package is the package (can be transitive) referencing the dependency
# - dependencyX should be the name of the referenced dependency
"ollama": {
# https://github.com/ollama/ollama-python/pull/445 (not yet released)
"ollama": {"httpx"}
},
"overkiz": {
# https://github.com/iMicknl/python-overkiz-api/issues/1644 (not yet released)
"pyoverkiz": {"attrs"},
"mealie": {
# https://github.com/joostlek/python-mealie/pull/490
"aiomealie": {"awesomeversion"}
},
}
@ -333,14 +330,6 @@ PYTHON_VERSION_CHECK_EXCEPTIONS: dict[str, dict[str, set[str]]] = {
# https://github.com/EuleMitKeule/eq3btsmart/releases/tag/2.0.0
"homeassistant": {"eq3btsmart"}
},
"homekit_controller": {
# https://github.com/Jc2k/aiohomekit/issues/456
"homeassistant": {"aiohomekit"}
},
"netatmo": {
# https://github.com/jabesq-org/pyatmo/pull/533 (not yet released)
"homeassistant": {"pyatmo"}
},
"python_script": {
# Security audits are needed for each Python version
"homeassistant": {"restrictedpython"}

View File

@ -196,6 +196,7 @@ EXCEPTIONS = {
"maxcube-api", # https://github.com/uebelack/python-maxcube-api/pull/48
"neurio", # https://github.com/jordanh/neurio-python/pull/13
"nsw-fuel-api-client", # https://github.com/nickw444/nsw-fuel-api-client/pull/14
"ollama", # https://github.com/ollama/ollama-python/pull/526
"pigpio", # https://github.com/joan2937/pigpio/pull/608
"pymitv", # MIT
"pybbox", # https://github.com/HydrelioxGitHub/pybbox/pull/5

View File

@ -15,7 +15,7 @@ printf "%s\n" $files
echo "=============="
echo "LINT with ruff"
echo "=============="
pre-commit run ruff --files $files
pre-commit run ruff-check --files $files
echo "================"
echo "LINT with pylint"
echo "================"