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/enphase_envoy/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"iot_class": "local_polling",
"loggers": ["pyenphase"],
"quality_scale": "platinum",
"requirements": ["pyenphase==2.2.0"],
"requirements": ["pyenphase==2.2.1"],
"zeroconf": [
{
"type": "_enphase-envoy._tcp.local."
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/gios/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"integration_type": "service",
"iot_class": "cloud_polling",
"loggers": ["dacite", "gios"],
"requirements": ["gios==6.0.0"]
"requirements": ["gios==6.1.0"]
}
4 changes: 2 additions & 2 deletions homeassistant/components/google_assistant_sdk/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ async def async_send_text_commands(

credentials = Credentials(session.token[CONF_ACCESS_TOKEN]) # type: ignore[no-untyped-call]
language_code = entry.options.get(CONF_LANGUAGE_CODE, default_language_code(hass))
command_response_list = []
with TextAssistant(
credentials, language_code, audio_out=bool(media_players)
) as assistant:
command_response_list = []
for command in commands:
try:
resp = await hass.async_add_executor_job(assistant.assist, command)
Expand Down Expand Up @@ -117,7 +117,7 @@ async def async_send_text_commands(
blocking=True,
)
command_response_list.append(CommandResponse(text_response))
return command_response_list
return command_response_list


def default_language_code(hass: HomeAssistant) -> str:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
"documentation": "https://www.home-assistant.io/integrations/google_assistant_sdk",
"integration_type": "service",
"iot_class": "cloud_polling",
"requirements": ["gassist-text==0.0.12"],
"requirements": ["gassist-text==0.0.14"],
"single_config_entry": true
}
9 changes: 7 additions & 2 deletions homeassistant/components/homeassistant/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,14 @@
from homeassistant.helpers.issue_registry import IssueSeverity
from homeassistant.helpers.service import (
async_extract_config_entry_ids,
async_extract_referenced_entity_ids,
async_register_admin_service,
)
from homeassistant.helpers.signal import KEY_HA_STOP
from homeassistant.helpers.system_info import async_get_system_info
from homeassistant.helpers.target import (
TargetSelectorData,
async_extract_referenced_entity_ids,
)
from homeassistant.helpers.template import async_load_custom_templates
from homeassistant.helpers.typing import ConfigType

Expand Down Expand Up @@ -111,7 +114,9 @@ async def async_save_persistent_states(service: ServiceCall) -> None:

async def async_handle_turn_service(service: ServiceCall) -> None:
"""Handle calls to homeassistant.turn_on/off."""
referenced = async_extract_referenced_entity_ids(hass, service)
referenced = async_extract_referenced_entity_ids(
hass, TargetSelectorData(service.data)
)
all_referenced = referenced.referenced | referenced.indirectly_referenced

# Generic turn on/off method requires entity id
Expand Down
11 changes: 7 additions & 4 deletions homeassistant/components/homekit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,12 @@
EntityFilter,
)
from homeassistant.helpers.reload import async_integration_yaml_config
from homeassistant.helpers.service import (
from homeassistant.helpers.service import async_register_admin_service
from homeassistant.helpers.start import async_at_started
from homeassistant.helpers.target import (
TargetSelectorData,
async_extract_referenced_entity_ids,
async_register_admin_service,
)
from homeassistant.helpers.start import async_at_started
from homeassistant.helpers.typing import ConfigType
from homeassistant.loader import IntegrationNotFound, async_get_integration
from homeassistant.util.async_ import create_eager_task
Expand Down Expand Up @@ -482,7 +483,9 @@ async def async_handle_homekit_reset_accessory(service: ServiceCall) -> None:

async def async_handle_homekit_unpair(service: ServiceCall) -> None:
"""Handle unpair HomeKit service call."""
referenced = async_extract_referenced_entity_ids(hass, service)
referenced = async_extract_referenced_entity_ids(
hass, TargetSelectorData(service.data)
)
dev_reg = dr.async_get(hass)
for device_id in referenced.referenced_devices:
if not (dev_reg_ent := dev_reg.async_get(device_id)):
Expand Down
26 changes: 1 addition & 25 deletions homeassistant/components/http/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,7 @@
)
from homeassistant.core import Event, HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import (
config_validation as cv,
frame,
issue_registry as ir,
storage,
)
from homeassistant.helpers import config_validation as cv, issue_registry as ir, storage
from homeassistant.helpers.http import (
KEY_ALLOW_CONFIGURED_CORS,
KEY_AUTHENTICATED, # noqa: F401
Expand Down Expand Up @@ -505,25 +500,6 @@ def _async_register_static_paths(
)
)

def register_static_path(
self, url_path: str, path: str, cache_headers: bool = True
) -> None:
"""Register a folder or file to serve as a static path."""
frame.report_usage(
"calls hass.http.register_static_path which "
"does blocking I/O in the event loop, instead "
"call `await hass.http.async_register_static_paths("
f'[StaticPathConfig("{url_path}", "{path}", {cache_headers})])`',
exclude_integrations={"http"},
core_behavior=frame.ReportBehavior.ERROR,
core_integration_behavior=frame.ReportBehavior.ERROR,
custom_integration_behavior=frame.ReportBehavior.ERROR,
breaks_in_ha_version="2025.7",
)
configs = [StaticPathConfig(url_path, path, cache_headers)]
resources = self._make_static_resources(configs)
self._async_register_static_paths(configs, resources)

def _create_ssl_context(self) -> ssl.SSLContext | None:
context: ssl.SSLContext | None = None
assert self.ssl_certificate is not None
Expand Down
8 changes: 4 additions & 4 deletions homeassistant/components/iskra/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"config": {
"step": {
"user": {
"title": "Configure Iskra Device",
"description": "Enter the IP address of your Iskra Device and select protocol.",
"title": "Configure Iskra device",
"description": "Enter the IP address of your Iskra device and select protocol.",
"data": {
"host": "[%key:common::config_flow::data::host%]"
},
Expand All @@ -12,7 +12,7 @@
}
},
"authentication": {
"title": "Configure Rest API Credentials",
"title": "Configure REST API credentials",
"description": "Enter username and password",
"data": {
"username": "[%key:common::config_flow::data::username%]",
Expand Down Expand Up @@ -44,7 +44,7 @@
"selector": {
"protocol": {
"options": {
"rest_api": "Rest API",
"rest_api": "REST API",
"modbus_tcp": "Modbus TCP"
}
}
Expand Down
10 changes: 7 additions & 3 deletions homeassistant/components/lifx/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
from homeassistant.const import ATTR_MODE
from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.service import async_extract_referenced_entity_ids
from homeassistant.helpers.target import (
TargetSelectorData,
async_extract_referenced_entity_ids,
)

from .const import _ATTR_COLOR_TEMP, ATTR_THEME, DOMAIN
from .coordinator import LIFXConfigEntry, LIFXUpdateCoordinator
Expand Down Expand Up @@ -268,7 +271,9 @@ def async_setup(self) -> None:

async def service_handler(service: ServiceCall) -> None:
"""Apply a service, i.e. start an effect."""
referenced = async_extract_referenced_entity_ids(self.hass, service)
referenced = async_extract_referenced_entity_ids(
self.hass, TargetSelectorData(service.data)
)
all_referenced = referenced.referenced | referenced.indirectly_referenced
if all_referenced:
await self.start_effect(all_referenced, service.service, **service.data)
Expand Down Expand Up @@ -499,6 +504,5 @@ async def start_effect(
if self.entry_id_to_entity_id[entry.entry_id] in entity_ids:
coordinators.append(entry.runtime_data)
bulbs.append(entry.runtime_data.device)

if start_effect_func := self._effect_dispatch.get(service):
await start_effect_func(self, bulbs, coordinators, **kwargs)
19 changes: 18 additions & 1 deletion homeassistant/components/rest/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,16 @@ async def async_update(self, log_errors: bool = True) -> None:
for key, value in rendered_params.items():
if isinstance(value, bool):
rendered_params[key] = str(value).lower()
elif not isinstance(value, (str, int, float, type(None))):
# For backward compatibility with httpx behavior, convert non-primitive
# types to strings. This maintains compatibility after switching from
# httpx to aiohttp. See https://github.com/home-assistant/core/issues/148153
_LOGGER.debug(
"REST query parameter '%s' has type %s, converting to string",
key,
type(value).__name__,
)
rendered_params[key] = str(value)

_LOGGER.debug("Updating from %s", self._resource)
# Create request kwargs
Expand All @@ -140,7 +150,14 @@ async def async_update(self, log_errors: bool = True) -> None:
self._method, self._resource, **request_kwargs
) as response:
# Read the response
self.data = await response.text(encoding=self._encoding)
# Only use configured encoding if no charset in Content-Type header
# If charset is present in Content-Type, let aiohttp use it
if response.charset:
# Let aiohttp use the charset from Content-Type header
self.data = await response.text()
else:
# Use configured encoding as fallback
self.data = await response.text(encoding=self._encoding)
self.headers = response.headers

except TimeoutError as ex:
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/sharkiq/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/sharkiq",
"iot_class": "cloud_polling",
"loggers": ["sharkiq"],
"requirements": ["sharkiq==1.1.0"]
"requirements": ["sharkiq==1.1.1"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/switchbot/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,5 @@
"iot_class": "local_push",
"loggers": ["switchbot"],
"quality_scale": "gold",
"requirements": ["PySwitchbot==0.67.0"]
"requirements": ["PySwitchbot==0.68.1"]
}
15 changes: 10 additions & 5 deletions homeassistant/components/unifiprotect/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@
device_registry as dr,
entity_registry as er,
)
from homeassistant.helpers.service import async_extract_referenced_entity_ids
from homeassistant.helpers.target import (
TargetSelectorData,
async_extract_referenced_entity_ids,
)
from homeassistant.util.json import JsonValueType
from homeassistant.util.read_only_dict import ReadOnlyDict

Expand Down Expand Up @@ -115,7 +118,7 @@ def _async_get_ufp_instance(hass: HomeAssistant, device_id: str) -> ProtectApiCl

@callback
def _async_get_ufp_camera(call: ServiceCall) -> Camera:
ref = async_extract_referenced_entity_ids(call.hass, call)
ref = async_extract_referenced_entity_ids(call.hass, TargetSelectorData(call.data))
entity_registry = er.async_get(call.hass)

entity_id = ref.indirectly_referenced.pop()
Expand All @@ -133,7 +136,7 @@ def _async_get_protect_from_call(call: ServiceCall) -> set[ProtectApiClient]:
return {
_async_get_ufp_instance(call.hass, device_id)
for device_id in async_extract_referenced_entity_ids(
call.hass, call
call.hass, TargetSelectorData(call.data)
).referenced_devices
}

Expand Down Expand Up @@ -196,7 +199,7 @@ def _async_unique_id_to_mac(unique_id: str) -> str:

async def set_chime_paired_doorbells(call: ServiceCall) -> None:
"""Set paired doorbells on chime."""
ref = async_extract_referenced_entity_ids(call.hass, call)
ref = async_extract_referenced_entity_ids(call.hass, TargetSelectorData(call.data))
entity_registry = er.async_get(call.hass)

entity_id = ref.indirectly_referenced.pop()
Expand All @@ -211,7 +214,9 @@ async def set_chime_paired_doorbells(call: ServiceCall) -> None:
assert chime is not None

call.data = ReadOnlyDict(call.data.get("doorbells") or {})
doorbell_refs = async_extract_referenced_entity_ids(call.hass, call)
doorbell_refs = async_extract_referenced_entity_ids(
call.hass, TargetSelectorData(call.data)
)
doorbell_ids: set[str] = set()
for camera_id in doorbell_refs.referenced | doorbell_refs.indirectly_referenced:
doorbell_sensor = entity_registry.async_get(camera_id)
Expand Down
46 changes: 25 additions & 21 deletions homeassistant/components/vacuum/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,16 +321,18 @@ def _report_deprecated_battery_properties(self, property: str) -> None:

Integrations should implement a sensor instead.
"""
report_usage(
f"is setting the {property} which has been deprecated."
f" Integration {self.platform.platform_name} should implement a sensor"
" instead with a correct device class and link it to the same device",
core_integration_behavior=ReportBehavior.LOG,
custom_integration_behavior=ReportBehavior.LOG,
breaks_in_ha_version="2026.8",
integration_domain=self.platform.platform_name if self.platform else None,
exclude_integrations={DOMAIN},
)
if self.platform:
# Don't report usage until after entity added to hass, after init
report_usage(
f"is setting the {property} which has been deprecated."
f" Integration {self.platform.platform_name} should implement a sensor"
" instead with a correct device class and link it to the same device",
core_integration_behavior=ReportBehavior.LOG,
custom_integration_behavior=ReportBehavior.LOG,
breaks_in_ha_version="2026.8",
integration_domain=self.platform.platform_name,
exclude_integrations={DOMAIN},
)

@callback
def _report_deprecated_battery_feature(self) -> None:
Expand All @@ -339,17 +341,19 @@ def _report_deprecated_battery_feature(self) -> None:
Integrations should remove the battery supported feature when migrating
battery level and icon to a sensor.
"""
report_usage(
f"is setting the battery supported feature which has been deprecated."
f" Integration {self.platform.platform_name} should remove this as part of migrating"
" the battery level and icon to a sensor",
core_behavior=ReportBehavior.LOG,
core_integration_behavior=ReportBehavior.LOG,
custom_integration_behavior=ReportBehavior.LOG,
breaks_in_ha_version="2026.8",
integration_domain=self.platform.platform_name if self.platform else None,
exclude_integrations={DOMAIN},
)
if self.platform:
# Don't report usage until after entity added to hass, after init
report_usage(
f"is setting the battery supported feature which has been deprecated."
f" Integration {self.platform.platform_name} should remove this as part of migrating"
" the battery level and icon to a sensor",
core_behavior=ReportBehavior.LOG,
core_integration_behavior=ReportBehavior.LOG,
custom_integration_behavior=ReportBehavior.LOG,
breaks_in_ha_version="2026.8",
integration_domain=self.platform.platform_name,
exclude_integrations={DOMAIN},
)

@cached_property
def battery_level(self) -> int | None:
Expand Down
10 changes: 5 additions & 5 deletions homeassistant/components/wallbox/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
"step": {
"user": {
"data": {
"station": "Station Serial Number",
"station": "Station serial number",
"username": "[%key:common::config_flow::data::username%]",
"password": "[%key:common::config_flow::data::password%]"
},
"data_description": {
"station": "Serial number of the charger, this value can be found in the Wallbox App or in the Wallbox Portal.",
"username": "Username for your Wallbox Account.",
"password": "Password for your Wallbox Account."
"station": "Serial number of the charger. Can be found in the Wallbox app or in the Wallbox portal.",
"username": "Username for your Wallbox account.",
"password": "Password for your Wallbox account."
}
},
"reauth_confirm": {
Expand All @@ -24,7 +24,7 @@
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"unknown": "[%key:common::config_flow::error::unknown%]",
"reauth_invalid": "Re-authentication failed; Serial Number does not match original"
"reauth_invalid": "Re-authentication failed; serial number does not match original"
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
Expand Down
5 changes: 4 additions & 1 deletion homeassistant/components/webostv/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,10 @@ async def async_step_pairing(
data = {CONF_HOST: self._host, CONF_CLIENT_SECRET: client.client_key}

if not self._name:
self._name = f"{DEFAULT_NAME} {client.tv_info.system['modelName']}"
if model_name := client.tv_info.system.get("modelName"):
self._name = f"{DEFAULT_NAME} {model_name}"
else:
self._name = DEFAULT_NAME
return self.async_create_entry(title=self._name, data=data)

return self.async_show_form(step_id="pairing", errors=errors)
Expand Down
Loading
Loading