Skip to content

[pull] dev from home-assistant:dev #982

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 4, 2025
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
18 changes: 9 additions & 9 deletions homeassistant/components/airos/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
from typing import Any

from airos.exceptions import (
ConnectionAuthenticationError,
ConnectionSetupError,
DataMissingError,
DeviceConnectionError,
KeyDataMissingError,
AirOSConnectionAuthenticationError,
AirOSConnectionSetupError,
AirOSDataMissingError,
AirOSDeviceConnectionError,
AirOSKeyDataMissingError,
)
import voluptuous as vol

Expand Down Expand Up @@ -59,13 +59,13 @@ async def async_step_user(
airos_data = await airos_device.status()

except (
ConnectionSetupError,
DeviceConnectionError,
AirOSConnectionSetupError,
AirOSDeviceConnectionError,
):
errors["base"] = "cannot_connect"
except (ConnectionAuthenticationError, DataMissingError):
except (AirOSConnectionAuthenticationError, AirOSDataMissingError):
errors["base"] = "invalid_auth"
except KeyDataMissingError:
except AirOSKeyDataMissingError:
errors["base"] = "key_data_missing"
except Exception:
_LOGGER.exception("Unexpected exception")
Expand Down
18 changes: 11 additions & 7 deletions homeassistant/components/airos/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

from airos.airos8 import AirOS, AirOSData
from airos.exceptions import (
ConnectionAuthenticationError,
ConnectionSetupError,
DataMissingError,
DeviceConnectionError,
AirOSConnectionAuthenticationError,
AirOSConnectionSetupError,
AirOSDataMissingError,
AirOSDeviceConnectionError,
)

from homeassistant.config_entries import ConfigEntry
Expand Down Expand Up @@ -47,18 +47,22 @@ async def _async_update_data(self) -> AirOSData:
try:
await self.airos_device.login()
return await self.airos_device.status()
except (ConnectionAuthenticationError,) as err:
except (AirOSConnectionAuthenticationError,) as err:
_LOGGER.exception("Error authenticating with airOS device")
raise ConfigEntryError(
translation_domain=DOMAIN, translation_key="invalid_auth"
) from err
except (ConnectionSetupError, DeviceConnectionError, TimeoutError) as err:
except (
AirOSConnectionSetupError,
AirOSDeviceConnectionError,
TimeoutError,
) as err:
_LOGGER.error("Error connecting to airOS device: %s", err)
raise UpdateFailed(
translation_domain=DOMAIN,
translation_key="cannot_connect",
) from err
except (DataMissingError,) as err:
except (AirOSDataMissingError,) as err:
_LOGGER.error("Expected data not returned by airOS device: %s", err)
raise UpdateFailed(
translation_domain=DOMAIN,
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/airos/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/airos",
"iot_class": "local_polling",
"quality_scale": "bronze",
"requirements": ["airos==0.2.1"]
"requirements": ["airos==0.2.4"]
}
7 changes: 0 additions & 7 deletions homeassistant/components/airos/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,6 @@ class AirOSSensorEntityDescription(SensorEntityDescription):
translation_key="wireless_essid",
value_fn=lambda data: data.wireless.essid,
),
AirOSSensorEntityDescription(
key="wireless_mode",
translation_key="wireless_mode",
device_class=SensorDeviceClass.ENUM,
value_fn=lambda data: data.wireless.mode.value.replace("-", "_").lower(),
options=WIRELESS_MODE_OPTIONS,
),
AirOSSensorEntityDescription(
key="wireless_antenna_gain",
translation_key="wireless_antenna_gain",
Expand Down
7 changes: 0 additions & 7 deletions homeassistant/components/airos/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,6 @@
"wireless_essid": {
"name": "Wireless SSID"
},
"wireless_mode": {
"name": "Wireless mode",
"state": {
"ap_ptp": "Access point",
"sta_ptp": "Station"
}
},
"wireless_antenna_gain": {
"name": "Antenna gain"
},
Expand Down
4 changes: 4 additions & 0 deletions homeassistant/components/hassio/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,10 @@
"unsupported_virtualization_image": {
"title": "Unsupported system - Incorrect OS image for virtualization",
"description": "System is unsupported because the Home Assistant OS image in use is not intended for use in a virtualized environment. Use the link to learn more and how to fix this."
},
"unsupported_os_version": {
"title": "Unsupported system - Home Assistant OS version",
"description": "System is unsupported because the Home Assistant OS version in use is not supported. Use the link to learn more and how to fix this."
}
},
"entity": {
Expand Down
25 changes: 25 additions & 0 deletions homeassistant/components/husqvarna_automower/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,28 @@
PARALLEL_UPDATES = 1


async def async_reset_cutting_blade_usage_time(
session: AutomowerSession,
mower_id: str,
) -> None:
"""Reset cutting blade usage time."""
await session.commands.reset_cutting_blade_usage_time(mower_id)


def reset_cutting_blade_usage_time_availability(data: MowerAttributes) -> bool:
"""Return True if blade usage time is greater than 0."""
value = data.statistics.cutting_blade_usage_time
return value is not None and value > 0


@dataclass(frozen=True, kw_only=True)
class AutomowerButtonEntityDescription(ButtonEntityDescription):
"""Describes Automower button entities."""

available_fn: Callable[[MowerAttributes], bool] = lambda _: True
exists_fn: Callable[[MowerAttributes], bool] = lambda _: True
press_fn: Callable[[AutomowerSession, str], Awaitable[Any]]
poll_after_sending: bool = False


MOWER_BUTTON_TYPES: tuple[AutomowerButtonEntityDescription, ...] = (
Expand All @@ -43,6 +58,14 @@ class AutomowerButtonEntityDescription(ButtonEntityDescription):
translation_key="sync_clock",
press_fn=lambda session, mower_id: session.commands.set_datetime(mower_id),
),
AutomowerButtonEntityDescription(
key="reset_cutting_blade_usage_time",
translation_key="reset_cutting_blade_usage_time",
available_fn=reset_cutting_blade_usage_time_availability,
exists_fn=lambda data: data.statistics.cutting_blade_usage_time is not None,
press_fn=async_reset_cutting_blade_usage_time,
poll_after_sending=True,
),
)


Expand Down Expand Up @@ -93,3 +116,5 @@ def available(self) -> bool:
async def async_press(self) -> None:
"""Send a command to the mower."""
await self.entity_description.press_fn(self.coordinator.api, self.mower_id)
if self.entity_description.poll_after_sending:
await self.coordinator.async_request_refresh()
3 changes: 3 additions & 0 deletions homeassistant/components/husqvarna_automower/icons.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
"button": {
"sync_clock": {
"default": "mdi:clock-check-outline"
},
"reset_cutting_blade_usage_time": {
"default": "mdi:saw-blade"
}
},
"number": {
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/husqvarna_automower/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
},
"sync_clock": {
"name": "Sync clock"
},
"reset_cutting_blade_usage_time": {
"name": "Reset cutting blade usage time"
}
},
"number": {
Expand Down
7 changes: 5 additions & 2 deletions homeassistant/components/reolink/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ class ReolinkChimeNumberEntityDescription(
cmd_id=[289, 438],
translation_key="floodlight_brightness",
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
native_step=1,
native_min_value=1,
native_max_value=100,
Expand Down Expand Up @@ -407,8 +408,8 @@ class ReolinkChimeNumberEntityDescription(
key="auto_track_limit_left",
cmd_key="GetPtzTraceSection",
translation_key="auto_track_limit_left",
mode=NumberMode.SLIDER,
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
native_step=1,
native_min_value=-1,
native_max_value=2700,
Expand All @@ -420,8 +421,8 @@ class ReolinkChimeNumberEntityDescription(
key="auto_track_limit_right",
cmd_key="GetPtzTraceSection",
translation_key="auto_track_limit_right",
mode=NumberMode.SLIDER,
entity_category=EntityCategory.CONFIG,
entity_registry_enabled_default=False,
native_step=1,
native_min_value=-1,
native_max_value=2700,
Expand All @@ -435,6 +436,7 @@ class ReolinkChimeNumberEntityDescription(
translation_key="auto_track_disappear_time",
entity_category=EntityCategory.CONFIG,
device_class=NumberDeviceClass.DURATION,
entity_registry_enabled_default=False,
native_step=1,
native_unit_of_measurement=UnitOfTime.SECONDS,
native_min_value=1,
Expand All @@ -451,6 +453,7 @@ class ReolinkChimeNumberEntityDescription(
translation_key="auto_track_stop_time",
entity_category=EntityCategory.CONFIG,
device_class=NumberDeviceClass.DURATION,
entity_registry_enabled_default=False,
native_step=1,
native_unit_of_measurement=UnitOfTime.SECONDS,
native_min_value=1,
Expand Down
6 changes: 6 additions & 0 deletions homeassistant/components/template/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,12 @@
}
}
},
"issues": {
"deprecated_battery_level": {
"title": "Deprecated battery level option in {entity_name}",
"description": "The template vacuum options `battery_level` and `battery_level_template` are being removed in 2026.8.\n\nPlease remove the `battery_level` or `battery_level_template` option from the YAML configuration for {entity_id} ({entity_name})."
}
},
"options": {
"step": {
"alarm_control_panel": {
Expand Down
47 changes: 46 additions & 1 deletion homeassistant/components/template/vacuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,16 @@
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import TemplateError
from homeassistant.helpers import config_validation as cv, template
from homeassistant.helpers import (
config_validation as cv,
issue_registry as ir,
template,
)
from homeassistant.helpers.entity_platform import (
AddConfigEntryEntitiesCallback,
AddEntitiesCallback,
)
from homeassistant.helpers.issue_registry import IssueSeverity
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType

from .const import DOMAIN
Expand Down Expand Up @@ -188,6 +193,26 @@ def async_create_preview_vacuum(
)


def create_issue(
hass: HomeAssistant, supported_features: int, name: str, entity_id: str
) -> None:
"""Create the battery_level issue."""
if supported_features & VacuumEntityFeature.BATTERY:
key = "deprecated_battery_level"
ir.async_create_issue(
hass,
DOMAIN,
f"{key}_{entity_id}",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key=key,
translation_placeholders={
"entity_name": name,
"entity_id": entity_id,
},
)


class AbstractTemplateVacuum(AbstractTemplateEntity, StateVacuumEntity):
"""Representation of a template vacuum features."""

Expand Down Expand Up @@ -369,6 +394,16 @@ def __init__(
self.add_script(action_id, action_config, name, DOMAIN)
self._attr_supported_features |= supported_feature

async def async_added_to_hass(self) -> None:
"""Run when entity about to be added to hass."""
await super().async_added_to_hass()
create_issue(
self.hass,
self._attr_supported_features,
self._attr_name or DEFAULT_NAME,
self.entity_id,
)

@callback
def _async_setup_templates(self) -> None:
"""Set up templates."""
Expand Down Expand Up @@ -434,6 +469,16 @@ def __init__(
self._to_render_simple.append(key)
self._parse_result.add(key)

async def async_added_to_hass(self) -> None:
"""Run when entity about to be added to hass."""
await super().async_added_to_hass()
create_issue(
self.hass,
self._attr_supported_features,
self._attr_name or DEFAULT_NAME,
self.entity_id,
)

@callback
def _handle_coordinator_update(self) -> None:
"""Handle update of the data."""
Expand Down
10 changes: 10 additions & 0 deletions homeassistant/components/tuya/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,16 @@ class TuyaBinarySensorEntityDescription(BinarySensorEntityDescription):
),
TAMPER_BINARY_SENSOR,
),
# Zigbee gateway
# Undocumented
"wg2": (
TuyaBinarySensorEntityDescription(
key=DPCode.MASTER_STATE,
device_class=BinarySensorDeviceClass.PROBLEM,
entity_category=EntityCategory.DIAGNOSTIC,
on_value="alarm",
),
),
# Thermostatic Radiator Valve
# Not documented
"wkf": (
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.

Loading
Loading