Skip to content

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

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 12 commits into from
May 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
6 changes: 3 additions & 3 deletions homeassistant/components/blink/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"config": {
"step": {
"user": {
"title": "Sign-in with Blink account",
"title": "Sign in with Blink account",
"data": {
"username": "[%key:common::config_flow::data::username%]",
"password": "[%key:common::config_flow::data::password%]"
Expand Down Expand Up @@ -30,7 +30,7 @@
"step": {
"simple_options": {
"data": {
"scan_interval": "Scan Interval (seconds)"
"scan_interval": "Scan interval (seconds)"
},
"title": "Blink options",
"description": "Configure Blink integration"
Expand Down Expand Up @@ -93,7 +93,7 @@
},
"config_entry_id": {
"name": "Integration ID",
"description": "The Blink Integration ID."
"description": "The Blink integration ID."
}
}
}
Expand Down
65 changes: 9 additions & 56 deletions homeassistant/components/esphome/entry_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from dataclasses import dataclass, field
from functools import partial
import logging
from operator import delitem
from typing import TYPE_CHECKING, Any, Final, TypedDict, cast

from aioesphomeapi import (
Expand Down Expand Up @@ -183,18 +184,7 @@ def async_register_static_info_callback(
"""Register to receive callbacks when static info changes for an EntityInfo type."""
callbacks = self.entity_info_callbacks.setdefault(entity_info_type, [])
callbacks.append(callback_)
return partial(
self._async_unsubscribe_register_static_info, callbacks, callback_
)

@callback
def _async_unsubscribe_register_static_info(
self,
callbacks: list[Callable[[list[EntityInfo]], None]],
callback_: Callable[[list[EntityInfo]], None],
) -> None:
"""Unsubscribe to when static info is registered."""
callbacks.remove(callback_)
return partial(callbacks.remove, callback_)

@callback
def async_register_key_static_info_updated_callback(
Expand All @@ -206,18 +196,7 @@ def async_register_key_static_info_updated_callback(
callback_key = (type(static_info), static_info.key)
callbacks = self.entity_info_key_updated_callbacks.setdefault(callback_key, [])
callbacks.append(callback_)
return partial(
self._async_unsubscribe_static_key_info_updated, callbacks, callback_
)

@callback
def _async_unsubscribe_static_key_info_updated(
self,
callbacks: list[Callable[[EntityInfo], None]],
callback_: Callable[[EntityInfo], None],
) -> None:
"""Unsubscribe to when static info is updated ."""
callbacks.remove(callback_)
return partial(callbacks.remove, callback_)

@callback
def async_set_assist_pipeline_state(self, state: bool) -> None:
Expand All @@ -232,14 +211,7 @@ def async_subscribe_assist_pipeline_update(
) -> CALLBACK_TYPE:
"""Subscribe to assist pipeline updates."""
self.assist_pipeline_update_callbacks.append(update_callback)
return partial(self._async_unsubscribe_assist_pipeline_update, update_callback)

@callback
def _async_unsubscribe_assist_pipeline_update(
self, update_callback: CALLBACK_TYPE
) -> None:
"""Unsubscribe to assist pipeline updates."""
self.assist_pipeline_update_callbacks.remove(update_callback)
return partial(self.assist_pipeline_update_callbacks.remove, update_callback)

@callback
def async_remove_entities(
Expand Down Expand Up @@ -337,27 +309,15 @@ async def async_update_static_infos(
def async_subscribe_device_updated(self, callback_: CALLBACK_TYPE) -> CALLBACK_TYPE:
"""Subscribe to state updates."""
self.device_update_subscriptions.add(callback_)
return partial(self._async_unsubscribe_device_update, callback_)

@callback
def _async_unsubscribe_device_update(self, callback_: CALLBACK_TYPE) -> None:
"""Unsubscribe to device updates."""
self.device_update_subscriptions.remove(callback_)
return partial(self.device_update_subscriptions.remove, callback_)

@callback
def async_subscribe_static_info_updated(
self, callback_: Callable[[list[EntityInfo]], None]
) -> CALLBACK_TYPE:
"""Subscribe to static info updates."""
self.static_info_update_subscriptions.add(callback_)
return partial(self._async_unsubscribe_static_info_updated, callback_)

@callback
def _async_unsubscribe_static_info_updated(
self, callback_: Callable[[list[EntityInfo]], None]
) -> None:
"""Unsubscribe to static info updates."""
self.static_info_update_subscriptions.remove(callback_)
return partial(self.static_info_update_subscriptions.remove, callback_)

@callback
def async_subscribe_state_update(
Expand All @@ -369,14 +329,7 @@ def async_subscribe_state_update(
"""Subscribe to state updates."""
subscription_key = (state_type, state_key)
self.state_subscriptions[subscription_key] = entity_callback
return partial(self._async_unsubscribe_state_update, subscription_key)

@callback
def _async_unsubscribe_state_update(
self, subscription_key: tuple[type[EntityState], int]
) -> None:
"""Unsubscribe to state updates."""
self.state_subscriptions.pop(subscription_key)
return partial(delitem, self.state_subscriptions, subscription_key)

@callback
def async_update_state(self, state: EntityState) -> None:
Expand Down Expand Up @@ -523,7 +476,7 @@ def async_register_assist_satellite_config_updated_callback(
) -> CALLBACK_TYPE:
"""Register to receive callbacks when the Assist satellite's configuration is updated."""
self.assist_satellite_config_update_callbacks.append(callback_)
return lambda: self.assist_satellite_config_update_callbacks.remove(callback_)
return partial(self.assist_satellite_config_update_callbacks.remove, callback_)

@callback
def async_assist_satellite_config_updated(
Expand All @@ -540,7 +493,7 @@ def async_register_assist_satellite_set_wake_word_callback(
) -> CALLBACK_TYPE:
"""Register to receive callbacks when the Assist satellite's wake word is set."""
self.assist_satellite_set_wake_word_callbacks.append(callback_)
return lambda: self.assist_satellite_set_wake_word_callbacks.remove(callback_)
return partial(self.assist_satellite_set_wake_word_callbacks.remove, callback_)

@callback
def async_assist_satellite_set_wake_word(self, wake_word_id: str) -> None:
Expand Down
6 changes: 3 additions & 3 deletions homeassistant/components/heos/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@
"options": {
"step": {
"init": {
"title": "HEOS Options",
"description": "You can sign-in to your HEOS Account to access favorites, streaming services, and other features. Clearing the credentials will sign-out of your account.",
"title": "HEOS options",
"description": "You can sign in to your HEOS Account to access favorites, streaming services, and other features. Clearing the credentials will sign out of your account.",
"data": {
"username": "[%key:common::config_flow::data::username%]",
"password": "[%key:common::config_flow::data::password%]"
Expand Down Expand Up @@ -102,7 +102,7 @@
},
"move_queue_item": {
"name": "Move queue item",
"description": "Move one or more items within the play queue.",
"description": "Moves one or more items within the play queue.",
"fields": {
"queue_ids": {
"name": "Queue IDs",
Expand Down
28 changes: 27 additions & 1 deletion homeassistant/components/intent/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
import voluptuous as vol

from homeassistant.components import http, sensor
from homeassistant.components.button import (
DOMAIN as BUTTON_DOMAIN,
SERVICE_PRESS as SERVICE_PRESS_BUTTON,
ButtonDeviceClass,
)
from homeassistant.components.climate import DOMAIN as CLIMATE_DOMAIN
from homeassistant.components.cover import (
ATTR_POSITION,
Expand All @@ -20,6 +25,7 @@
CoverDeviceClass,
)
from homeassistant.components.http.data_validator import RequestDataValidator
from homeassistant.components.input_button import DOMAIN as INPUT_BUTTON_DOMAIN
from homeassistant.components.lock import (
DOMAIN as LOCK_DOMAIN,
SERVICE_LOCK,
Expand Down Expand Up @@ -80,6 +86,7 @@
]

ONOFF_DEVICE_CLASSES = {
ButtonDeviceClass,
CoverDeviceClass,
ValveDeviceClass,
SwitchDeviceClass,
Expand All @@ -103,7 +110,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
intent.INTENT_TURN_ON,
HOMEASSISTANT_DOMAIN,
SERVICE_TURN_ON,
description="Turns on/opens a device or entity. For locks, this performs a 'lock' action. Use for requests like 'turn on', 'activate', 'enable', or 'lock'.",
description="Turns on/opens/presses a device or entity. For locks, this performs a 'lock' action. Use for requests like 'turn on', 'activate', 'enable', or 'lock'.",
device_classes=ONOFF_DEVICE_CLASSES,
),
)
Expand Down Expand Up @@ -168,6 +175,25 @@ async def async_call_service(
"""Call service on entity with handling for special cases."""
hass = intent_obj.hass

if state.domain in (BUTTON_DOMAIN, INPUT_BUTTON_DOMAIN):
if service != SERVICE_TURN_ON:
raise intent.IntentHandleError(
f"Entity {state.entity_id} cannot be turned off"
)

await self._run_then_background(
hass.async_create_task(
hass.services.async_call(
state.domain,
SERVICE_PRESS_BUTTON,
{ATTR_ENTITY_ID: state.entity_id},
context=intent_obj.context,
blocking=True,
)
)
)
return

if state.domain == COVER_DOMAIN:
# on = open
# off = close
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/peco/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"user": {
"data": {
"county": "County",
"phone_number": "Phone Number"
"phone_number": "Phone number"
},
"data_description": {
"county": "County used for outage number retrieval",
Expand Down
5 changes: 3 additions & 2 deletions homeassistant/components/rehlko/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ async def async_refresh_token_update(refresh_token: str) -> None:
)

rehlko.set_refresh_token_callback(async_refresh_token_update)
rehlko.set_retry_policy(retry_count=3, retry_delays=[5, 10, 20])

try:
await rehlko.authenticate(
entry.data[CONF_EMAIL],
entry.data[CONF_PASSWORD],
entry.data.get(CONF_REFRESH_TOKEN),
)
homes = await rehlko.get_homes()
except AuthenticationError as ex:
raise ConfigEntryAuthFailed(
translation_domain=DOMAIN,
Expand All @@ -60,7 +60,6 @@ async def async_refresh_token_update(refresh_token: str) -> None:
translation_key="cannot_connect",
) from ex
coordinators: dict[int, RehlkoUpdateCoordinator] = {}
homes = await rehlko.get_homes()

entry.runtime_data = RehlkoRuntimeData(
coordinators=coordinators,
Expand All @@ -86,6 +85,8 @@ async def async_refresh_token_update(refresh_token: str) -> None:
await coordinator.async_config_entry_first_refresh()
coordinators[device_id] = coordinator
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
# Retrys enabled after successful connection to prevent blocking startup
rehlko.set_retry_policy(retry_count=3, retry_delays=[5, 10, 20])
return True


Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/rehlko/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@
"iot_class": "cloud_polling",
"loggers": ["aiokem"],
"quality_scale": "silver",
"requirements": ["aiokem==0.5.9"]
"requirements": ["aiokem==0.5.10"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/ring/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"config": {
"step": {
"user": {
"title": "Sign-in with Ring account",
"title": "Sign in with Ring account",
"data": {
"username": "[%key:common::config_flow::data::username%]",
"password": "[%key:common::config_flow::data::password%]"
Expand Down
6 changes: 3 additions & 3 deletions homeassistant/components/tami4/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@
"config": {
"step": {
"user": {
"title": "SMS Verification",
"title": "SMS verification",
"description": "Enter your phone number (same as what you used to register to the tami4 app)",
"data": {
"phone": "Phone Number"
"phone": "Phone number"
}
},
"otp": {
"title": "[%key:component::tami4::config::step::user::title%]",
"description": "Enter the code you received via SMS",
"data": {
"otp": "SMS Code"
"otp": "SMS code"
}
}
},
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/technove/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@
},
"switch": {
"auto_charge": {
"name": "Auto charge"
"name": "Auto-charge"
},
"session_active": {
"name": "Charging Enabled"
"name": "Charging enabled"
}
}
},
Expand Down
6 changes: 3 additions & 3 deletions homeassistant/components/verisure/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
"step": {
"user": {
"data": {
"description": "Sign-in with your Verisure My Pages account.",
"description": "Sign in with your Verisure My Pages account.",
"email": "[%key:common::config_flow::data::email%]",
"password": "[%key:common::config_flow::data::password%]"
}
},
"mfa": {
"data": {
"description": "Your account has 2-step verification enabled. Please enter the verification code Verisure sends to you.",
"code": "Verification Code"
"code": "Verification code"
}
},
"installation": {
Expand All @@ -37,7 +37,7 @@
"error": {
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"unknown": "[%key:common::config_flow::error::unknown%]",
"unknown_mfa": "Unknown error occurred during MFA set up"
"unknown_mfa": "Unknown error occurred during MFA setup"
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_account%]",
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/zwave_me/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"config": {
"step": {
"user": {
"description": "Input IP address with port and access token of Z-Way server. To get the token go to the Z-Way user interface Smart Home UI > Menu > Settings > Users > Administrator > API token.\n\nExample of connecting to Z-Way running as an add-on:\nURL: {add_on_url}\nToken: {local_token}\n\nExample of connecting to Z-Way in the local network:\nURL: {local_url}\nToken: {local_token}\n\nExample of connecting to Z-Way via remote access find.z-wave.me:\nURL: {find_url}\nToken: {find_token}\n\nExample of connecting to Z-Way with a static public IP address:\nURL: {remote_url}\nToken: {local_token}\n\nWhen connecting via find.z-wave.me you need to use a token with a global scope (log-in to Z-Way via find.z-wave.me for this).",
"description": "Input IP address with port and access token of Z-Way server. To get the token go to the Z-Way user interface Smart Home UI > Menu > Settings > Users > Administrator > API token.\n\nExample of connecting to Z-Way running as an add-on:\nURL: {add_on_url}\nToken: {local_token}\n\nExample of connecting to Z-Way in the local network:\nURL: {local_url}\nToken: {local_token}\n\nExample of connecting to Z-Way via remote access find.z-wave.me:\nURL: {find_url}\nToken: {find_token}\n\nExample of connecting to Z-Way with a static public IP address:\nURL: {remote_url}\nToken: {local_token}\n\nWhen connecting via find.z-wave.me you need to use a token with a global scope (log in to Z-Way via find.z-wave.me for this).",
"data": {
"url": "[%key:common::config_flow::data::url%]",
"token": "[%key:common::config_flow::data::api_token%]"
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