Skip to content

Commit

Permalink
2024.8.2 (#124069)
Browse files Browse the repository at this point in the history
  • Loading branch information
frenck committed Aug 16, 2024
2 parents ae4fc95 + a2027fc commit 94516de
Show file tree
Hide file tree
Showing 77 changed files with 993 additions and 304 deletions.
2 changes: 1 addition & 1 deletion homeassistant/components/aemet/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/aemet",
"iot_class": "cloud_polling",
"loggers": ["aemet_opendata"],
"requirements": ["AEMET-OpenData==0.5.3"]
"requirements": ["AEMET-OpenData==0.5.4"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/airzone/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ async def async_step_dhcp(
)
try:
await airzone.get_version()
except AirzoneError as err:
except (AirzoneError, TimeoutError) as err:
raise AbortFlow("cannot_connect") from err

return await self.async_step_discovered_connection()
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/airzone_cloud/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/airzone_cloud",
"iot_class": "cloud_push",
"loggers": ["aioairzone_cloud"],
"requirements": ["aioairzone-cloud==0.6.1"]
"requirements": ["aioairzone-cloud==0.6.2"]
}
37 changes: 20 additions & 17 deletions homeassistant/components/bluesound/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,6 @@ def __init__(
self._status: Status | None = None
self._inputs: list[Input] = []
self._presets: list[Preset] = []
self._is_online = False
self._muted = False
self._master: BluesoundPlayer | None = None
self._is_master = False
Expand Down Expand Up @@ -312,20 +311,24 @@ async def force_update_sync_status(self) -> bool:

async def _start_poll_command(self):
"""Loop which polls the status of the player."""
try:
while True:
while True:
try:
await self.async_update_status()

except (TimeoutError, ClientError):
_LOGGER.error("Node %s:%s is offline, retrying later", self.host, self.port)
await asyncio.sleep(NODE_OFFLINE_CHECK_TIMEOUT)
self.start_polling()

except CancelledError:
_LOGGER.debug("Stopping the polling of node %s:%s", self.host, self.port)
except Exception:
_LOGGER.exception("Unexpected error in %s:%s", self.host, self.port)
raise
except (TimeoutError, ClientError):
_LOGGER.error(
"Node %s:%s is offline, retrying later", self.host, self.port
)
await asyncio.sleep(NODE_OFFLINE_CHECK_TIMEOUT)
except CancelledError:
_LOGGER.debug(
"Stopping the polling of node %s:%s", self.host, self.port
)
return
except Exception:
_LOGGER.exception(
"Unexpected error in %s:%s, retrying later", self.host, self.port
)
await asyncio.sleep(NODE_OFFLINE_CHECK_TIMEOUT)

async def async_added_to_hass(self) -> None:
"""Start the polling task."""
Expand All @@ -348,7 +351,7 @@ async def async_will_remove_from_hass(self) -> None:

async def async_update(self) -> None:
"""Update internal status of the entity."""
if not self._is_online:
if not self.available:
return

with suppress(TimeoutError):
Expand All @@ -365,7 +368,7 @@ async def async_update_status(self):
try:
status = await self._player.status(etag=etag, poll_timeout=120, timeout=125)

self._is_online = True
self._attr_available = True
self._last_status_update = dt_util.utcnow()
self._status = status

Expand Down Expand Up @@ -394,7 +397,7 @@ async def async_update_status(self):

self.async_write_ha_state()
except (TimeoutError, ClientError):
self._is_online = False
self._attr_available = False
self._last_status_update = None
self._status = None
self.async_write_ha_state()
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/bluetooth/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"requirements": [
"bleak==0.22.2",
"bleak-retry-connector==3.5.0",
"bluetooth-adapters==0.19.3",
"bluetooth-adapters==0.19.4",
"bluetooth-auto-recovery==1.4.2",
"bluetooth-data-tools==1.19.4",
"dbus-fast==2.22.1",
Expand Down
3 changes: 1 addition & 2 deletions homeassistant/components/concord232/alarm_control_panel.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
"""Support for Concord232 alarm control panels."""

# mypy: ignore-errors
from __future__ import annotations

import datetime
import logging

# from concord232 import client as concord232_client
from concord232 import client as concord232_client
import requests
import voluptuous as vol

Expand Down
3 changes: 1 addition & 2 deletions homeassistant/components/concord232/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
"""Support for exposing Concord232 elements as sensors."""

# mypy: ignore-errors
from __future__ import annotations

import datetime
import logging

# from concord232 import client as concord232_client
from concord232 import client as concord232_client
import requests
import voluptuous as vol

Expand Down
3 changes: 1 addition & 2 deletions homeassistant/components/concord232/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
"domain": "concord232",
"name": "Concord232",
"codeowners": [],
"disabled": "This integration is disabled because it uses non-open source code to operate.",
"documentation": "https://www.home-assistant.io/integrations/concord232",
"iot_class": "local_polling",
"loggers": ["concord232", "stevedore"],
"requirements": ["concord232==0.15"]
"requirements": ["concord232==0.15.1"]
}
5 changes: 0 additions & 5 deletions homeassistant/components/concord232/ruff.toml

This file was deleted.

2 changes: 1 addition & 1 deletion homeassistant/components/daikin/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
"documentation": "https://www.home-assistant.io/integrations/daikin",
"iot_class": "local_polling",
"loggers": ["pydaikin"],
"requirements": ["pydaikin==2.13.2"],
"requirements": ["pydaikin==2.13.4"],
"zeroconf": ["_dkapi._tcp.local."]
}
14 changes: 9 additions & 5 deletions homeassistant/components/ecovacs/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

from functools import partial
import logging
import ssl
from typing import Any, cast
Expand Down Expand Up @@ -105,11 +106,14 @@ async def _validate_input(
if not user_input.get(CONF_VERIFY_MQTT_CERTIFICATE, True) and mqtt_url:
ssl_context = get_default_no_verify_context()

mqtt_config = create_mqtt_config(
device_id=device_id,
country=country,
override_mqtt_url=mqtt_url,
ssl_context=ssl_context,
mqtt_config = await hass.async_add_executor_job(
partial(
create_mqtt_config,
device_id=device_id,
country=country,
override_mqtt_url=mqtt_url,
ssl_context=ssl_context,
)
)

client = MqttClient(mqtt_config, authenticator)
Expand Down
36 changes: 22 additions & 14 deletions homeassistant/components/ecovacs/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from __future__ import annotations

from collections.abc import Mapping
from functools import partial
import logging
import ssl
from typing import Any
Expand Down Expand Up @@ -64,32 +65,28 @@ def __init__(self, hass: HomeAssistant, config: Mapping[str, Any]) -> None:
if not config.get(CONF_VERIFY_MQTT_CERTIFICATE, True) and mqtt_url:
ssl_context = get_default_no_verify_context()

self._mqtt = MqttClient(
create_mqtt_config(
device_id=self._device_id,
country=country,
override_mqtt_url=mqtt_url,
ssl_context=ssl_context,
),
self._authenticator,
self._mqtt_config_fn = partial(
create_mqtt_config,
device_id=self._device_id,
country=country,
override_mqtt_url=mqtt_url,
ssl_context=ssl_context,
)
self._mqtt_client: MqttClient | None = None

self._added_legacy_entities: set[str] = set()

async def initialize(self) -> None:
"""Init controller."""
mqtt_config_verfied = False
try:
devices = await self._api_client.get_devices()
credentials = await self._authenticator.authenticate()
for device_config in devices:
if isinstance(device_config, DeviceInfo):
# MQTT device
if not mqtt_config_verfied:
await self._mqtt.verify_config()
mqtt_config_verfied = True
device = Device(device_config, self._authenticator)
await device.initialize(self._mqtt)
mqtt = await self._get_mqtt_client()
await device.initialize(mqtt)
self._devices.append(device)
else:
# Legacy device
Expand All @@ -116,7 +113,8 @@ async def teardown(self) -> None:
await device.teardown()
for legacy_device in self._legacy_devices:
await self._hass.async_add_executor_job(legacy_device.disconnect)
await self._mqtt.disconnect()
if self._mqtt_client is not None:
await self._mqtt_client.disconnect()
await self._authenticator.teardown()

def add_legacy_entity(self, device: VacBot, component: str) -> None:
Expand All @@ -127,6 +125,16 @@ def legacy_entity_is_added(self, device: VacBot, component: str) -> bool:
"""Check if legacy entity is added."""
return f"{device.vacuum['did']}_{component}" in self._added_legacy_entities

async def _get_mqtt_client(self) -> MqttClient:
"""Return validated MQTT client."""
if self._mqtt_client is None:
config = await self._hass.async_add_executor_job(self._mqtt_config_fn)
mqtt = MqttClient(config, self._authenticator)
await mqtt.verify_config()
self._mqtt_client = mqtt

return self._mqtt_client

@property
def devices(self) -> list[Device]:
"""Return devices."""
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/enigma2/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"integration_type": "device",
"iot_class": "local_polling",
"loggers": ["openwebif"],
"requirements": ["openwebifpy==4.2.5"]
"requirements": ["openwebifpy==4.2.7"]
}
8 changes: 6 additions & 2 deletions homeassistant/components/environment_canada/weather.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from __future__ import annotations

from typing import Any

from homeassistant.components.weather import (
ATTR_CONDITION_CLEAR_NIGHT,
ATTR_CONDITION_CLOUDY,
Expand Down Expand Up @@ -190,10 +192,12 @@ def get_forecast(ec_data, hourly) -> list[Forecast] | None:
if not (half_days := ec_data.daily_forecasts):
return None

def get_day_forecast(fcst: list[dict[str, str]]) -> Forecast:
def get_day_forecast(
fcst: list[dict[str, Any]],
) -> Forecast:
high_temp = int(fcst[0]["temperature"]) if len(fcst) == 2 else None
return {
ATTR_FORECAST_TIME: fcst[0]["timestamp"],
ATTR_FORECAST_TIME: fcst[0]["timestamp"].isoformat(),
ATTR_FORECAST_NATIVE_TEMP: high_temp,
ATTR_FORECAST_NATIVE_TEMP_LOW: int(fcst[-1]["temperature"]),
ATTR_FORECAST_PRECIPITATION_PROBABILITY: int(
Expand Down
10 changes: 4 additions & 6 deletions homeassistant/components/glances/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,13 @@ async def _async_update_data(self) -> dict[str, Any]:
except exceptions.GlancesApiError as err:
raise UpdateFailed from err
# Update computed values
uptime: datetime | None = self.data["computed"]["uptime"] if self.data else None
uptime: datetime | None = None
up_duration: timedelta | None = None
if up_duration := parse_duration(data.get("uptime")):
if "uptime" in data and (up_duration := parse_duration(data["uptime"])):
uptime = self.data["computed"]["uptime"] if self.data else None
# Update uptime if previous value is None or previous uptime is bigger than
# new uptime (i.e. server restarted)
if (
self.data is None
or self.data["computed"]["uptime_duration"] > up_duration
):
if uptime is None or self.data["computed"]["uptime_duration"] > up_duration:
uptime = utcnow() - up_duration
data["computed"] = {"uptime_duration": up_duration, "uptime": uptime}
return data or {}
25 changes: 14 additions & 11 deletions homeassistant/components/glances/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ class GlancesSensor(CoordinatorEntity[GlancesDataUpdateCoordinator], SensorEntit

entity_description: GlancesSensorEntityDescription
_attr_has_entity_name = True
_data_valid: bool = False

def __init__(
self,
Expand All @@ -351,14 +352,7 @@ def __init__(
@property
def available(self) -> bool:
"""Set sensor unavailable when native value is invalid."""
if super().available:
return (
not self._numeric_state_expected
or isinstance(value := self.native_value, (int, float))
or isinstance(value, str)
and value.isnumeric()
)
return False
return super().available and self._data_valid

@callback
def _handle_coordinator_update(self) -> None:
Expand All @@ -368,10 +362,19 @@ def _handle_coordinator_update(self) -> None:

def _update_native_value(self) -> None:
"""Update sensor native value from coordinator data."""
data = self.coordinator.data[self.entity_description.type]
if dict_val := data.get(self._sensor_label):
data = self.coordinator.data.get(self.entity_description.type)
if data and (dict_val := data.get(self._sensor_label)):
self._attr_native_value = dict_val.get(self.entity_description.key)
elif self.entity_description.key in data:
elif data and (self.entity_description.key in data):
self._attr_native_value = data.get(self.entity_description.key)
else:
self._attr_native_value = None
self._update_data_valid()

def _update_data_valid(self) -> None:
self._data_valid = self._attr_native_value is not None and (
not self._numeric_state_expected
or isinstance(self._attr_native_value, (int, float))
or isinstance(self._attr_native_value, str)
and self._attr_native_value.isnumeric()
)
5 changes: 4 additions & 1 deletion homeassistant/components/homeassistant/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,11 @@
"integration_not_found": {
"title": "Integration {domain} not found",
"fix_flow": {
"abort": {
"issue_ignored": "Not existing integration {domain} ignored."
},
"step": {
"remove_entries": {
"init": {
"title": "[%key:component::homeassistant::issues::integration_not_found::title%]",
"description": "The integration `{domain}` could not be found. This happens when a (custom) integration was removed from Home Assistant, but there are still configurations for this `integration`. Please use the buttons below to either remove the previous configurations for `{domain}` or ignore this.",
"menu_options": {
Expand Down
7 changes: 5 additions & 2 deletions homeassistant/components/homekit/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
sensor,
)
from homeassistant.components.camera import DOMAIN as CAMERA_DOMAIN
from homeassistant.components.event import DOMAIN as EVENT_DOMAIN
from homeassistant.components.lock import DOMAIN as LOCK_DOMAIN
from homeassistant.components.media_player import (
DOMAIN as MEDIA_PLAYER_DOMAIN,
Expand Down Expand Up @@ -167,9 +168,11 @@
vol.Optional(
CONF_VIDEO_PACKET_SIZE, default=DEFAULT_VIDEO_PACKET_SIZE
): cv.positive_int,
vol.Optional(CONF_LINKED_MOTION_SENSOR): cv.entity_domain(binary_sensor.DOMAIN),
vol.Optional(CONF_LINKED_MOTION_SENSOR): cv.entity_domain(
[binary_sensor.DOMAIN, EVENT_DOMAIN]
),
vol.Optional(CONF_LINKED_DOORBELL_SENSOR): cv.entity_domain(
binary_sensor.DOMAIN
[binary_sensor.DOMAIN, EVENT_DOMAIN]
),
}
)
Expand Down
Loading

0 comments on commit 94516de

Please sign in to comment.