Skip to content

[pull] dev from home-assistant:dev #775

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion homeassistant/components/compensation/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
"documentation": "https://www.home-assistant.io/integrations/compensation",
"iot_class": "calculated",
"quality_scale": "legacy",
"requirements": ["numpy==2.2.6"]
"requirements": ["numpy==2.3.0"]
}
27 changes: 5 additions & 22 deletions homeassistant/components/enphase_envoy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,25 @@

from __future__ import annotations

import httpx
from pyenphase import Envoy

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.httpx_client import get_async_client

from .const import (
DOMAIN,
OPTION_DISABLE_KEEP_ALIVE,
OPTION_DISABLE_KEEP_ALIVE_DEFAULT_VALUE,
PLATFORMS,
)
from homeassistant.helpers.aiohttp_client import async_create_clientsession

from .const import DOMAIN, PLATFORMS
from .coordinator import EnphaseConfigEntry, EnphaseUpdateCoordinator


async def async_setup_entry(hass: HomeAssistant, entry: EnphaseConfigEntry) -> bool:
"""Set up Enphase Envoy from a config entry."""

host = entry.data[CONF_HOST]
options = entry.options
envoy = (
Envoy(
host,
httpx.AsyncClient(
verify=False, limits=httpx.Limits(max_keepalive_connections=0)
),
)
if options.get(
OPTION_DISABLE_KEEP_ALIVE, OPTION_DISABLE_KEEP_ALIVE_DEFAULT_VALUE
)
else Envoy(host, get_async_client(hass, verify_ssl=False))
)
session = async_create_clientsession(hass, verify_ssl=False)
envoy = Envoy(host, session)
coordinator = EnphaseUpdateCoordinator(hass, envoy, entry)

await coordinator.async_config_entry_first_refresh()
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/enphase_envoy/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
CONF_USERNAME,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.httpx_client import get_async_client
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo
from homeassistant.helpers.typing import VolDictType

Expand Down Expand Up @@ -63,7 +63,7 @@ async def validate_input(
description_placeholders: dict[str, str],
) -> Envoy:
"""Validate the user input allows us to connect."""
envoy = Envoy(host, get_async_client(hass, verify_ssl=False))
envoy = Envoy(host, async_get_clientsession(hass, verify_ssl=False))
try:
await envoy.setup()
await envoy.authenticate(username=username, password=password)
Expand Down
9 changes: 5 additions & 4 deletions homeassistant/components/enphase_envoy/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from datetime import datetime
from typing import TYPE_CHECKING, Any

from aiohttp import ClientResponse
from attr import asdict
from pyenphase.envoy import Envoy
from pyenphase.exceptions import EnvoyError
Expand Down Expand Up @@ -69,14 +70,14 @@ async def _get_fixture_collection(envoy: Envoy, serial: str) -> dict[str, Any]:

for end_point in end_points:
try:
response = await envoy.request(end_point)
fixture_data[end_point] = response.text.replace("\n", "").replace(
serial, CLEAN_TEXT
response: ClientResponse = await envoy.request(end_point)
fixture_data[end_point] = (
(await response.text()).replace("\n", "").replace(serial, CLEAN_TEXT)
)
fixture_data[f"{end_point}_log"] = json_dumps(
{
"headers": dict(response.headers.items()),
"code": response.status_code,
"code": response.status,
}
)
except EnvoyError as err:
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/enphase_envoy/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from collections.abc import Callable, Coroutine
from typing import Any, Concatenate

from httpx import HTTPError
from aiohttp import ClientError
from pyenphase import EnvoyData
from pyenphase.exceptions import EnvoyError

Expand All @@ -16,7 +16,7 @@
from .const import DOMAIN
from .coordinator import EnphaseUpdateCoordinator

ACTIONERRORS = (EnvoyError, HTTPError)
ACTIONERRORS = (EnvoyError, ClientError)


class EnvoyBaseEntity(CoordinatorEntity[EnphaseUpdateCoordinator]):
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/enphase_envoy/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"iot_class": "local_polling",
"loggers": ["pyenphase"],
"quality_scale": "platinum",
"requirements": ["pyenphase==1.26.1"],
"requirements": ["pyenphase==2.0.1"],
"zeroconf": [
{
"type": "_enphase-envoy._tcp.local."
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/holiday/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/holiday",
"iot_class": "local_polling",
"requirements": ["holidays==0.73", "babel==2.15.0"]
"requirements": ["holidays==0.74", "babel==2.15.0"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/iqvia/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"integration_type": "service",
"iot_class": "cloud_polling",
"loggers": ["pyiqvia"],
"requirements": ["numpy==2.2.6", "pyiqvia==2022.04.0"]
"requirements": ["numpy==2.3.0", "pyiqvia==2022.04.0"]
}
6 changes: 3 additions & 3 deletions homeassistant/components/onvif/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from http import HTTPStatus
import logging

from httpx import RequestError
import aiohttp
from onvif.exceptions import ONVIFError
from onvif.util import is_auth_error, stringify_onvif_error
from zeep.exceptions import Fault, TransportError
Expand Down Expand Up @@ -49,7 +49,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
await device.async_setup()
if not entry.data.get(CONF_SNAPSHOT_AUTH):
await async_populate_snapshot_auth(hass, device, entry)
except RequestError as err:
except (TimeoutError, aiohttp.ClientError) as err:
await device.device.close()
raise ConfigEntryNotReady(
f"Could not connect to camera {device.device.host}:{device.device.port}: {err}"
Expand Down Expand Up @@ -119,7 +119,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
if device.capabilities.events and device.events.started:
try:
await device.events.async_stop()
except (ONVIFError, Fault, RequestError, TransportError):
except (TimeoutError, ONVIFError, Fault, aiohttp.ClientError, TransportError):
LOGGER.warning("Error while stopping events: %s", device.name)

return await hass.config_entries.async_unload_platforms(entry, device.platforms)
Expand Down
11 changes: 9 additions & 2 deletions homeassistant/components/onvif/const.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
"""Constants for the onvif component."""

import asyncio
import logging

from httpx import RequestError
import aiohttp
from onvif.exceptions import ONVIFError
from zeep.exceptions import Fault, TransportError

Expand Down Expand Up @@ -48,4 +49,10 @@

# Some cameras don't support the GetServiceCapabilities call
# and will return a 404 error which is caught by TransportError
GET_CAPABILITIES_EXCEPTIONS = (ONVIFError, Fault, RequestError, TransportError)
GET_CAPABILITIES_EXCEPTIONS = (
ONVIFError,
Fault,
aiohttp.ClientError,
asyncio.TimeoutError,
TransportError,
)
6 changes: 3 additions & 3 deletions homeassistant/components/onvif/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import time
from typing import Any

from httpx import RequestError
import aiohttp
import onvif
from onvif import ONVIFCamera
from onvif.exceptions import ONVIFError
Expand Down Expand Up @@ -235,7 +235,7 @@ async def async_check_date_and_time(self) -> None:
LOGGER.debug("%s: Retrieving current device date/time", self.name)
try:
device_time = await device_mgmt.GetSystemDateAndTime()
except (RequestError, Fault) as err:
except (TimeoutError, aiohttp.ClientError, Fault) as err:
LOGGER.warning(
"Couldn't get device '%s' date/time. Error: %s", self.name, err
)
Expand Down Expand Up @@ -303,7 +303,7 @@ async def async_check_date_and_time(self) -> None:
# Set Date and Time ourselves if Date and Time is set manually in the camera.
try:
await self.async_manually_set_date_and_time()
except (RequestError, TransportError, IndexError, Fault):
except (TimeoutError, aiohttp.ClientError, TransportError, IndexError, Fault):
LOGGER.warning("%s: Could not sync date/time on this camera", self.name)
self._async_log_time_out_of_sync(cam_date_utc, system_date)

Expand Down
32 changes: 25 additions & 7 deletions homeassistant/components/onvif/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
from collections.abc import Callable
import datetime as dt

import aiohttp
from aiohttp.web import Request
from httpx import RemoteProtocolError, RequestError, TransportError
from onvif import ONVIFCamera
from onvif.client import (
NotificationManager,
Expand All @@ -16,7 +16,7 @@
)
from onvif.exceptions import ONVIFError
from onvif.util import stringify_onvif_error
from zeep.exceptions import Fault, ValidationError, XMLParseError
from zeep.exceptions import Fault, TransportError, ValidationError, XMLParseError

from homeassistant.components import webhook
from homeassistant.config_entries import ConfigEntry
Expand All @@ -34,10 +34,23 @@
UNHANDLED_TOPICS: set[str] = {"tns1:MediaControl/VideoEncoderConfiguration"}

SUBSCRIPTION_ERRORS = (Fault, TimeoutError, TransportError)
CREATE_ERRORS = (ONVIFError, Fault, RequestError, XMLParseError, ValidationError)
CREATE_ERRORS = (
ONVIFError,
Fault,
aiohttp.ClientError,
asyncio.TimeoutError,
XMLParseError,
ValidationError,
)
SET_SYNCHRONIZATION_POINT_ERRORS = (*SUBSCRIPTION_ERRORS, TypeError)
UNSUBSCRIBE_ERRORS = (XMLParseError, *SUBSCRIPTION_ERRORS)
RENEW_ERRORS = (ONVIFError, RequestError, XMLParseError, *SUBSCRIPTION_ERRORS)
RENEW_ERRORS = (
ONVIFError,
aiohttp.ClientError,
asyncio.TimeoutError,
XMLParseError,
*SUBSCRIPTION_ERRORS,
)
#
# We only keep the subscription alive for 10 minutes, and will keep
# renewing it every 8 minutes. This is to avoid the camera
Expand Down Expand Up @@ -372,13 +385,13 @@ async def _async_pull_messages(self) -> None:
"%s: PullPoint skipped because Home Assistant is not running yet",
self._name,
)
except RemoteProtocolError as err:
except aiohttp.ServerDisconnectedError as err:
# Either a shutdown event or the camera closed the connection. Because
# http://datatracker.ietf.org/doc/html/rfc2616#section-8.1.4 allows the server
# to close the connection at any time, we treat this as a normal. Some
# cameras may close the connection if there are no messages to pull.
LOGGER.debug(
"%s: PullPoint subscription encountered a remote protocol error "
"%s: PullPoint subscription encountered a server disconnected error "
"(this is normal for some cameras): %s",
self._name,
stringify_onvif_error(err),
Expand All @@ -394,7 +407,12 @@ async def _async_pull_messages(self) -> None:
# Treat errors as if the camera restarted. Assume that the pullpoint
# subscription is no longer valid.
self._pullpoint_manager.resume()
except (XMLParseError, RequestError, TimeoutError, TransportError) as err:
except (
XMLParseError,
aiohttp.ClientError,
TimeoutError,
TransportError,
) as err:
LOGGER.debug(
"%s: PullPoint subscription encountered an unexpected error and will be retried "
"(this is normal for some cameras): %s",
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/onvif/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"documentation": "https://www.home-assistant.io/integrations/onvif",
"iot_class": "local_push",
"loggers": ["onvif", "wsdiscovery", "zeep"],
"requirements": ["onvif-zeep-async==3.2.5", "WSDiscovery==2.1.2"]
"requirements": ["onvif-zeep-async==4.0.1", "WSDiscovery==2.1.2"]
}
6 changes: 3 additions & 3 deletions homeassistant/components/rest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import logging
from typing import Any

import httpx
import aiohttp
import voluptuous as vol

from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
Expand Down Expand Up @@ -211,10 +211,10 @@ def create_rest_data_from_config(hass: HomeAssistant, config: ConfigType) -> Res
if not resource:
raise HomeAssistantError("Resource not set for RestData")

auth: httpx.DigestAuth | tuple[str, str] | None = None
auth: aiohttp.DigestAuthMiddleware | tuple[str, str] | None = None
if username and password:
if config.get(CONF_AUTHENTICATION) == HTTP_DIGEST_AUTHENTICATION:
auth = httpx.DigestAuth(username, password)
auth = aiohttp.DigestAuthMiddleware(username, password)
else:
auth = (username, password)

Expand Down
Loading