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
5 changes: 5 additions & 0 deletions homeassistant/brands/sensereo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"domain": "sensereo",
"name": "Sensereo",
"iot_standards": ["matter"]
}
5 changes: 5 additions & 0 deletions homeassistant/brands/zunzunbee.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"domain": "zunzunbee",
"name": "Zunzunbee",
"iot_standards": ["zigbee"]
}
5 changes: 3 additions & 2 deletions homeassistant/components/automation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -899,12 +899,13 @@ def started_action() -> None:
async def async_will_remove_from_hass(self) -> None:
"""Remove listeners when removing automation from Home Assistant."""
await super().async_will_remove_from_hass()
await self._async_disable()
if self.registry_entry and self.registry_entry.entity_id != self.entity_id:
# Entity ID change, do not unload the script or conditions as they will
# be reused.
await self._async_disable()
return
self.action_script.async_unload()
await self._async_disable(stop_actions=False)
await self.action_script.async_unload()
if self._condition is not None:
self._condition.async_unload()

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/conversation/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/conversation",
"integration_type": "entity",
"quality_scale": "internal",
"requirements": ["hassil==3.5.0", "home-assistant-intents==2026.3.24"]
"requirements": ["hassil==3.5.0", "home-assistant-intents==2026.5.5"]
}
14 changes: 14 additions & 0 deletions homeassistant/components/duco/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
from .const import DOMAIN
from .coordinator import DucoConfigEntry

# MAC addresses and serial numbers are redacted because a Duco installer or
# manufacturer could cross-reference them against an installation registry to
# identify the physical location of the device.
TO_REDACT = {
CONF_HOST,
"mac",
Expand All @@ -31,9 +34,15 @@ async def async_get_config_entry_diagnostics(
coordinator = entry.runtime_data

board = asdict(coordinator.board_info)
# `time` is a Unix epoch timestamp of the last board info fetch; not useful for support triage.
board.pop("time")
if board["public_api_version"] is None:
board.pop("public_api_version")
if board["software_version"] is None:
board.pop("software_version")

try:
api_info_obj = await coordinator.client.async_get_api_info()
lan_info = await coordinator.client.async_get_lan_info()
duco_diags = await coordinator.client.async_get_diagnostics()
write_remaining = await coordinator.client.async_get_write_req_remaining()
Expand All @@ -43,10 +52,15 @@ async def async_get_config_entry_diagnostics(
translation_key="connection_error",
) from err

api_info: dict[str, Any] = {"public_api_version": api_info_obj.public_api_version}
if api_info_obj.reported_api_version is not None:
api_info["reported_api_version"] = api_info_obj.reported_api_version

return async_redact_data(
{
"entry_data": entry.data,
"board_info": board,
"api_info": api_info,
"lan_info": asdict(lan_info),
"nodes": {
str(node_id): asdict(node)
Expand Down
4 changes: 0 additions & 4 deletions homeassistant/components/ecovacs/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,6 @@ async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the initial step."""

if not self.show_advanced_options:
return await self.async_step_auth()

if user_input:
self._mode = user_input[CONF_MODE]
return await self.async_step_auth()
Expand Down
2 changes: 0 additions & 2 deletions homeassistant/components/fluss/coordinator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""DataUpdateCoordinator for Fluss+ integration."""

from __future__ import annotations

import asyncio
from typing import Any

Expand Down
8 changes: 6 additions & 2 deletions homeassistant/components/growatt_server/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,9 @@ async def read_ac_charge_times(self) -> dict:
if not self.data:
await self.async_refresh()

return self.api.sph_read_ac_charge_times(settings_data=self.data)
return self.api.sph_read_ac_charge_times(
self.device_id, settings_data=self.data
)

async def read_ac_discharge_times(self) -> dict:
"""Read AC discharge time settings from SPH device cache."""
Expand All @@ -609,4 +611,6 @@ async def read_ac_discharge_times(self) -> dict:
if not self.data:
await self.async_refresh()

return self.api.sph_read_ac_discharge_times(settings_data=self.data)
return self.api.sph_read_ac_discharge_times(
self.device_id, settings_data=self.data
)
2 changes: 1 addition & 1 deletion homeassistant/components/growatt_server/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"iot_class": "cloud_polling",
"loggers": ["growattServer"],
"quality_scale": "silver",
"requirements": ["growattServer==1.9.0"]
"requirements": ["growattServer==2.1.0"]
}
5 changes: 2 additions & 3 deletions homeassistant/components/intent_script/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,9 @@ async def async_reload(hass: HomeAssistant, service_call: ServiceCall) -> None:
existing_intents = hass.data[DOMAIN]

for intent_type, conf in existing_intents.items():
if isinstance(conf.get(CONF_ACTION), script.Script):
await conf[CONF_ACTION].async_stop()
conf[CONF_ACTION].async_unload()
intent.async_remove(hass, intent_type)
if isinstance(conf.get(CONF_ACTION), script.Script):
await conf[CONF_ACTION].async_unload()

if not new_config or DOMAIN not in new_config:
hass.data[DOMAIN] = {}
Expand Down
2 changes: 0 additions & 2 deletions homeassistant/components/mitsubishi_comfort/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""Mitsubishi Comfort integration for Home Assistant."""

from __future__ import annotations

import asyncio
import logging

Expand Down
2 changes: 0 additions & 2 deletions homeassistant/components/mitsubishi_comfort/climate.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""Climate entity for Mitsubishi Comfort integration."""

from __future__ import annotations

from typing import Any

from mitsubishi_comfort import FanSpeed, IndoorUnit, Mode, VaneDirection
Expand Down
2 changes: 0 additions & 2 deletions homeassistant/components/mitsubishi_comfort/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""Config flow for Mitsubishi Comfort integration."""

from __future__ import annotations

import logging
from typing import Any

Expand Down
2 changes: 0 additions & 2 deletions homeassistant/components/mitsubishi_comfort/coordinator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""DataUpdateCoordinator for Mitsubishi Comfort devices."""

from __future__ import annotations

import logging

from mitsubishi_comfort import IndoorUnit, KumoStation
Expand Down
2 changes: 0 additions & 2 deletions homeassistant/components/mitsubishi_comfort/entity.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""Base entity for Mitsubishi Comfort integration."""

from __future__ import annotations

from mitsubishi_comfort import IndoorUnit, KumoStation

from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
Expand Down
30 changes: 29 additions & 1 deletion homeassistant/components/mqtt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@
from homeassistant import config as conf_util
from homeassistant.components import websocket_api
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_DISCOVERY, CONF_PLATFORM, SERVICE_RELOAD
from homeassistant.const import (
CONF_DISCOVERY,
CONF_PLATFORM,
CONF_PROTOCOL,
SERVICE_RELOAD,
)
from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.exceptions import (
ConfigValidationError,
Expand All @@ -27,6 +32,7 @@
from homeassistant.helpers.device_registry import DeviceEntry
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import async_get_platforms
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from homeassistant.helpers.reload import async_integration_yaml_config
from homeassistant.helpers.service import async_register_admin_service
from homeassistant.helpers.typing import ConfigType
Expand Down Expand Up @@ -73,12 +79,14 @@
DEFAULT_DISCOVERY,
DEFAULT_ENCODING,
DEFAULT_PREFIX,
DEFAULT_PROTOCOL,
DEFAULT_QOS,
DEFAULT_RETAIN,
DOMAIN,
ENTITY_PLATFORMS,
ENTRY_OPTION_FIELDS,
MQTT_CONNECTION_STATE,
PROTOCOL_311,
TEMPLATE_ERRORS,
Platform,
)
Expand Down Expand Up @@ -424,6 +432,26 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Load a config entry."""
mqtt_data: MqttData

if (protocol := entry.data.get(CONF_PROTOCOL, PROTOCOL_311)) != DEFAULT_PROTOCOL:
broker: str = entry.data[CONF_BROKER]
async_create_issue(
hass,
DOMAIN,
"protocol_5_migration",
issue_domain=DOMAIN,
is_fixable=True,
breaks_in_ha_version="2027.1.0",
severity=IssueSeverity.WARNING,
learn_more_url="https://www.home-assistant.io/integrations/mqtt/#mqtt-protocol",
data={
"entry_id": entry.entry_id,
"broker": broker,
"protocol": protocol,
},
translation_placeholders={"broker": broker, "protocol": protocol},
translation_key="protocol_5_migration",
)

async def _setup_client() -> tuple[MqttData, dict[str, Any]]:
"""Set up the MQTT client."""
# Fetch configuration
Expand Down
12 changes: 9 additions & 3 deletions homeassistant/components/mqtt/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@
DEFAULT_ENCODING,
DEFAULT_KEEPALIVE,
DEFAULT_PORT,
DEFAULT_PROTOCOL,
DEFAULT_QOS,
DEFAULT_TRANSPORT,
DEFAULT_WILL,
Expand All @@ -74,6 +73,7 @@
MQTT_PROCESSED_SUBSCRIPTIONS,
PROTOCOL_5,
PROTOCOL_31,
PROTOCOL_311,
TRANSPORT_WEBSOCKETS,
)
from .models import (
Expand Down Expand Up @@ -331,7 +331,10 @@ def setup(self) -> None:

config = self._config
clean_session: bool | None = None
if (protocol := config.get(CONF_PROTOCOL, DEFAULT_PROTOCOL)) == PROTOCOL_31:
# If no protocol setting is set in the config entry data
# we assume the config was migrated from YAML, and the
# protocol version is defaulting to legacy version 3.1.1.
if (protocol := config.get(CONF_PROTOCOL, PROTOCOL_311)) == PROTOCOL_31:
proto = mqtt.MQTTv31
clean_session = True
elif protocol == PROTOCOL_5:
Expand Down Expand Up @@ -420,7 +423,10 @@ def __init__(
self.loop = hass.loop
self.config_entry = config_entry
self.conf = conf
self.is_mqttv5 = conf.get(CONF_PROTOCOL, DEFAULT_PROTOCOL) == PROTOCOL_5
# If no protocol setting is set in the config entry data
# we assume the config was migrated from YAML, and the
# protocol version is defaulting to legacy version 3.1.1.
self.is_mqttv5 = conf.get(CONF_PROTOCOL, PROTOCOL_311) == PROTOCOL_5

self._simple_subscriptions: defaultdict[str, set[Subscription]] = defaultdict(
set
Expand Down
5 changes: 5 additions & 0 deletions homeassistant/components/mqtt/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -4073,6 +4073,7 @@ async def _async_get_config_and_try(self) -> dict[str, Any] | None:
config: dict[str, Any] = {
CONF_BROKER: addon_discovery_config[CONF_HOST],
CONF_PORT: addon_discovery_config[CONF_PORT],
CONF_PROTOCOL: DEFAULT_PROTOCOL,
CONF_USERNAME: addon_discovery_config.get(CONF_USERNAME),
CONF_PASSWORD: addon_discovery_config.get(CONF_PASSWORD),
CONF_DISCOVERY: DEFAULT_DISCOVERY,
Expand Down Expand Up @@ -4301,6 +4302,7 @@ async def async_step_hassio_confirm(
if user_input is not None:
data: dict[str, Any] = self._hassio_discovery.copy()
data[CONF_BROKER] = data.pop(CONF_HOST)
data[CONF_PROTOCOL] = DEFAULT_PROTOCOL
can_connect = await self.hass.async_add_executor_job(
try_connection,
data,
Expand All @@ -4312,6 +4314,7 @@ async def async_step_hassio_confirm(
data={
CONF_BROKER: data[CONF_BROKER],
CONF_PORT: data[CONF_PORT],
CONF_PROTOCOL: DEFAULT_PROTOCOL,
CONF_USERNAME: data.get(CONF_USERNAME),
CONF_PASSWORD: data.get(CONF_PASSWORD),
CONF_DISCOVERY: DEFAULT_DISCOVERY,
Expand Down Expand Up @@ -5178,6 +5181,8 @@ async def _async_validate_broker_settings(
) -> bool:
"""Additional validation on broker settings for better error messages."""

if CONF_PROTOCOL not in validated_user_input:
validated_user_input[CONF_PROTOCOL] = DEFAULT_PROTOCOL
# Get current certificate settings from config entry
certificate: str | None = (
"auto"
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/mqtt/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,14 +347,14 @@
PROTOCOL_31 = "3.1"
PROTOCOL_311 = "3.1.1"
PROTOCOL_5 = "5"
SUPPORTED_PROTOCOLS = [PROTOCOL_31, PROTOCOL_311, PROTOCOL_5]
SUPPORTED_PROTOCOLS = [PROTOCOL_5, PROTOCOL_311, PROTOCOL_31]

TRANSPORT_TCP = "tcp"
TRANSPORT_WEBSOCKETS = "websockets"

DEFAULT_PORT = 1883
DEFAULT_KEEPALIVE = 60
DEFAULT_PROTOCOL = PROTOCOL_311
DEFAULT_PROTOCOL = PROTOCOL_5
DEFAULT_TRANSPORT = TRANSPORT_TCP

DEFAULT_BIRTH = {
Expand Down
Loading
Loading