Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
1c93901
Remove the concept of device info types from device registry (#179397)
emontnemery Aug 19, 2026
281bec2
Migrate integrations to call dr.async_entries_for_config_entry (#179550)
emontnemery Aug 19, 2026
f3deadb
Bump lyngdorf to 1.9.0 (#179520)
fishloa Aug 19, 2026
dbee85c
Deprecate default_ members in DeviceInfo (#179549)
emontnemery Aug 19, 2026
465624e
Forward service call context to entity in assist_satellite.ask_questi…
balloob Aug 19, 2026
c3510f0
Avoid a naive datetime.now() in buienradar (#178368)
soldier2008 Aug 19, 2026
52df7ad
Use a flow specific client for Z-Wave JS adapter migration (#179541)
balloobbot Aug 19, 2026
ddd86f3
Bump mvg to 1.6.0 (#179532)
danielpotthast Aug 19, 2026
f632e11
Migrate integration tests to call dr.async_entries_for_config_entry (…
emontnemery Aug 19, 2026
3975eff
Migrate withings to call DeviceRegistry.async_get_devices (#179559)
emontnemery Aug 19, 2026
8ef3e3d
Use entity attribute enums in group (#178256)
epenet Aug 19, 2026
b180223
Use EntityStateAttribute enum for restored attribute in helpers (#178…
epenet Aug 19, 2026
6c8d6e0
Migrate integration tests to call DeviceRegistry.async_get_devices (#…
emontnemery Aug 19, 2026
e9fbfb4
Keep Z-Wave JS node statistics flowing when a route can't be resolved…
MindFreeze Aug 19, 2026
8c6a1bb
Avoid potentional KeyError in zha logbook platform (#179565)
emontnemery Aug 19, 2026
4ceabf0
Update lxml to 6.1.2 (#179555)
cdce8p Aug 19, 2026
e456fc5
Forward service call context to entity in group.set and group.remove …
balloob Aug 19, 2026
3e53fa8
Add `Images` scope to Home Connect (#178485)
Diegorro98 Aug 19, 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
4 changes: 2 additions & 2 deletions homeassistant/components/alexa_devices/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ def __init__(
device_registry = dr.async_get(hass)
self.previous_devices: set[str] = {
identifier
for device in device_registry.devices.get_devices_for_config_entry_id(
entry.entry_id
for device in dr.async_entries_for_config_entry(
device_registry, entry.entry_id
)
if device.entry_type != dr.DeviceEntryType.SERVICE
for identifier_domain, identifier in device.identifiers
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/assist_satellite/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ async def handle_ask_question(call: ServiceCall) -> dict[str, Any]:
f"Invalid Assist satellite entity id: {satellite_entity_id}"
)

satellite_entity.async_set_context(call.context)

ask_question_args = {
"question": call.data.get("question"),
"question_media_id": call.data.get("question_media_id"),
Expand Down
4 changes: 1 addition & 3 deletions homeassistant/components/bang_olufsen/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,7 @@ async def async_setup_entry(
# As it has to be removed from the device on the app.

device_registry = dr.async_get(hass)
devices = device_registry.devices.get_devices_for_config_entry_id(
config_entry.entry_id
)
devices = dr.async_entries_for_config_entry(device_registry, config_entry.entry_id)
for device in devices:
if device.model == BeoModel.BEOREMOTE_ONE and device.serial_number not in {
remote.serial_number for remote in remotes
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/bang_olufsen/websocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,8 @@ async def on_notification_notification(
# Get remote devices connected to the device from Home Assistant
device_serial_numbers = [
device.serial_number
for device in device_registry.devices.get_devices_for_config_entry_id(
self.entry.entry_id
for device in dr.async_entries_for_config_entry(
device_registry, self.entry.entry_id
)
if device.serial_number is not None
and device.model == BeoModel.BEOREMOTE_ONE
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/buienradar/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
SUPPORTED_COUNTRY_CODES = ["NL", "BE"]
DEFAULT_COUNTRY = "NL"

SERVICE_TIME_ZONE = "Europe/Amsterdam"
"""Time zone of the buienradar.nl service, which updates around local midnight."""

SCHEDULE_OK = 10
"""Schedule next call after (minutes)."""
SCHEDULE_NOK = 2
Expand Down
11 changes: 8 additions & 3 deletions homeassistant/components/buienradar/util.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Shared utilities for different supported platforms."""

from datetime import datetime, timedelta
from datetime import timedelta
from http import HTTPStatus
import logging
from typing import Any
Expand Down Expand Up @@ -34,7 +34,7 @@
from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.util import dt as dt_util

from .const import DEFAULT_TIMEOUT, SCHEDULE_NOK, SCHEDULE_OK
from .const import DEFAULT_TIMEOUT, SCHEDULE_NOK, SCHEDULE_OK, SERVICE_TIME_ZONE

__all__ = ["BrData"]
_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -158,7 +158,12 @@ async def _async_update(self):

_LOGGER.debug("Buienradar parsed data: %s", result)
if result.get(SUCCESS) is not True:
if int(datetime.now().strftime("%H")) > 0: # pylint: disable=home-assistant-enforce-naive-now
# buienradar.nl updates its forecast for the next day between 00:00
# and 01:00 CE(S)T and often serves nothing during that hour, so the
# warning is only meaningful outside it. The hour that decides this
# is the one at the service, not in the user's configured time zone.
service_tz = await dt_util.async_get_time_zone(SERVICE_TIME_ZONE)
if service_tz is None or dt_util.utcnow().astimezone(service_tz).hour > 0:
_LOGGER.warning(
"Unable to parse data from Buienradar. (Msg: %s)",
result.get(MESSAGE),
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/deconz/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ async def async_remove_orphaned_entries_service(hub: DeconzHub) -> None:
entities_to_be_removed = []
devices_to_be_removed = [
entry.id
for entry in device_registry.devices.get_devices_for_config_entry_id(
hub.config_entry.entry_id
for entry in dr.async_entries_for_config_entry(
device_registry, hub.config_entry.entry_id
)
]

Expand Down
4 changes: 1 addition & 3 deletions homeassistant/components/geofency/device_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ def _receive_data(device, gps, location_name, attributes):
dev_reg = dr.async_get(hass)
dev_ids = {
identifier[1]
for device in dev_reg.devices.get_devices_for_config_entry_id(
config_entry.entry_id
)
for device in dr.async_entries_for_config_entry(dev_reg, config_entry.entry_id)
for identifier in device.identifiers
}

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/gpslogger/device_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def _receive_data(device, gps, battery, accuracy, attrs):
dev_reg = dr.async_get(hass)
dev_ids = {
identifier[1]
for device in dev_reg.devices.get_devices_for_config_entry_id(entry.entry_id)
for device in dr.async_entries_for_config_entry(dev_reg, entry.entry_id)
for identifier in device.identifiers
}
if not dev_ids:
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/group/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,13 +265,16 @@ async def groups_service_handler(service: ServiceCall) -> None:
mode=service.data.get(ATTR_ALL),
object_id=object_id,
order=None,
context=service.context,
)
return

if group is None:
_LOGGER.warning("%s:Group '%s' doesn't exist!", service.service, object_id)
return

group.async_set_context(service.context)

# update group
if service.service == SERVICE_SET:
need_update = False
Expand Down
11 changes: 5 additions & 6 deletions homeassistant/components/group/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,18 @@
import voluptuous as vol

from homeassistant.components.cover import (
ATTR_CURRENT_POSITION,
ATTR_CURRENT_TILT_POSITION,
ATTR_POSITION,
ATTR_TILT_POSITION,
DOMAIN as COVER_DOMAIN,
PLATFORM_SCHEMA as COVER_PLATFORM_SCHEMA,
CoverEntity,
CoverEntityFeature,
CoverEntityStateAttribute,
CoverState,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
CONF_ENTITIES,
CONF_NAME,
CONF_UNIQUE_ID,
Expand All @@ -32,6 +30,7 @@
SERVICE_STOP_COVER_TILT,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
EntityStateAttribute,
)
from homeassistant.core import HomeAssistant, State, callback
from homeassistant.helpers import config_validation as cv, entity_registry as er
Expand Down Expand Up @@ -148,7 +147,7 @@ def async_update_supported_features(
values.discard(entity_id)
return

features = new_state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
features = new_state.attributes.get(EntityStateAttribute.SUPPORTED_FEATURES, 0)

if features & (CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE):
self._covers[KEY_OPEN_CLOSE].add(entity_id)
Expand Down Expand Up @@ -313,14 +312,14 @@ def async_update_group_state(self) -> None:
all_position_states = [self.hass.states.get(x) for x in position_covers]
position_states: list[State] = list(filter(None, all_position_states))
self._attr_current_cover_position = reduce_attribute(
position_states, ATTR_CURRENT_POSITION
position_states, CoverEntityStateAttribute.CURRENT_POSITION
)

tilt_covers = self._tilts[KEY_POSITION]
all_tilt_states = [self.hass.states.get(x) for x in tilt_covers]
tilt_states: list[State] = list(filter(None, all_tilt_states))
self._attr_current_cover_tilt_position = reduce_attribute(
tilt_states, ATTR_CURRENT_TILT_POSITION
tilt_states, CoverEntityStateAttribute.CURRENT_TILT_POSITION
)

supported_features = CoverEntityFeature(0)
Expand Down
24 changes: 17 additions & 7 deletions homeassistant/components/group/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
from typing import Any, override

from homeassistant.const import (
ATTR_ASSUMED_STATE,
ATTR_ENTITY_ID,
ATTR_GROUP_ENTITIES,
STATE_OFF,
STATE_ON,
EntityCapabilityAttribute,
EntityStateAttribute,
)
from homeassistant.core import (
CALLBACK_TYPE,
Context,
Event,
EventStateChangedData,
HomeAssistant,
Expand All @@ -39,7 +40,9 @@
class GroupEntity(Entity):
"""Representation of a Group of entities."""

_unrecorded_attributes = frozenset({ATTR_ENTITY_ID, ATTR_GROUP_ENTITIES})
_unrecorded_attributes = frozenset(
{ATTR_ENTITY_ID, EntityCapabilityAttribute.GROUP_ENTITIES}
)

_attr_should_poll = False
_entity_ids: list[str]
Expand Down Expand Up @@ -127,7 +130,7 @@ def _update_assumed_state_from_members(self) -> None:
for entity_id in self._entity_ids:
if (state := self.hass.states.get(entity_id)) is None:
continue
if state.attributes.get(ATTR_ASSUMED_STATE):
if state.attributes.get(EntityStateAttribute.ASSUMED_STATE):
self._attr_assumed_state = True
return

Expand Down Expand Up @@ -231,6 +234,7 @@ async def async_create_group(
mode: bool | None,
object_id: str | None,
order: int | None,
context: Context | None,
) -> Group:
"""Initialize a group.

Expand All @@ -247,6 +251,9 @@ async def async_create_group(
order=order,
)

if context is not None:
group.async_set_context(context)

# If called before the platform async_setup is called (test cases)
await async_get_component(hass).async_add_entities([group])
return group
Expand Down Expand Up @@ -430,7 +437,9 @@ def _see_state(self, new_state: State) -> None:
domain = new_state.domain
state = new_state.state
registry = self._registry
self._assumed[entity_id] = bool(new_state.attributes.get(ATTR_ASSUMED_STATE))
self._assumed[entity_id] = bool(
new_state.attributes.get(EntityStateAttribute.ASSUMED_STATE)
)

if domain not in registry.on_states_by_domain:
# Handle the group of a group case
Expand Down Expand Up @@ -462,11 +471,12 @@ def _async_update_group_state(self, tr_state: State | None = None) -> None:
return

if tr_state is None or (
self._assumed_state and not tr_state.attributes.get(ATTR_ASSUMED_STATE)
self._assumed_state
and not tr_state.attributes.get(EntityStateAttribute.ASSUMED_STATE)
):
self._assumed_state = self.mode(self._assumed.values())

elif tr_state.attributes.get(ATTR_ASSUMED_STATE):
elif tr_state.attributes.get(EntityStateAttribute.ASSUMED_STATE):
self._assumed_state = True

num_on_states = len(self._on_states)
Expand Down
24 changes: 14 additions & 10 deletions homeassistant/components/group/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,21 @@
import voluptuous as vol

from homeassistant.components.event import (
ATTR_EVENT_TYPE,
ATTR_EVENT_TYPES,
DOMAIN as EVENT_DOMAIN,
PLATFORM_SCHEMA as EVENT_PLATFORM_SCHEMA,
EventEntity,
EventEntityCapabilityAttribute,
EventEntityStateAttribute,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_DEVICE_CLASS,
ATTR_ENTITY_ID,
ATTR_FRIENDLY_NAME,
CONF_ENTITIES,
CONF_NAME,
CONF_UNIQUE_ID,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
EntityStateAttribute,
)
from homeassistant.core import Event, EventStateChangedData, HomeAssistant, callback
from homeassistant.helpers import config_validation as cv, entity_registry as er
Expand Down Expand Up @@ -142,16 +141,20 @@ def async_state_changed_listener(
and old_state.state not in (STATE_UNAVAILABLE, STATE_UNKNOWN)
and (new_state := event.data["new_state"])
and new_state.state not in (STATE_UNAVAILABLE, STATE_UNKNOWN)
and (event_type := new_state.attributes.get(ATTR_EVENT_TYPE))
and (
event_type := new_state.attributes.get(
EventEntityStateAttribute.EVENT_TYPE
)
)
):
event_attributes = new_state.attributes.copy()

# We should not propagate the event properties as
# fired event attributes.
del event_attributes[ATTR_EVENT_TYPE]
del event_attributes[ATTR_EVENT_TYPES]
event_attributes.pop(ATTR_DEVICE_CLASS, None)
event_attributes.pop(ATTR_FRIENDLY_NAME, None)
del event_attributes[EventEntityStateAttribute.EVENT_TYPE]
del event_attributes[EventEntityCapabilityAttribute.EVENT_TYPES]
event_attributes.pop(EntityStateAttribute.DEVICE_CLASS, None)
event_attributes.pop(EntityStateAttribute.FRIENDLY_NAME, None)

# Fire the group event
self._trigger_event(event_type, event_attributes)
Expand Down Expand Up @@ -185,7 +188,8 @@ def async_update_group_state(self) -> None:
self._attr_event_types = list(
set(
itertools.chain.from_iterable(
state.attributes.get(ATTR_EVENT_TYPES, []) for state in states
state.attributes.get(EventEntityCapabilityAttribute.EVENT_TYPES, [])
for state in states
)
)
)
Expand Down
27 changes: 20 additions & 7 deletions homeassistant/components/group/fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
ATTR_DIRECTION,
ATTR_OSCILLATING,
ATTR_PERCENTAGE,
ATTR_PERCENTAGE_STEP,
DOMAIN as FAN_DOMAIN,
PLATFORM_SCHEMA as FAN_PLATFORM_SCHEMA,
SERVICE_OSCILLATE,
Expand All @@ -21,17 +20,18 @@
SERVICE_TURN_ON,
FanEntity,
FanEntityFeature,
FanEntityStateAttribute,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_SUPPORTED_FEATURES,
CONF_ENTITIES,
CONF_NAME,
CONF_UNIQUE_ID,
STATE_ON,
STATE_UNAVAILABLE,
STATE_UNKNOWN,
EntityStateAttribute,
)
from homeassistant.core import HomeAssistant, State, callback
from homeassistant.helpers import config_validation as cv, entity_registry as er
Expand Down Expand Up @@ -166,7 +166,9 @@ def async_update_supported_features(
for values in self._fans.values():
values.discard(entity_id)
else:
features = new_state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
features = new_state.attributes.get(
EntityStateAttribute.SUPPORTED_FEATURES, 0
)
for feature in SUPPORTED_FLAGS:
if features & feature:
self._fans[feature].add(entity_id)
Expand Down Expand Up @@ -286,14 +288,25 @@ def async_update_group_state(self) -> None:
percentage_states = self._async_states_by_support_flag(
FanEntityFeature.SET_SPEED
)
self._percentage = reduce_attribute(percentage_states, ATTR_PERCENTAGE)
self._percentage = reduce_attribute(
percentage_states, FanEntityStateAttribute.PERCENTAGE
)
if (
percentage_states
and percentage_states[0].attributes.get(ATTR_PERCENTAGE_STEP)
and attribute_equal(percentage_states, ATTR_PERCENTAGE_STEP)
and percentage_states[0].attributes.get(
FanEntityStateAttribute.PERCENTAGE_STEP
)
and attribute_equal(
percentage_states, FanEntityStateAttribute.PERCENTAGE_STEP
)
):
self._speed_count = (
round(100 / percentage_states[0].attributes[ATTR_PERCENTAGE_STEP])
round(
100
/ percentage_states[0].attributes[
FanEntityStateAttribute.PERCENTAGE_STEP
]
)
or 100
)
else:
Expand Down
Loading
Loading