Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
dc133bf
Move Tuya helpers to external library (#158791)
epenet Feb 25, 2026
50f3962
Add vacuum area mapping not configured issue (#163965)
arturpragacz Feb 25, 2026
3426846
Add CLEAN_AREA feature to Matter vacuum entity (#163570)
lboue Feb 25, 2026
834227a
Use constants in calendar test (#164021)
epenet Feb 25, 2026
f0edfbf
Enrich DeviceInfo with meter metadata in route_b_smart_meter (#164006)
yufeikang Feb 25, 2026
910f501
Fix ingress compression breaking SSE and streaming responses (#160704)
tomquist Feb 25, 2026
195e550
Drop single-use service name constants in Renault (#164043)
epenet Feb 25, 2026
8dcaed6
Add base entity to Zinvolt (#164051)
joostlek Feb 25, 2026
44a4be0
Use constants in counter tests (#164020)
epenet Feb 25, 2026
b8df61f
Categorize update entity as diagnostic in IronOS integration (#164023)
tr4nt0r Feb 25, 2026
0cb34d2
Categorize update entity as diagnostic in Uptime Kuma (#164022)
tr4nt0r Feb 25, 2026
317f95f
Add a service to retrieve images for the Volvo integration (#159603)
thomasddn Feb 25, 2026
fc79e0c
Bump zinvolt to 0.3.0 (#164046)
joostlek Feb 25, 2026
89c5511
Improve configuration url in Uptime Kuma (#164057)
tr4nt0r Feb 25, 2026
caf40f9
Add diagnostics to NRGkick integration (#164047)
andijakl Feb 25, 2026
f9a61e5
Mark docs-examples done for Liebherr integration (#163034)
mettolen Feb 25, 2026
01f0e4f
Add update platform to ntfy integration (#164018)
tr4nt0r Feb 25, 2026
925bcea
Add number platform to Zinvolt (#164058)
joostlek Feb 25, 2026
c5b31d6
Add Update Platform to Smarla Integration (#163255)
rlint-explicatis Feb 25, 2026
70f5f2c
Add binary sensor platform to Zinvolt (#164050)
joostlek Feb 25, 2026
0563037
Fix MatterValve state handling and allow None values for attributes (…
lboue Feb 25, 2026
2cfafc0
Bump python-bsblan to 5.1.0 (#164064)
liudger Feb 25, 2026
cb99082
Improve platforms pylint plugin (#164067)
joostlek Feb 25, 2026
e591291
Add platform tests for aladdin_connect cover and sensor (#164011)
JamieMagee Feb 25, 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: 1 addition & 3 deletions homeassistant/components/aladdin_connect/quality_scale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ rules:
log-when-unavailable: todo
parallel-updates: todo
reauthentication-flow: done
test-coverage:
status: todo
comment: Platform tests for cover and sensor need to be implemented to reach 95% coverage.
test-coverage: done

# Gold
devices: done
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/bsblan/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"iot_class": "local_polling",
"loggers": ["bsblan"],
"quality_scale": "silver",
"requirements": ["python-bsblan==5.0.1"],
"requirements": ["python-bsblan==5.1.0"],
"zeroconf": [
{
"name": "bsb-lan*",
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/hassio/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ def should_compress(content_type: str, path: str | None = None) -> bool:
"""Return if we should compress a response."""
if path is not None and NO_COMPRESS.match(path):
return False
if content_type.startswith("text/event-stream"):
return False
if content_type.startswith("image/"):
return "svg" in content_type
if content_type.startswith("application/"):
Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/iron_os/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
UpdateEntityDescription,
UpdateEntityFeature,
)
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.restore_state import RestoreEntity
Expand All @@ -22,6 +23,7 @@
UPDATE_DESCRIPTION = UpdateEntityDescription(
key="firmware",
device_class=UpdateDeviceClass.FIRMWARE,
entity_category=EntityCategory.DIAGNOSTIC,
)


Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/liebherr/quality_scale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ rules:
comment: Cloud API does not require updating entry data from network discovery.
discovery: done
docs-data-update: done
docs-examples: todo
docs-examples: done
docs-known-limitations: done
docs-supported-devices: done
docs-supported-functions: done
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/matter/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,9 @@ async def send_device_command(
self,
command: ClusterCommand,
**kwargs: Any,
) -> None:
) -> Any:
"""Send device command on the primary attribute's endpoint."""
await self.matter_client.send_device_command(
return await self.matter_client.send_device_command(
node_id=self._endpoint.node.node_id,
endpoint_id=self._endpoint.endpoint_id,
command=command,
Expand Down
104 changes: 102 additions & 2 deletions homeassistant/components/matter/vacuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from matter_server.client.models import device_types

from homeassistant.components.vacuum import (
Segment,
StateVacuumEntity,
StateVacuumEntityDescription,
VacuumActivity,
Expand Down Expand Up @@ -70,6 +71,7 @@ class MatterVacuum(MatterEntity, StateVacuumEntity):
"""Representation of a Matter Vacuum cleaner entity."""

_last_accepted_commands: list[int] | None = None
_last_service_area_feature_map: int | None = None
_supported_run_modes: (
dict[int, clusters.RvcRunMode.Structs.ModeOptionStruct] | None
) = None
Expand Down Expand Up @@ -136,6 +138,16 @@ async def async_start(self) -> None:
"No supported run mode found to start the vacuum cleaner."
)

# Reset selected areas to an unconstrained selection to ensure start
# performs a full clean and does not reuse a previous area-targeted
# selection.
if VacuumEntityFeature.CLEAN_AREA in self.supported_features:
# Matter ServiceArea: an empty NewAreas list means unconstrained
# operation (full clean).
await self.send_device_command(
clusters.ServiceArea.Commands.SelectAreas(newAreas=[])
)

await self.send_device_command(
clusters.RvcRunMode.Commands.ChangeToMode(newMode=mode.mode)
)
Expand All @@ -144,6 +156,66 @@ async def async_pause(self) -> None:
"""Pause the cleaning task."""
await self.send_device_command(clusters.RvcOperationalState.Commands.Pause())

@property
def _current_segments(self) -> dict[str, Segment]:
"""Return the current cleanable segments reported by the device."""
supported_areas: list[clusters.ServiceArea.Structs.AreaStruct] = (
self.get_matter_attribute_value(
clusters.ServiceArea.Attributes.SupportedAreas
)
)

segments: dict[str, Segment] = {}
for area in supported_areas:
area_name = None
if area.areaInfo and area.areaInfo.locationInfo:
area_name = area.areaInfo.locationInfo.locationName

if area_name:
segment_id = str(area.areaID)
segments[segment_id] = Segment(id=segment_id, name=area_name)

return segments

async def async_get_segments(self) -> list[Segment]:
"""Get the segments that can be cleaned.

Returns a list of segments containing their ids and names.
"""
return list(self._current_segments.values())

async def async_clean_segments(self, segment_ids: list[str], **kwargs: Any) -> None:
"""Clean the specified segments.

Args:
segment_ids: List of segment IDs to clean.
**kwargs: Additional arguments (unused).

"""
area_ids = [int(segment_id) for segment_id in segment_ids]

mode = self._get_run_mode_by_tag(ModeTag.CLEANING)
if mode is None:
raise HomeAssistantError(
"No supported run mode found to start the vacuum cleaner."
)

response = await self.send_device_command(
clusters.ServiceArea.Commands.SelectAreas(newAreas=area_ids)
)

if (
response
and response.status != clusters.ServiceArea.Enums.SelectAreasStatus.kSuccess
):
raise HomeAssistantError(
f"Failed to select areas: {response.statusText or response.status.name}"
)

await self.send_device_command(
clusters.RvcRunMode.Commands.ChangeToMode(newMode=mode.mode)
)

@callback
def _update_from_device(self) -> None:
"""Update from device."""
Expand Down Expand Up @@ -176,16 +248,34 @@ def _update_from_device(self) -> None:
state = VacuumActivity.CLEANING
self._attr_activity = state

if (
VacuumEntityFeature.CLEAN_AREA in self.supported_features
and self.registry_entry is not None
and (last_seen_segments := self.last_seen_segments) is not None
and self._current_segments != {s.id: s for s in last_seen_segments}
):
self.async_create_segments_issue()

@callback
def _calculate_features(self) -> None:
"""Calculate features for HA Vacuum platform."""
accepted_operational_commands: list[int] = self.get_matter_attribute_value(
clusters.RvcOperationalState.Attributes.AcceptedCommandList
)
# in principle the feature set should not change, except for the accepted commands
if self._last_accepted_commands == accepted_operational_commands:
service_area_feature_map: int | None = self.get_matter_attribute_value(
clusters.ServiceArea.Attributes.FeatureMap
)

# In principle the feature set should not change, except for accepted
# commands and service area feature map.
if (
self._last_accepted_commands == accepted_operational_commands
and self._last_service_area_feature_map == service_area_feature_map
):
return

self._last_accepted_commands = accepted_operational_commands
self._last_service_area_feature_map = service_area_feature_map
supported_features: VacuumEntityFeature = VacuumEntityFeature(0)
supported_features |= VacuumEntityFeature.START
supported_features |= VacuumEntityFeature.STATE
Expand All @@ -212,6 +302,12 @@ def _calculate_features(self) -> None:
in accepted_operational_commands
):
supported_features |= VacuumEntityFeature.RETURN_HOME
# Check if Map feature is enabled for clean area support
if (
service_area_feature_map is not None
and service_area_feature_map & clusters.ServiceArea.Bitmaps.Feature.kMaps
):
supported_features |= VacuumEntityFeature.CLEAN_AREA

self._attr_supported_features = supported_features

Expand All @@ -228,6 +324,10 @@ def _calculate_features(self) -> None:
clusters.RvcRunMode.Attributes.CurrentMode,
clusters.RvcOperationalState.Attributes.OperationalState,
),
optional_attributes=(
clusters.ServiceArea.Attributes.FeatureMap,
clusters.ServiceArea.Attributes.SupportedAreas,
),
device_type=(device_types.RoboticVacuumCleaner,),
allow_none_value=True,
),
Expand Down
34 changes: 19 additions & 15 deletions homeassistant/components/matter/valve.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,34 +69,37 @@ async def async_set_valve_position(self, position: int) -> None:
def _update_from_device(self) -> None:
"""Update from device."""
self._calculate_features()
current_state: int
self._attr_is_opening = False
self._attr_is_closing = False

current_state: int | None
current_state = self.get_matter_attribute_value(
ValveConfigurationAndControl.Attributes.CurrentState
)
target_state: int
target_state: int | None
target_state = self.get_matter_attribute_value(
ValveConfigurationAndControl.Attributes.TargetState
)
if (
current_state == ValveStateEnum.kTransitioning
and target_state == ValveStateEnum.kOpen

if current_state is None:
self._attr_is_closed = None
elif current_state == ValveStateEnum.kTransitioning and (
target_state == ValveStateEnum.kOpen
):
self._attr_is_opening = True
self._attr_is_closing = False
elif (
current_state == ValveStateEnum.kTransitioning
and target_state == ValveStateEnum.kClosed
self._attr_is_closed = None
elif current_state == ValveStateEnum.kTransitioning and (
target_state == ValveStateEnum.kClosed
):
self._attr_is_opening = False
self._attr_is_closing = True
self._attr_is_closed = None
elif current_state == ValveStateEnum.kClosed:
self._attr_is_opening = False
self._attr_is_closing = False
self._attr_is_closed = True
else:
self._attr_is_opening = False
self._attr_is_closing = False
elif current_state == ValveStateEnum.kOpen:
self._attr_is_closed = False
else:
self._attr_is_closed = None

# handle optional position
if self.supported_features & ValveEntityFeature.SET_POSITION:
self._attr_current_valve_position = self.get_matter_attribute_value(
Expand Down Expand Up @@ -145,6 +148,7 @@ def _calculate_features(
ValveConfigurationAndControl.Attributes.CurrentState,
ValveConfigurationAndControl.Attributes.TargetState,
),
allow_none_value=True,
optional_attributes=(ValveConfigurationAndControl.Attributes.CurrentLevel,),
device_type=(device_types.WaterValve,),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
from .services import async_setup_services

_PLATFORMS: list[Platform] = [
Platform.SENSOR,
Platform.TIME,
Platform.SWITCH,
Platform.NUMBER,
Platform.SELECT,
Platform.SENSOR,
Platform.SWITCH,
Platform.TIME,
]

PLATFORM_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
Expand Down
30 changes: 30 additions & 0 deletions homeassistant/components/nrgkick/diagnostics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""Diagnostics support for NRGkick."""

from __future__ import annotations

from dataclasses import asdict
from typing import Any

from homeassistant.components.diagnostics import async_redact_data
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant

from .coordinator import NRGkickConfigEntry

TO_REDACT = {
CONF_PASSWORD,
CONF_USERNAME,
}


async def async_get_config_entry_diagnostics(
hass: HomeAssistant, entry: NRGkickConfigEntry
) -> dict[str, Any]:
"""Return diagnostics for a config entry."""
return async_redact_data(
{
"entry_data": entry.data,
"coordinator_data": asdict(entry.runtime_data.data),
},
TO_REDACT,
)
2 changes: 1 addition & 1 deletion homeassistant/components/nrgkick/quality_scale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ rules:

# Gold
devices: done
diagnostics: todo
diagnostics: done
discovery: done
discovery-update-info: done
docs-data-update: done
Expand Down
Loading
Loading