Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
aaf5807
Rename security panel to safety panel (#154435)
piitaya Oct 14, 2025
4879408
Dependency update py-melissa-climate to 3.0.2 (#154285)
kennedyshead Oct 14, 2025
d108d5f
Use Shelly RPC cover methods from upstream and fix cover status updat…
thecode Oct 14, 2025
81fd9e1
Move state conversion from library to nasweb integration code (#153208)
nasWebio Oct 14, 2025
fcea5e0
Simplify DPType lookup in Tuya (#150117)
epenet Oct 14, 2025
fbf875b
Deprecate has_mean in favor of mean_type in recorder statistic API (#…
emontnemery Oct 14, 2025
c3e2f0e
Always run install of packages with same python as script (#154253)
elupus Oct 14, 2025
8464dad
Add milliPascal (mPa) as unit of measurement for Pressure (#153087)
Domochip Oct 14, 2025
106a74c
Prevent AttributeError in luci device tracker (#148357)
mmstano Oct 14, 2025
cdc6c44
Fix reconfigure flow in esphome uses create_entry (#154107)
gjohansson-ST Oct 14, 2025
06e4922
Fix state class for Overkiz water consumption (#154164)
Yvan13120 Oct 14, 2025
64f4856
Change device identifier and binary_sensor unique_id for airOS (#153085)
CoMPaTech Oct 14, 2025
bddbf9c
Simplify current ids callback in config entries (#154082)
arturpragacz Oct 14, 2025
85b2647
Shut down core event loop on unrecoverable errors (#144806)
akx Oct 14, 2025
21f24c2
Get Enphase_envoy collar grid status from admin_state_str rather then…
catsmanac Oct 14, 2025
d140eb4
Protect internal coordinator state (#153685)
elupus Oct 14, 2025
61a9094
Update WLED Select Options after update (#154205)
mik-laj Oct 14, 2025
8db6505
Set initial integration_hub in manifest for Squeezebox (#154438)
peteS-UK Oct 14, 2025
f3c4288
Use contact header for outgoing call transport (#151847)
jaminh Oct 14, 2025
8dba1ed
Machine container: Remove codenotary configuration (#153855)
agners Oct 14, 2025
38d0299
Remove URL from ViCare strings.json (#154243)
CFenner Oct 14, 2025
ae3d320
Move URL out of Switcher strings.json (#154240)
thecode Oct 14, 2025
a92e73f
Move URL out of sfr_box strings.json (#154364)
epenet Oct 14, 2025
7ddfcd3
Move URLs out of SABnzbd strings.json (#154333)
shaiu Oct 14, 2025
7f5128e
Add description placeholders to pyLoad config flow (#154254)
tr4nt0r Oct 14, 2025
6e515d4
Move URL out of Mealie strings.json (#154230)
andrew-codechimp Oct 14, 2025
b517774
Move Ecobee authorization URL out of strings.json (#154332)
ogruendel Oct 14, 2025
13e8280
Move developer url out of strings.json for coinbase setup flow (#154339)
ogruendel Oct 14, 2025
26fec2f
Move Electricity Maps url out of strings.json (#154284)
jpbede Oct 14, 2025
1237010
auth: add required issuer to OAuth (#152385)
ptu14 Oct 14, 2025
d2af875
Move igloohome API access URL into constant placeholders (#154430)
DannyS95 Oct 14, 2025
416f6b9
Add reconfigure flow to airOS (#154447)
CoMPaTech Oct 14, 2025
c6e334c
Skip adding Control4 rooms with no audio/video sources as media playe…
davidrecordon Oct 14, 2025
c0fc7b6
Move translatable URLs out of strings.json for huawei lte (#154368)
sonianuj287 Oct 14, 2025
2812d7c
Add the coordinator pattern to the NS integration (#154149)
heindrichpaul Oct 14, 2025
7a3630e
Add sensor description for switchbot cloud's device(plug) small chan…
XiaoLing-git Oct 14, 2025
a3dec46
Add derivative tests exhibiting unit issues (#153051)
karwosts Oct 14, 2025
2abc197
Add extract_from_target websocket command (#150124)
abmantis Oct 14, 2025
3e20c50
Add gallons per hour as volume flow rate unit (#154246)
autinerd Oct 14, 2025
080a7dc
Allow more device types for Vodafone Station (#153990)
chemelli74 Oct 14, 2025
11ee7d6
Remove vesync unused extra attributes, refine enums (#153171)
cdnninja Oct 14, 2025
655de3d
Use `async_schedule_reload` instead of `async_reload` for ZHA (#154397)
puddly Oct 14, 2025
6aff128
Fix capitalization of RADIUS in Uptime Kuma (#154456)
tr4nt0r Oct 14, 2025
b494074
Fix device registry arg docstring (#154453)
abmantis Oct 14, 2025
97a0a4e
Add tyre pressure to Renault integration (#154377)
kelyaenn Oct 14, 2025
31857a0
Remove Asuwrt device tracker last_time_reachable extra attribute (#15…
ollo69 Oct 14, 2025
28405e2
Add model name to Lunatone devices (#154432)
MoonDevLT Oct 14, 2025
8b6fb05
Add subentry support for MQTT siren device (#154220)
jbouwh Oct 14, 2025
b6337c0
Update intellifire4py to 4.2.1 (#154454)
cdce8p Oct 14, 2025
1d6c662
Migrate onewire to async library (#154439)
epenet Oct 14, 2025
681eb6b
Add LED control for supported UniFi network devices (#152649)
Sese-Schneider Oct 14, 2025
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
62 changes: 57 additions & 5 deletions homeassistant/components/airos/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from __future__ import annotations

import logging

from airos.airos8 import AirOS8

from homeassistant.const import (
Expand All @@ -12,17 +14,20 @@
CONF_VERIFY_SSL,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.aiohttp_client import async_get_clientsession

from .const import DEFAULT_SSL, DEFAULT_VERIFY_SSL, SECTION_ADVANCED_SETTINGS
from .const import DEFAULT_SSL, DEFAULT_VERIFY_SSL, DOMAIN, SECTION_ADVANCED_SETTINGS
from .coordinator import AirOSConfigEntry, AirOSDataUpdateCoordinator

_PLATFORMS: list[Platform] = [
Platform.BINARY_SENSOR,
Platform.SENSOR,
]

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(hass: HomeAssistant, entry: AirOSConfigEntry) -> bool:
"""Set up Ubiquiti airOS from a config entry."""
Expand Down Expand Up @@ -54,11 +59,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: AirOSConfigEntry) -> boo
async def async_migrate_entry(hass: HomeAssistant, entry: AirOSConfigEntry) -> bool:
"""Migrate old config entry."""

if entry.version > 1:
# This means the user has downgraded from a future version
# This means the user has downgraded from a future version
if entry.version > 2:
return False

# 1.1 Migrate config_entry to add advanced ssl settings
if entry.version == 1 and entry.minor_version == 1:
new_minor_version = 2
new_data = {**entry.data}
advanced_data = {
CONF_SSL: DEFAULT_SSL,
Expand All @@ -69,7 +76,52 @@ async def async_migrate_entry(hass: HomeAssistant, entry: AirOSConfigEntry) -> b
hass.config_entries.async_update_entry(
entry,
data=new_data,
minor_version=2,
minor_version=new_minor_version,
)

# 2.1 Migrate binary_sensor entity unique_id from device_id to mac_address
# Step 1 - migrate binary_sensor entity unique_id
# Step 2 - migrate device entity identifier
if entry.version == 1:
new_version = 2
new_minor_version = 1

mac_adress = dr.format_mac(entry.unique_id)

device_registry = dr.async_get(hass)
if device_entry := device_registry.async_get_device(
connections={(dr.CONNECTION_NETWORK_MAC, mac_adress)}
):
old_device_id = next(
(
device_id
for domain, device_id in device_entry.identifiers
if domain == DOMAIN
),
)

@callback
def update_unique_id(
entity_entry: er.RegistryEntry,
) -> dict[str, str] | None:
"""Update unique id from device_id to mac address."""
if old_device_id and entity_entry.unique_id.startswith(old_device_id):
suffix = entity_entry.unique_id.removeprefix(old_device_id)
new_unique_id = f"{mac_adress}{suffix}"
return {"new_unique_id": new_unique_id}
return None

await er.async_migrate_entries(hass, entry.entry_id, update_unique_id)

new_identifiers = device_entry.identifiers.copy()
new_identifiers.discard((DOMAIN, old_device_id))
new_identifiers.add((DOMAIN, mac_adress))
device_registry.async_update_device(
device_entry.id, new_identifiers=new_identifiers
)

hass.config_entries.async_update_entry(
entry, version=new_version, minor_version=new_minor_version
)

return True
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/airos/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def __init__(
super().__init__(coordinator)

self.entity_description = description
self._attr_unique_id = f"{coordinator.data.host.device_id}_{description.key}"
self._attr_unique_id = f"{coordinator.data.derived.mac}_{description.key}"

@property
def is_on(self) -> bool:
Expand Down
64 changes: 60 additions & 4 deletions homeassistant/components/airos/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@
)
import voluptuous as vol

from homeassistant.config_entries import SOURCE_REAUTH, ConfigFlow, ConfigFlowResult
from homeassistant.config_entries import (
SOURCE_REAUTH,
SOURCE_RECONFIGURE,
ConfigFlow,
ConfigFlowResult,
)
from homeassistant.const import (
CONF_HOST,
CONF_PASSWORD,
Expand Down Expand Up @@ -57,8 +62,8 @@
class AirOSConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Ubiquiti airOS."""

VERSION = 1
MINOR_VERSION = 2
VERSION = 2
MINOR_VERSION = 1

def __init__(self) -> None:
"""Initialize the config flow."""
Expand Down Expand Up @@ -119,7 +124,7 @@ async def _validate_and_get_device_info(
else:
await self.async_set_unique_id(airos_data.derived.mac)

if self.source == SOURCE_REAUTH:
if self.source in [SOURCE_REAUTH, SOURCE_RECONFIGURE]:
self._abort_if_unique_id_mismatch()
else:
self._abort_if_unique_id_configured()
Expand Down Expand Up @@ -164,3 +169,54 @@ async def async_step_reauth_confirm(
),
errors=self.errors,
)

async def async_step_reconfigure(
self,
user_input: Mapping[str, Any] | None = None,
) -> ConfigFlowResult:
"""Handle reconfiguration of airOS."""
self.errors = {}
entry = self._get_reconfigure_entry()
current_data = entry.data

if user_input is not None:
validate_data = {**current_data, **user_input}
if await self._validate_and_get_device_info(config_data=validate_data):
return self.async_update_reload_and_abort(
entry,
data_updates=validate_data,
)

return self.async_show_form(
step_id="reconfigure",
data_schema=vol.Schema(
{
vol.Required(CONF_PASSWORD): TextSelector(
TextSelectorConfig(
type=TextSelectorType.PASSWORD,
autocomplete="current-password",
)
),
vol.Required(SECTION_ADVANCED_SETTINGS): section(
vol.Schema(
{
vol.Required(
CONF_SSL,
default=current_data[SECTION_ADVANCED_SETTINGS][
CONF_SSL
],
): bool,
vol.Required(
CONF_VERIFY_SSL,
default=current_data[SECTION_ADVANCED_SETTINGS][
CONF_VERIFY_SSL
],
): bool,
}
),
{"collapsed": True},
),
}
),
errors=self.errors,
)
2 changes: 1 addition & 1 deletion homeassistant/components/airos/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def __init__(self, coordinator: AirOSDataUpdateCoordinator) -> None:
self._attr_device_info = DeviceInfo(
connections={(CONNECTION_NETWORK_MAC, airos_data.derived.mac)},
configuration_url=configuration_url,
identifiers={(DOMAIN, str(airos_data.host.device_id))},
identifiers={(DOMAIN, airos_data.derived.mac)},
manufacturer=MANUFACTURER,
model=airos_data.host.devmodel,
model_id=(
Expand Down
23 changes: 23 additions & 0 deletions homeassistant/components/airos/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,27 @@
"password": "[%key:component::airos::config::step::user::data_description::password%]"
}
},
"reconfigure": {
"data": {
"password": "[%key:common::config_flow::data::password%]"
},
"data_description": {
"password": "[%key:component::airos::config::step::user::data_description::password%]"
},
"sections": {
"advanced_settings": {
"name": "[%key:component::airos::config::step::user::sections::advanced_settings::name%]",
"data": {
"ssl": "[%key:component::airos::config::step::user::sections::advanced_settings::data::ssl%]",
"verify_ssl": "[%key:common::config_flow::data::verify_ssl%]"
},
"data_description": {
"ssl": "[%key:component::airos::config::step::user::sections::advanced_settings::data_description::ssl%]",
"verify_ssl": "[%key:component::airos::config::step::user::sections::advanced_settings::data_description::verify_ssl%]"
}
}
}
},
"user": {
"data": {
"host": "[%key:common::config_flow::data::host%]",
Expand All @@ -23,6 +44,7 @@
},
"sections": {
"advanced_settings": {
"name": "Advanced settings",
"data": {
"ssl": "Use HTTPS",
"verify_ssl": "[%key:common::config_flow::data::verify_ssl%]"
Expand All @@ -44,6 +66,7 @@
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]",
"reconfigure_successful": "[%key:common::config_flow::abort::reconfigure_successful%]",
"unique_id_mismatch": "Re-authentication should be used for the same device not a new one"
}
},
Expand Down
9 changes: 0 additions & 9 deletions homeassistant/components/asuswrt/device_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
from . import AsusWrtConfigEntry
from .router import AsusWrtDevInfo, AsusWrtRouter

ATTR_LAST_TIME_REACHABLE = "last_time_reachable"

DEFAULT_DEVICE_NAME = "Unknown device"


Expand Down Expand Up @@ -58,8 +56,6 @@ def add_entities(
class AsusWrtDevice(ScannerEntity):
"""Representation of a AsusWrt device."""

_unrecorded_attributes = frozenset({ATTR_LAST_TIME_REACHABLE})

_attr_should_poll = False

def __init__(self, router: AsusWrtRouter, device: AsusWrtDevInfo) -> None:
Expand Down Expand Up @@ -97,11 +93,6 @@ def mac_address(self) -> str:
def async_on_demand_update(self) -> None:
"""Update state."""
self._device = self._router.devices[self._device.mac]
self._attr_extra_state_attributes = {}
if self._device.last_activity:
self._attr_extra_state_attributes[ATTR_LAST_TIME_REACHABLE] = (
self._device.last_activity.isoformat(timespec="seconds")
)
self.async_write_ha_state()

async def async_added_to_hass(self) -> None:
Expand Down
27 changes: 16 additions & 11 deletions homeassistant/components/auth/login_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,17 +136,22 @@ async def get(self, request: web.Request) -> web.Response:
url_prefix = get_url(hass, require_current_request=True)
except NoURLAvailableError:
url_prefix = ""
return self.json(
{
"authorization_endpoint": f"{url_prefix}/auth/authorize",
"token_endpoint": f"{url_prefix}/auth/token",
"revocation_endpoint": f"{url_prefix}/auth/revoke",
"response_types_supported": ["code"],
"service_documentation": (
"https://developers.home-assistant.io/docs/auth_api"
),
}
)

metadata = {
"authorization_endpoint": f"{url_prefix}/auth/authorize",
"token_endpoint": f"{url_prefix}/auth/token",
"revocation_endpoint": f"{url_prefix}/auth/revoke",
"response_types_supported": ["code"],
"service_documentation": (
"https://developers.home-assistant.io/docs/auth_api"
),
}

# Add issuer only when we have a valid base URL (RFC 8414 compliance)
if url_prefix:
metadata["issuer"] = url_prefix

return self.json(metadata)


class AuthProvidersView(HomeAssistantView):
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/canary/alarm_control_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ async def async_setup_entry(
for location_id, location in coordinator.data["locations"].items()
]

async_add_entities(alarms, True)
async_add_entities(alarms)


class CanaryAlarm(
Expand Down
3 changes: 1 addition & 2 deletions homeassistant/components/canary/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ async def async_setup_entry(
for location_id, location in coordinator.data["locations"].items()
for device in location.devices
if device.is_online
),
True,
)
)


Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/canary/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ async def async_setup_entry(
if device_type.get("name") in sensor_type[4]
)

async_add_entities(sensors, True)
async_add_entities(sensors)


class CanarySensor(CoordinatorEntity[CanaryDataUpdateCoordinator], SensorEntity):
Expand Down
6 changes: 6 additions & 0 deletions homeassistant/components/co2signal/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@

_LOGGER = logging.getLogger(__name__)

DESCRIPTION_PLACEHOLDER = {
"register_link": "https://electricitymaps.com/free-tier",
}


class ElectricityMapsConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Co2signal."""
Expand Down Expand Up @@ -70,6 +74,7 @@ async def async_step_user(
return self.async_show_form(
step_id="user",
data_schema=data_schema,
description_placeholders=DESCRIPTION_PLACEHOLDER,
)

data = {CONF_API_KEY: user_input[CONF_API_KEY]}
Expand Down Expand Up @@ -179,4 +184,5 @@ async def _validate_and_create(
step_id=step_id,
data_schema=data_schema,
errors=errors,
description_placeholders=DESCRIPTION_PLACEHOLDER,
)
1 change: 0 additions & 1 deletion homeassistant/components/co2signal/quality_scale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ rules:
status: todo
comment: |
The config flow misses data descriptions.
Remove URLs from data descriptions, they should be replaced with placeholders.
Make use of Electricity Maps zone keys in country code as dropdown.
Make use of location selector for coordinates.
dependency-transparency: done
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/co2signal/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"location": "[%key:common::config_flow::data::location%]",
"api_key": "[%key:common::config_flow::data::access_token%]"
},
"description": "Visit https://electricitymaps.com/free-tier to request a token."
"description": "Visit the [Electricity Maps page]({register_link}) to request a token."
},
"coordinates": {
"data": {
Expand Down
Loading
Loading