Skip to content
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/aemet/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ class AemetSensorEntityDescription(SensorEntityDescription):
keys=[AOD_WEATHER, AOD_WIND_DIRECTION],
name="Wind bearing",
native_unit_of_measurement=DEGREE,
state_class=SensorStateClass.MEASUREMENT,
state_class=SensorStateClass.MEASUREMENT_ANGLE,
device_class=SensorDeviceClass.WIND_DIRECTION,
),
AemetSensorEntityDescription(
Expand Down
7 changes: 3 additions & 4 deletions homeassistant/components/alexa_devices/strings.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
{
"common": {
"data_country": "Country code",
"data_code": "One-time password (OTP code)",
"data_description_country": "The country of your Amazon account.",
"data_description_country": "The country where your Amazon account is registered.",
"data_description_username": "The email address of your Amazon account.",
"data_description_password": "The password of your Amazon account.",
"data_description_code": "The one-time password to log in to your account. Currently, only tokens from OTP applications are supported."
Expand All @@ -12,10 +11,10 @@
"step": {
"user": {
"data": {
"country": "[%key:component::alexa_devices::common::data_country%]",
"country": "[%key:common::config_flow::data::country%]",
"username": "[%key:common::config_flow::data::username%]",
"password": "[%key:common::config_flow::data::password%]",
"code": "[%key:component::alexa_devices::common::data_description_code%]"
"code": "[%key:component::alexa_devices::common::data_code%]"
},
"data_description": {
"country": "[%key:component::alexa_devices::common::data_description_country%]",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ async def async_get_config_entry_diagnostics(
"title": entry.title,
"data": entry.data,
"options": entry.options,
"subentries": dict(entry.subentries),
},
TO_REDACT,
)
2 changes: 1 addition & 1 deletion homeassistant/components/lametric/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,5 @@ def installed_version(self) -> str:
def latest_version(self) -> str | None:
"""Return the latest version of the entity."""
if not self.coordinator.data.update:
return None
return self.coordinator.data.os_version
return self.coordinator.data.update.version
64 changes: 38 additions & 26 deletions homeassistant/components/matter/vacuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,25 @@ class MatterVacuum(MatterEntity, StateVacuumEntity):

_last_accepted_commands: list[int] | None = None
_supported_run_modes: (
dict[int, clusters.RvcCleanMode.Structs.ModeOptionStruct] | None
dict[int, clusters.RvcRunMode.Structs.ModeOptionStruct] | None
) = None
entity_description: StateVacuumEntityDescription
_platform_translation_key = "vacuum"

async def async_stop(self, **kwargs: Any) -> None:
"""Stop the vacuum cleaner."""
await self.send_device_command(clusters.OperationalState.Commands.Stop())
# We simply set the RvcRunMode to the first runmode
# that has the idle tag to stop the vacuum cleaner.
# this is compatible with both Matter 1.2 and 1.3+ devices.
supported_run_modes = self._supported_run_modes or {}
for mode in supported_run_modes.values():
for tag in mode.modeTags:
if tag.value == ModeTag.IDLE:
# stop the vacuum by changing the run mode to idle
await self.send_device_command(
clusters.RvcRunMode.Commands.ChangeToMode(newMode=mode.mode)
)
return

async def async_return_to_base(self, **kwargs: Any) -> None:
"""Set the vacuum cleaner to return to the dock."""
Expand All @@ -83,15 +94,30 @@ async def async_start(self) -> None:
"""Start or resume the cleaning task."""
if TYPE_CHECKING:
assert self._last_accepted_commands is not None

accepted_operational_commands = self._last_accepted_commands
if (
clusters.RvcOperationalState.Commands.Resume.command_id
in self._last_accepted_commands
in accepted_operational_commands
and self.state == VacuumActivity.PAUSED
):
# vacuum is paused and supports resume command
await self.send_device_command(
clusters.RvcOperationalState.Commands.Resume()
)
else:
await self.send_device_command(clusters.OperationalState.Commands.Start())
return

# We simply set the RvcRunMode to the first runmode
# that has the cleaning tag to start the vacuum cleaner.
# this is compatible with both Matter 1.2 and 1.3+ devices.
supported_run_modes = self._supported_run_modes or {}
for mode in supported_run_modes.values():
for tag in mode.modeTags:
if tag.value == ModeTag.CLEANING:
await self.send_device_command(
clusters.RvcRunMode.Commands.ChangeToMode(newMode=mode.mode)
)
return

async def async_pause(self) -> None:
"""Pause the cleaning task."""
Expand Down Expand Up @@ -130,6 +156,8 @@ def _update_from_device(self) -> None:
state = VacuumActivity.CLEANING
elif ModeTag.IDLE in tags:
state = VacuumActivity.IDLE
elif ModeTag.MAPPING in tags:
state = VacuumActivity.CLEANING
self._attr_activity = state

@callback
Expand All @@ -143,7 +171,10 @@ def _calculate_features(self) -> None:
return
self._last_accepted_commands = accepted_operational_commands
supported_features: VacuumEntityFeature = VacuumEntityFeature(0)
supported_features |= VacuumEntityFeature.START
supported_features |= VacuumEntityFeature.STATE
supported_features |= VacuumEntityFeature.STOP

# optional battery attribute = battery feature
if self.get_matter_attribute_value(
clusters.PowerSource.Attributes.BatPercentRemaining
Expand All @@ -153,7 +184,7 @@ def _calculate_features(self) -> None:
if self.get_matter_attribute_value(clusters.Identify.Attributes.IdentifyType):
supported_features |= VacuumEntityFeature.LOCATE
# create a map of supported run modes
run_modes: list[clusters.RvcCleanMode.Structs.ModeOptionStruct] = (
run_modes: list[clusters.RvcRunMode.Structs.ModeOptionStruct] = (
self.get_matter_attribute_value(
clusters.RvcRunMode.Attributes.SupportedModes
)
Expand All @@ -165,22 +196,6 @@ def _calculate_features(self) -> None:
in accepted_operational_commands
):
supported_features |= VacuumEntityFeature.PAUSE
if (
clusters.OperationalState.Commands.Stop.command_id
in accepted_operational_commands
):
supported_features |= VacuumEntityFeature.STOP
if (
clusters.OperationalState.Commands.Start.command_id
in accepted_operational_commands
):
# note that start has been replaced by resume in rev2 of the spec
supported_features |= VacuumEntityFeature.START
if (
clusters.RvcOperationalState.Commands.Resume.command_id
in accepted_operational_commands
):
supported_features |= VacuumEntityFeature.START
if (
clusters.RvcOperationalState.Commands.GoHome.command_id
in accepted_operational_commands
Expand All @@ -202,10 +217,7 @@ def _calculate_features(self) -> None:
clusters.RvcRunMode.Attributes.CurrentMode,
clusters.RvcOperationalState.Attributes.OperationalState,
),
optional_attributes=(
clusters.RvcCleanMode.Attributes.CurrentMode,
clusters.PowerSource.Attributes.BatPercentRemaining,
),
optional_attributes=(clusters.PowerSource.Attributes.BatPercentRemaining,),
device_type=(device_types.RoboticVacuumCleaner,),
allow_none_value=True,
),
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/zwave_js/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3105,7 +3105,7 @@ def set_driver_ready(event: dict) -> None:
driver.once("driver ready", set_driver_ready),
]

await controller.async_restore_nvm_base64(msg["data"])
await controller.async_restore_nvm_base64(msg["data"], {"preserveRoutes": False})

with suppress(TimeoutError):
async with asyncio.timeout(DRIVER_READY_TIMEOUT):
Expand Down
4 changes: 3 additions & 1 deletion homeassistant/components/zwave_js/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -1400,7 +1400,9 @@ def set_driver_ready(event: dict) -> None:
driver.once("driver ready", set_driver_ready),
]
try:
await controller.async_restore_nvm(self.backup_data)
await controller.async_restore_nvm(
self.backup_data, {"preserveRoutes": False}
)
except FailedCommand as err:
raise AbortFlow(f"Failed to restore network: {err}") from err
else:
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/zwave_js/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"integration_type": "hub",
"iot_class": "local_push",
"loggers": ["zwave_js_server"],
"requirements": ["pyserial==3.5", "zwave-js-server-python==0.64.0"],
"requirements": ["pyserial==3.5", "zwave-js-server-python==0.65.0"],
"usb": [
{
"vid": "0658",
Expand Down
1 change: 1 addition & 0 deletions homeassistant/config_entries.py
Original file line number Diff line number Diff line change
Expand Up @@ -1646,6 +1646,7 @@ async def async_finish_flow(
report_usage(
"creates a config entry when another entry with the same unique ID "
"exists",
breaks_in_ha_version="2026.3",
core_behavior=ReportBehavior.LOG,
core_integration_behavior=ReportBehavior.LOG,
custom_integration_behavior=ReportBehavior.LOG,
Expand Down
2 changes: 1 addition & 1 deletion requirements_all.txt

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

2 changes: 1 addition & 1 deletion requirements_test_all.txt

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

Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,14 @@ def mock_config_entry(hass: HomeAssistant) -> MockConfigEntry:
"data": {},
"subentry_type": "conversation",
"title": DEFAULT_CONVERSATION_NAME,
"subentry_id": "ulid-conversation",
"unique_id": None,
},
{
"data": {},
"subentry_type": "tts",
"title": DEFAULT_TTS_NAME,
"subentry_id": "ulid-tts",
"unique_id": None,
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,35 @@
'api_key': '**REDACTED**',
}),
'options': dict({
'chat_model': 'models/gemini-2.5-flash',
'dangerous_block_threshold': 'BLOCK_MEDIUM_AND_ABOVE',
'harassment_block_threshold': 'BLOCK_MEDIUM_AND_ABOVE',
'hate_block_threshold': 'BLOCK_MEDIUM_AND_ABOVE',
'max_tokens': 1500,
'prompt': 'Speak like a pirate',
'recommended': False,
'sexual_block_threshold': 'BLOCK_MEDIUM_AND_ABOVE',
'temperature': 1.0,
'top_k': 64,
'top_p': 0.95,
}),
'subentries': dict({
'ulid-conversation': dict({
'data': dict({
'chat_model': 'models/gemini-2.5-flash',
'dangerous_block_threshold': 'BLOCK_MEDIUM_AND_ABOVE',
'harassment_block_threshold': 'BLOCK_MEDIUM_AND_ABOVE',
'hate_block_threshold': 'BLOCK_MEDIUM_AND_ABOVE',
'max_tokens': 1500,
'prompt': 'Speak like a pirate',
'recommended': False,
'sexual_block_threshold': 'BLOCK_MEDIUM_AND_ABOVE',
'temperature': 1.0,
'top_k': 64,
'top_p': 0.95,
}),
'subentry_id': 'ulid-conversation',
'subentry_type': 'conversation',
'title': 'Google AI Conversation',
'unique_id': None,
}),
'ulid-tts': dict({
'data': dict({
}),
'subentry_id': 'ulid-tts',
'subentry_type': 'tts',
'title': 'Google AI TTS',
'unique_id': None,
}),
}),
'title': 'Google Generative AI Conversation',
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ async def test_diagnostics(
snapshot: SnapshotAssertion,
) -> None:
"""Test diagnostics."""
mock_config_entry.add_to_hass(hass)
hass.config_entries.async_update_entry(
hass.config_entries.async_update_subentry(
mock_config_entry,
options={
next(iter(mock_config_entry.subentries.values())),
data={
CONF_RECOMMENDED: False,
CONF_PROMPT: "Speak like a pirate",
CONF_TEMPERATURE: RECOMMENDED_TEMPERATURE,
Expand Down
4 changes: 2 additions & 2 deletions tests/components/matter/snapshots/test_vacuum.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
'platform': 'matter',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': <VacuumEntityFeature: 12308>,
'supported_features': <VacuumEntityFeature: 12316>,
'translation_key': None,
'unique_id': '00000000000004D2-0000000000000042-MatterNodeDevice-1-MatterVacuumCleaner-84-1',
'unit_of_measurement': None,
Expand All @@ -38,7 +38,7 @@
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Mock Vacuum',
'supported_features': <VacuumEntityFeature: 12308>,
'supported_features': <VacuumEntityFeature: 12316>,
}),
'context': <ANY>,
'entity_id': 'vacuum.mock_vacuum',
Expand Down
Loading
Loading