Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f803ced
Add clarity to the STT Labs title (#180927)
shayredmond Aug 31, 2026
16040b5
Use registry fixtures in tests (6/8) (#180928)
joostlek Aug 31, 2026
49fd8f4
Add miele washing machine program for towels (#180916)
astrandb Aug 31, 2026
8c5493a
Use registry fixtures in tests (8/8) (#180931)
joostlek Aug 31, 2026
b7ad53e
Suggest hours as unit of measurement for Google Health sleep duration…
allenporter Aug 31, 2026
3b84971
Revert images functionality in Home Connect (#180933)
Diegorro98 Aug 31, 2026
acf7a9e
Use registry fixtures in tests (3/8) (#180923)
joostlek Aug 31, 2026
ff5bde3
Use registry fixtures in tests (4/8) (#180924)
joostlek Aug 31, 2026
b23e5c8
Use registry fixtures in tests (2/8) (#180920)
joostlek Aug 31, 2026
df2e2cb
Use registry fixtures in tests (7/8) (#180930)
joostlek Aug 31, 2026
e85d14f
Use registry fixtures in tests (5/8) (#180926)
joostlek Aug 31, 2026
73f184c
Bump sofar-modbus to 0.8.0 (#180935)
darkrain-nl Aug 31, 2026
1bdf472
Add player reports for Nintendo Parental Controls (#180937)
pantherale0 Aug 31, 2026
5373e31
Add Zonneplan integration (#180722)
erwindouna Aug 31, 2026
987e6b3
Bump tesla-fleet-api to 1.12.1 (#180911)
Bre77 Aug 31, 2026
bc893b0
Restore Husqvarna Automower work area sensors and gate by WorkAreaTyp…
Thomas55555 Aug 31, 2026
601ed3f
Add missing quality scale ProxmoxVE (#178429)
erwindouna Aug 31, 2026
7950dd4
refactor(`metoffice`): use `dt_util.now` in `weather.py` (#180902)
robotsnh Aug 31, 2026
bfb55cc
Improve code quality of hr_energy_qube (#178280)
MattieGit Aug 31, 2026
ffbdca8
Bump grpcio to 1.83.1 and protobuf to v7 (#180614)
silamon Aug 31, 2026
6cd5e22
Remove Subaru unique_id migration for HA<=2022.10 (#180944)
jpettitt Aug 31, 2026
1c7a6b6
Bump satel_integra to 1.4.0 (#180960)
Tommatheussen Aug 31, 2026
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
1 change: 1 addition & 0 deletions .strict-typing
Original file line number Diff line number Diff line change
Expand Up @@ -674,4 +674,5 @@ homeassistant.components.zeroconf.*
homeassistant.components.zinvolt.*
homeassistant.components.zodiac.*
homeassistant.components.zone.*
homeassistant.components.zonneplan.*
homeassistant.components.zwave_js.*
2 changes: 2 additions & 0 deletions CODEOWNERS

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion homeassistant/components/cloud/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
"description": "We're testing a new speech-to-text engine for Home Assistant Cloud, the part of voice control that turns what you say into words. In our testing it copes better with accents, background noise, and languages other than English.\n\nWhile this is enabled, any audio from your voice commands is processed by [Soniox](https://soniox.com/) rather than our current provider. This is relevant only to Assistants configured to use Home Assistant Cloud as an STT engine. It travels through a Nabu Casa proxy, which handles authentication and forwards it to the processing region closest to you. Nabu Casa doesn't process, store or log your audio at any point. Everything else about your voice pipeline stays the same, and you can turn this off again at any time.",
"disable_confirmation": "Any Assistant currently using the new engine will go back to being transcribed by our current speech-to-text provider.",
"enable_confirmation": "This feature is still in development and may change. While it's enabled, audio from your voice commands in supported languages is transcribed by Soniox instead of our current provider.",
"name": "Speech-to-text"
"name": "New speech-to-text engine"
}
},
"services": {
Expand Down
6 changes: 6 additions & 0 deletions homeassistant/components/google_health/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ class GoogleHealthSensorEntityDescription[
key="sleep_asleep",
translation_key="sleep_asleep",
native_unit_of_measurement=UnitOfTime.MINUTES,
suggested_unit_of_measurement=UnitOfTime.HOURS,
suggested_display_precision=2,
device_class=SensorDeviceClass.DURATION,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: (
Expand All @@ -170,6 +172,8 @@ class GoogleHealthSensorEntityDescription[
key="sleep_awake",
translation_key="sleep_awake",
native_unit_of_measurement=UnitOfTime.MINUTES,
suggested_unit_of_measurement=UnitOfTime.HOURS,
suggested_display_precision=2,
device_class=SensorDeviceClass.DURATION,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: (
Expand All @@ -182,6 +186,8 @@ class GoogleHealthSensorEntityDescription[
key="sleep_in_bed",
translation_key="sleep_in_bed",
native_unit_of_measurement=UnitOfTime.MINUTES,
suggested_unit_of_measurement=UnitOfTime.HOURS,
suggested_display_precision=2,
device_class=SensorDeviceClass.DURATION,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda data: (
Expand Down
1 change: 0 additions & 1 deletion homeassistant/components/home_connect/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
Platform.BUTTON,
Platform.CLIMATE,
Platform.FAN,
Platform.IMAGE,
Platform.LIGHT,
Platform.NUMBER,
Platform.SELECT,
Expand Down
16 changes: 8 additions & 8 deletions homeassistant/components/home_connect/common.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Common callbacks for all Home Connect platforms."""

from collections import defaultdict
from collections.abc import Callable, Sequence
from collections.abc import Callable
from functools import partial
from typing import cast

Expand All @@ -10,7 +10,7 @@
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity import Entity, EntityDescription
from homeassistant.helpers.entity import EntityDescription
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from .const import DOMAIN
Expand Down Expand Up @@ -48,7 +48,7 @@ def _create_option_entities(
known_entity_unique_ids: dict[str, str],
get_option_entities_for_appliance: Callable[
[HomeConnectApplianceCoordinator, er.EntityRegistry],
Sequence[HomeConnectEntity],
list[HomeConnectEntity],
],
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
Expand All @@ -74,11 +74,11 @@ def _handle_paired_or_connected_appliance(
entry: HomeConnectConfigEntry,
known_entity_unique_ids: dict[str, str],
get_entities_for_appliance: Callable[
[HomeConnectApplianceCoordinator], Sequence[Entity]
[HomeConnectApplianceCoordinator], list[HomeConnectEntity]
],
get_option_entities_for_appliance: Callable[
[HomeConnectApplianceCoordinator, er.EntityRegistry],
Sequence[HomeConnectEntity],
list[HomeConnectEntity],
]
| None,
changed_options_listener_remove_callbacks: dict[str, list[Callable[[], None]]],
Expand All @@ -91,7 +91,7 @@ def _handle_paired_or_connected_appliance(
when they are turned off, so we need to check if the entities have been added
already or it is the first time we see them when the appliance is connected.
"""
entities: list[Entity] = []
entities: list[HomeConnectEntity] = []
entity_registry = er.async_get(hass)
for appliance_coordinator in entry.runtime_data.appliance_coordinators.values():
appliance_ha_id = appliance_coordinator.data.info.ha_id
Expand Down Expand Up @@ -161,12 +161,12 @@ def setup_home_connect_entry(
hass: HomeAssistant,
entry: HomeConnectConfigEntry,
get_entities_for_appliance: Callable[
[HomeConnectApplianceCoordinator], Sequence[Entity]
[HomeConnectApplianceCoordinator], list[HomeConnectEntity]
],
async_add_entities: AddConfigEntryEntitiesCallback,
get_option_entities_for_appliance: Callable[
[HomeConnectApplianceCoordinator, er.EntityRegistry],
Sequence[HomeConnectEntity],
list[HomeConnectEntity],
]
| None = None,
) -> None:
Expand Down
41 changes: 1 addition & 40 deletions homeassistant/components/home_connect/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from collections.abc import Mapping
import logging
from typing import Any, Final, override
from typing import Any, override

import jwt
import voluptuous as vol
Expand All @@ -13,8 +13,6 @@

from .const import DOMAIN

INPUT_IMAGES_SCOPE: Final = "images_scope"


class OAuth2FlowHandler(
config_entry_oauth2_flow.AbstractOAuth2FlowHandler, domain=DOMAIN
Expand All @@ -25,49 +23,12 @@ class OAuth2FlowHandler(

MINOR_VERSION = 3

images_scope: bool | None = None

@property
@override
def logger(self) -> logging.Logger:
"""Return logger."""
return logging.getLogger(__name__)

@property
@override
def extra_authorize_data(self) -> dict[str, str]:
return {
"scope": (
"Control Monitor Settings"
f" IdentifyAppliance{' Images' if self.images_scope else ''}"
),
}

@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle a flow start."""
return await self.async_step_scopes(user_input)

async def async_step_scopes(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Ask for the scopes to use."""
if user_input is not None:
self.images_scope = user_input[INPUT_IMAGES_SCOPE]
if self.images_scope is not None:
return await self.async_step_pick_implementation(None)

return self.async_show_form(
step_id="scopes",
data_schema=vol.Schema(
{
vol.Required(INPUT_IMAGES_SCOPE): bool,
}
),
)

async def async_step_reauth(
self, entry_data: Mapping[str, Any]
) -> ConfigFlowResult:
Expand Down
74 changes: 0 additions & 74 deletions homeassistant/components/home_connect/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
TooManyRequestsError,
UnauthorizedError,
)
from aiohomeconnect.model.image import Image
from aiohomeconnect.model.program import EnumerateProgram, ProgramDefinitionOption

from homeassistant.config_entries import ConfigEntry
Expand Down Expand Up @@ -66,7 +65,6 @@ class HomeConnectApplianceData:
programs: list[EnumerateProgram]
settings: dict[SettingKey, GetSetting]
status: dict[StatusKey, Status]
images: dict[str, Image]

def update(self, other: HomeConnectApplianceData) -> None:
"""Update data with data from other instance."""
Expand All @@ -80,7 +78,6 @@ def update(self, other: HomeConnectApplianceData) -> None:
self.programs.extend(other.programs)
self.settings.update(other.settings)
self.status.update(other.status)
self.images.update(other.images)

@classmethod
def empty(cls, appliance: HomeAppliance) -> HomeConnectApplianceData:
Expand All @@ -93,7 +90,6 @@ def empty(cls, appliance: HomeAppliance) -> HomeConnectApplianceData:
programs=[],
settings={},
status={},
images={},
)


Expand Down Expand Up @@ -272,10 +268,6 @@ def __init__(
self.global_listeners = global_listeners
self.data = HomeConnectApplianceData.empty(appliance)
self._execution_tracker: list[float] = []
self.should_fetch_images = "Images" in self._config_entry.data["token"].get(
"scope", ""
)
self._image_listeners: dict[str, list[CALLBACK_TYPE]] = {}

def _get_listeners_for_event_key(self, event_key: EventKey) -> list[CALLBACK_TYPE]:
return [
Expand Down Expand Up @@ -575,18 +567,6 @@ async def get_appliance_data(self) -> None:
except HomeConnectError:
commands = set()

try:
images = await self.get_latest_images() if self.should_fetch_images else {}
except TooManyRequestsError:
raise
except HomeConnectError as error:
_LOGGER.debug(
"Error fetching images for %s: %s",
appliance.ha_id,
error,
)
images = {}

self.data.update(
HomeConnectApplianceData(
commands=commands,
Expand All @@ -596,7 +576,6 @@ async def get_appliance_data(self) -> None:
programs=programs,
settings=settings,
status=status,
images=images,
)
)

Expand Down Expand Up @@ -667,59 +646,6 @@ async def update_options(self, program_key: ProgramKey) -> None:
for listener in self._get_listeners_for_event_key(EventKey(option_key)):
listener()

async def get_latest_images(self) -> dict[str, Image]:
"""Get the latest images for the appliance."""
try:
new_images = await self.client.get_images(self.data.info.ha_id)
except TooManyRequestsError:
raise
except HomeConnectError as error:
_LOGGER.debug(
"Error fetching images for %s: %s",
self.data.info.ha_id,
error,
)
return {}

latest_images: dict[str, Image] = {}
for image in new_images.images:
if (
existing_image := latest_images.get(image.key)
) is None or image.timestamp > existing_image.timestamp:
latest_images[image.key] = image

return latest_images

async def update_images(self) -> None:
"""Update images for appliance."""
old_images = self.data.images.copy()
self.data.images.update(await self.get_latest_images())
for image_key, image in self.data.images.items():
if image.image_key != old_images[image_key].image_key:
for listener in self._image_listeners.get(image_key, []):
listener()

def add_image_listener(
self, image_key: str, update_callback: CALLBACK_TYPE
) -> Callable[[], None]:
"""Listen for image updates.

These listeners will not be called on refresh.
"""

@callback
def remove_listener() -> None:
"""Remove update listener."""
self._image_listeners[image_key].remove(update_callback)
if not self._image_listeners[image_key]:
del self._image_listeners[image_key]

if image_key not in self._image_listeners:
self._image_listeners[image_key] = []
self._image_listeners[image_key].append(update_callback)

return remove_listener

def refreshed_too_often_recently(self) -> bool:
"""Check if the appliance data hasn't been refreshed too often recently."""

Expand Down
Loading
Loading