Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
381db53
Add ventilation quickmode switches to ViCare (#179430)
lackas Aug 29, 2026
52adc20
Add Priority Status sensor to Lyric integration (#177065)
clutch2sft Aug 29, 2026
99192f5
Add serial number to Roborock devices (#180465)
ximex Aug 29, 2026
d75f497
Add Tailscale connected to control binary sensor (#179506)
AlfonsoDehesa Aug 29, 2026
b6b40e2
Include contributor reviewed 2 PRs in ha merge queue skill (#180631)
silamon Aug 29, 2026
2f50531
Scan every supported wireless interface in Mikrotik (#180636)
chemelli74 Aug 29, 2026
05c2618
Add 100% coverage for coordinator in Mikrotik (#180637)
chemelli74 Aug 29, 2026
76f77d0
Add 100% coverage to light in Midea (#180640)
chemelli74 Aug 29, 2026
8a89fa8
Give a sleeping printer time to wake up (#180616)
frenck Aug 29, 2026
6f9d552
Add DALI line status diagnostic sensor to lunatone (#179706)
MoonDevLT Aug 29, 2026
b4826e7
Add 100% coverage to coordinator in Shelly (#180644)
chemelli74 Aug 29, 2026
0313d49
Add 100% coverage to coordinator in Fritz (#180647)
chemelli74 Aug 29, 2026
74a364c
Add 100% coverage to sensor in Fritz (#180646)
chemelli74 Aug 29, 2026
8575b67
Add 100% coverage to todo in Alexa Devices (#180638)
chemelli74 Aug 29, 2026
93791ed
Add 100% coverage to binary_sensor in Midea (#180642)
chemelli74 Aug 29, 2026
6a6f930
Split the Elgato user flow init from its data (#180654)
frenck Aug 29, 2026
a1f7924
Split the Peblar user flow init from its data (#180653)
frenck Aug 29, 2026
6a1fe7c
Split the Twente Milieu user flow init from its data (#180645)
frenck Aug 29, 2026
db71607
Split the Tailwind user flow init from its data (#180648)
frenck Aug 29, 2026
e50ca95
Split the Tailscale user flow init from its data (#180649)
frenck Aug 29, 2026
959970d
Split the SolarEdge user flow init from its data (#180650)
frenck Aug 29, 2026
755a049
Split the Season user flow init from its data (#180651)
frenck Aug 29, 2026
fd790dd
Split the PVOutput user flow init from its data (#180652)
frenck Aug 29, 2026
d2d35fe
Split the Whois user flow init from its data (#180643)
frenck Aug 29, 2026
8afadfa
Split the AdGuard Home user flow init from its data (#180639)
frenck Aug 29, 2026
8fc0cc5
Split the WLED user flow init from its data (#180641)
frenck Aug 29, 2026
6d5256e
Mark Vistapool entities unavailable while the push connection is down…
fdebrus Aug 29, 2026
6eabc44
Bump google cloud dependencies (#180625)
silamon Aug 29, 2026
12fc18f
Bump probatio to 0.11.4 (#180655)
frenck Aug 29, 2026
018694c
Bump uiprotect to 16.6.1 (#180670)
RaHehl Aug 29, 2026
41dbe41
Split the Samsung SyncThru user flow init from its data (#180661)
frenck Aug 29, 2026
bf43038
Split The Things Network user flow init from its data (#180660)
frenck Aug 29, 2026
f008a3a
Split the Syncthing user flow init from its data (#180662)
frenck Aug 29, 2026
856a73f
Split the Soma user flow init from its data (#180664)
frenck Aug 29, 2026
40b951a
Split the StarLine user flow init from its data (#180663)
frenck Aug 29, 2026
7bb0412
Split the Smarla user flow init from its data (#180665)
frenck Aug 29, 2026
4b5930c
Split the SleepIQ user flow init from its data (#180666)
frenck Aug 29, 2026
57aecb2
Split the SkyBell user flow init from its data (#180674)
frenck Aug 29, 2026
7fd88d5
Split the 17TRACK user flow init from its data (#180675)
frenck Aug 29, 2026
c186313
Split the ROVA user flow init from its data (#180676)
frenck Aug 29, 2026
47fad86
Split the Slack user flow init from its data (#180673)
frenck Aug 29, 2026
a1eba84
Split the ROMY user flow init from its data (#180680)
frenck Aug 29, 2026
5c94fb9
Add battery support to SolarEdge Modbus (#180657)
frenck Aug 29, 2026
60be162
Split the Redgtech user flow init from its data (#180681)
frenck Aug 29, 2026
a9fbc0d
Add reconfigure and reauth flows for CentriConnect (#180215)
gresrun Aug 29, 2026
915d135
Split the PoolSense user flow init from its data (#180685)
frenck Aug 29, 2026
e2e687b
Split the Pterodactyl user flow init from its data (#180684)
frenck Aug 29, 2026
fddd796
Split the Pushover user flow init from its data (#180682)
frenck Aug 29, 2026
b31c625
Split the Pushbullet user flow init from its data (#180683)
frenck Aug 29, 2026
3052056
Add binary sensors to SolarEdge Modbus (#180687)
frenck Aug 29, 2026
b50835d
Add number entities to SolarEdge Modbus (#180691)
frenck Aug 29, 2026
5914747
Bump midea-local to 10.1.0 (#180694)
rokam Aug 29, 2026
e4455e9
Add state_class to UniFi device temperature sensor (#180688)
bob-laz Aug 29, 2026
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
27 changes: 21 additions & 6 deletions .claude/skills/ha-merge-queue/SKILL.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,7 +27,7 @@ verify every finalist with the per-PR checks below.

## Verify each finalist

Check all five. A PR fails the shortlist if any one fails.
Check all six conditions. A PR fails the shortlist if any of checks 1 through 5 fail.

Paginate every list response before deciding. Check runs, reviews and review threads are all
paged, typically 30 per page, and a full-suite Home Assistant PR runs to 40-odd check runs —
Expand DownExpand Up@@ -90,12 +90,27 @@ Compare the returned count against the reported total and keep fetching until th
discount one for the category it appears to fall into; an unaddressed defect is a
blocker whether or not anyone is arguing about it.

6. **Peer-Review Checklist Verification (Priority Boost)** — inspect the PR body text for
the template checkbox: `- [x] I have reviewed two other [open pull requests][prs] in this repository.`
- **Checked (`[x]`):** Give this PR higher priority in ranking to reward contributors helping
clear the review backlog.
- **Unchecked (`[ ]` or missing):** Keep in queue with standard priority (do not disqualify).

## Report

Rank by how little work each PR needs: `clean` first, then `blocked` with everything else
green. For each PR give the number as a full markdown link, the integration or core area,
one line on what it does, and its blocking state. Plenty of `home-assistant/core` PRs touch
helpers, the framework, the recorder or repo tooling and have no integration at all — name
Rank and order candidates primarily by their status readiness (`clean` first, then `blocked`
with everything else green), and **secondarily by peer-review participation**:

1. **Clean PRs** with the `[x] I have reviewed two other open pull requests...` checkbox checked.
2. **Clean PRs** without the checkbox checked.
3. **Blocked/Near-miss PRs** with the `[x] I have reviewed two other open pull requests...` checkbox checked.
4. **Blocked/Near-miss PRs** without the checkbox checked.

For each PR give the number as a full markdown link, the integration or core area,
one line on what it does, its blocking state, and explicitly note if the author checked the
peer-review box (e.g., "⭐ *Contributor reviewed 2 PRs*").

Plenty of `home-assistant/core` PRs touch helpers, the framework, the recorder or repo tooling and have no integration at all — name
what they touch instead, rather than dropping them or inventing one.

Then list the near-misses separately, each with the one action that unblocks it. The
Expand All@@ -115,4 +130,4 @@ change but carries no `breaking-change` label will silently miss the release not
- Only report in the CONSOLE. DO NOT ACT ON GITHUB — no comments, no reviews, no merges,
no pushes to contributor branches. Per `AI_POLICY.md`, a human decides and acts.
- Never call a PR ready on green CI alone. Read the diff of every PR you shortlist; CI
cannot tell you whether the change is correct or wanted.
cannot tell you whether the change is correct or wanted.
134 changes: 116 additions & 18 deletions homeassistant/components/centriconnect/config_flow.py
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
"""Config flow for the CentriConnect/MyPropane API integration."""

from collections.abc import Callable, Mapping
import logging
from typing import Any, override

Expand All@@ -11,7 +12,7 @@
CentriConnectNotFoundError,
CentriConnectTooManyRequestsError,
)
import voluptuous as vol
import probatio

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_DEVICE_ID, CONF_PASSWORD, CONF_USERNAME
Expand All@@ -22,11 +23,25 @@

_LOGGER = logging.getLogger(__name__)

STEP_USER_DATA_SCHEMA = vol.Schema(
STEP_RECONFIGURE_DATA_SCHEMA = probatio.Schema(
{
vol.Required(CONF_USERNAME): str,
vol.Required(CONF_DEVICE_ID): str,
vol.Required(CONF_PASSWORD): str,
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_PASSWORD): str,
}
)

STEP_REAUTHENTICATE_DATA_SCHEMA = probatio.Schema(
{
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_PASSWORD): str,
}
)

STEP_USER_DATA_SCHEMA = probatio.Schema(
{
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_DEVICE_ID): str,
probatio.Required(CONF_PASSWORD): str,
}
)

Expand DownExpand Up@@ -57,34 +72,117 @@ class CentriConnectConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for CentriConnect/MyPropane API."""

VERSION = 1

@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
_device_id: str | None = None

async def _handle_flow(
self,
step_id: str,
data_schema: probatio.Schema,
user_input: dict[str, Any] | None,
update_user_input: Callable[[dict[str, Any]], dict[str, Any]],
on_success: Callable[[dict[str, Any], dict[str, Any]], ConfigFlowResult],
) -> ConfigFlowResult:
"""Handle the initial step."""
"""Handle the flow for both user and reconfigure steps."""
errors: dict[str, str] = {}
if user_input is not None:
try:
info = await validate_input(self.hass, user_input)
except CentriConnectConnectionError, CentriConnectTooManyRequestsError:
info = await validate_input(self.hass, update_user_input(user_input))
except (
CentriConnectConnectionError,
CentriConnectTooManyRequestsError,
):
errors["base"] = "cannot_connect"
except CentriConnectNotFoundError:
errors["base"] = "invalid_auth"
except CentriConnectEmptyResponseError, CentriConnectDecodeError:
errors["base"] = "unknown"
except Exception:
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
await self.async_set_unique_id(
unique_id=info[CENTRICONNECT_DEVICE_ID], raise_on_progress=True
)
self._abort_if_unique_id_configured(
updates=user_input, reload_on_update=True
)
return self.async_create_entry(title=info["title"], data=user_input)
return on_success(info, user_input)

return self.async_show_form(
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
step_id=step_id, data_schema=data_schema, errors=errors
)

async def async_step_reconfigure(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle reconfiguration of the integration."""
old_entry = self._get_reconfigure_entry()

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_mismatch(reason="wrong_device")
return self.async_update_reload_and_abort(
old_entry, data_updates=user_input
)

return await self._handle_flow(
step_id="reconfigure",
data_schema=STEP_RECONFIGURE_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: {
**user_input,
CONF_DEVICE_ID: old_entry.data[CONF_DEVICE_ID],
},
on_success=_on_success,
)

async def async_step_reauth(
self, entry_data: Mapping[str, Any]
) -> ConfigFlowResult:
"""Handle configuration by re-auth."""
self._device_id = entry_data[CONF_DEVICE_ID]
return await self.async_step_reauth_confirm()

async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Perform reauthentication upon an API authentication error."""

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_mismatch(reason="wrong_device")
return self.async_update_reload_and_abort(
self._get_reauth_entry(), data_updates=user_input
)

return await self._handle_flow(
step_id="reauth_confirm",
data_schema=STEP_REAUTHENTICATE_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: {
**user_input,
CONF_DEVICE_ID: self._device_id,
},
on_success=_on_success,
)

@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the initial step."""

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_configured(
updates=user_input, reload_on_update=True
)
return self.async_create_entry(title=info["title"], data=user_input)

return await self._handle_flow(
step_id="user",
data_schema=STEP_USER_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: user_input,
on_success=_on_success,
)
4 changes: 2 additions & 2 deletions homeassistant/components/centriconnect/quality_scale.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,7 +42,7 @@ rules:
integration-owner: done
log-when-unavailable: done
parallel-updates: done
reauthentication-flow: todo
reauthentication-flow: done
test-coverage: done

# Gold
Expand DownExpand Up@@ -70,7 +70,7 @@ rules:
entity-translations: done
exception-translations: done
icon-translations: done
reconfiguration-flow: todo
reconfiguration-flow: done
repair-issues:
status: exempt
comment: No user-actionable repair scenarios identified for this integration.
Expand Down
27 changes: 26 additions & 1 deletion homeassistant/components/centriconnect/strings.json
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,39 @@
{
"config": {
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
"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%]",
"wrong_device": "This CentriConnect/MyPropane device does not match the existing device ID. Please make sure you entered the credentials correctly."
},
"error": {
"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%]"
},
"step": {
"reauth_confirm": {
"data": {
"password": "[%key:component::centriconnect::config::step::user::data::password%]",
"username": "[%key:component::centriconnect::config::step::user::data::username%]"
},
"data_description": {
"password": "[%key:component::centriconnect::config::step::user::data_description::password%]",
"username": "[%key:component::centriconnect::config::step::user::data_description::username%]"
},
"description": "[%key:component::centriconnect::config::step::user::description%]"
},
"reconfigure": {
"data": {
"password": "[%key:component::centriconnect::config::step::user::data::password%]",
"username": "[%key:component::centriconnect::config::step::user::data::username%]"
},
"data_description": {
"password": "[%key:component::centriconnect::config::step::user::data_description::password%]",
"username": "[%key:component::centriconnect::config::step::user::data_description::username%]"
},
"description": "[%key:component::centriconnect::config::step::user::description%]"
},
"user": {
"data": {
"device_id": "Device ID",
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/google_cloud/manifest.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@
"integration_type": "service",
"iot_class": "cloud_push",
"requirements": [
"google-cloud-texttospeech==2.25.1",
"google-cloud-speech==2.31.1"
"google-cloud-texttospeech==2.37.0",
"google-cloud-speech==2.40.0"
]
}
3 changes: 2 additions & 1 deletion homeassistant/components/ipp/config_flow.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,7 +27,7 @@
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo

from .const import CONF_BASE_PATH, CONF_SERIAL, DOMAIN
from .const import CONF_BASE_PATH, CONF_SERIAL, DOMAIN, REQUEST_TIMEOUT

_LOGGER = logging.getLogger(__name__)

Expand All@@ -45,6 +45,7 @@ async def validate_input(hass: HomeAssistant, data: dict) -> dict[str, Any]:
tls=data[CONF_SSL],
verify_ssl=data[CONF_VERIFY_SSL],
session=session,
request_timeout=REQUEST_TIMEOUT,
)

printer = await ipp.printer()
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/ipp/const.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,6 +14,9 @@
ATTR_STATE_REASON = "state_reason"
ATTR_URI_SUPPORTED = "uri_supported"

# Printers waking from sleep can take well over pyipp's own default
REQUEST_TIMEOUT = 30

# Config Keys
CONF_BASE_PATH = "base_path"
CONF_SERIAL = "serial"
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/ipp/coordinator.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,7 +12,7 @@
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import CONF_BASE_PATH, DOMAIN
from .const import CONF_BASE_PATH, DOMAIN, REQUEST_TIMEOUT

SCAN_INTERVAL = timedelta(seconds=60)

Expand All@@ -36,6 +36,7 @@ def __init__(self, hass: HomeAssistant, config_entry: IPPConfigEntry) -> None:
tls=config_entry.data[CONF_SSL],
verify_ssl=config_entry.data[CONF_VERIFY_SSL],
session=async_get_clientsession(hass, config_entry.data[CONF_VERIFY_SSL]),
request_timeout=REQUEST_TIMEOUT,
)

super().__init__(
Expand Down
9 changes: 9 additions & 0 deletions homeassistant/components/lunatone/icons.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
{
"entity": {
"sensor": {
"dali_line_status": {
"default": "mdi:current-ac"
}
}
}
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
[pull] dev from home-assistant:dev by pull[bot] · Pull Request #2408 · code/app-python-home-assistant-core · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
381db53
Add ventilation quickmode switches to ViCare (#179430)
lackas Aug 29, 2026
52adc20
Add Priority Status sensor to Lyric integration (#177065)
clutch2sft Aug 29, 2026
99192f5
Add serial number to Roborock devices (#180465)
ximex Aug 29, 2026
d75f497
Add Tailscale connected to control binary sensor (#179506)
AlfonsoDehesa Aug 29, 2026
b6b40e2
Include contributor reviewed 2 PRs in ha merge queue skill (#180631)
silamon Aug 29, 2026
2f50531
Scan every supported wireless interface in Mikrotik (#180636)
chemelli74 Aug 29, 2026
05c2618
Add 100% coverage for coordinator in Mikrotik (#180637)
chemelli74 Aug 29, 2026
76f77d0
Add 100% coverage to light in Midea (#180640)
chemelli74 Aug 29, 2026
8a89fa8
Give a sleeping printer time to wake up (#180616)
frenck Aug 29, 2026
6f9d552
Add DALI line status diagnostic sensor to lunatone (#179706)
MoonDevLT Aug 29, 2026
b4826e7
Add 100% coverage to coordinator in Shelly (#180644)
chemelli74 Aug 29, 2026
0313d49
Add 100% coverage to coordinator in Fritz (#180647)
chemelli74 Aug 29, 2026
74a364c
Add 100% coverage to sensor in Fritz (#180646)
chemelli74 Aug 29, 2026
8575b67
Add 100% coverage to todo in Alexa Devices (#180638)
chemelli74 Aug 29, 2026
93791ed
Add 100% coverage to binary_sensor in Midea (#180642)
chemelli74 Aug 29, 2026
6a6f930
Split the Elgato user flow init from its data (#180654)
frenck Aug 29, 2026
a1f7924
Split the Peblar user flow init from its data (#180653)
frenck Aug 29, 2026
6a1fe7c
Split the Twente Milieu user flow init from its data (#180645)
frenck Aug 29, 2026
db71607
Split the Tailwind user flow init from its data (#180648)
frenck Aug 29, 2026
e50ca95
Split the Tailscale user flow init from its data (#180649)
frenck Aug 29, 2026
959970d
Split the SolarEdge user flow init from its data (#180650)
frenck Aug 29, 2026
755a049
Split the Season user flow init from its data (#180651)
frenck Aug 29, 2026
fd790dd
Split the PVOutput user flow init from its data (#180652)
frenck Aug 29, 2026
d2d35fe
Split the Whois user flow init from its data (#180643)
frenck Aug 29, 2026
8afadfa
Split the AdGuard Home user flow init from its data (#180639)
frenck Aug 29, 2026
8fc0cc5
Split the WLED user flow init from its data (#180641)
frenck Aug 29, 2026
6d5256e
Mark Vistapool entities unavailable while the push connection is down…
fdebrus Aug 29, 2026
6eabc44
Bump google cloud dependencies (#180625)
silamon Aug 29, 2026
12fc18f
Bump probatio to 0.11.4 (#180655)
frenck Aug 29, 2026
018694c
Bump uiprotect to 16.6.1 (#180670)
RaHehl Aug 29, 2026
41dbe41
Split the Samsung SyncThru user flow init from its data (#180661)
frenck Aug 29, 2026
bf43038
Split The Things Network user flow init from its data (#180660)
frenck Aug 29, 2026
f008a3a
Split the Syncthing user flow init from its data (#180662)
frenck Aug 29, 2026
856a73f
Split the Soma user flow init from its data (#180664)
frenck Aug 29, 2026
40b951a
Split the StarLine user flow init from its data (#180663)
frenck Aug 29, 2026
7bb0412
Split the Smarla user flow init from its data (#180665)
frenck Aug 29, 2026
4b5930c
Split the SleepIQ user flow init from its data (#180666)
frenck Aug 29, 2026
57aecb2
Split the SkyBell user flow init from its data (#180674)
frenck Aug 29, 2026
7fd88d5
Split the 17TRACK user flow init from its data (#180675)
frenck Aug 29, 2026
c186313
Split the ROVA user flow init from its data (#180676)
frenck Aug 29, 2026
47fad86
Split the Slack user flow init from its data (#180673)
frenck Aug 29, 2026
a1eba84
Split the ROMY user flow init from its data (#180680)
frenck Aug 29, 2026
5c94fb9
Add battery support to SolarEdge Modbus (#180657)
frenck Aug 29, 2026
60be162
Split the Redgtech user flow init from its data (#180681)
frenck Aug 29, 2026
a9fbc0d
Add reconfigure and reauth flows for CentriConnect (#180215)
gresrun Aug 29, 2026
915d135
Split the PoolSense user flow init from its data (#180685)
frenck Aug 29, 2026
e2e687b
Split the Pterodactyl user flow init from its data (#180684)
frenck Aug 29, 2026
fddd796
Split the Pushover user flow init from its data (#180682)
frenck Aug 29, 2026
b31c625
Split the Pushbullet user flow init from its data (#180683)
frenck Aug 29, 2026
3052056
Add binary sensors to SolarEdge Modbus (#180687)
frenck Aug 29, 2026
b50835d
Add number entities to SolarEdge Modbus (#180691)
frenck Aug 29, 2026
5914747
Bump midea-local to 10.1.0 (#180694)
rokam Aug 29, 2026
e4455e9
Add state_class to UniFi device temperature sensor (#180688)
bob-laz Aug 29, 2026
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
27 changes: 21 additions & 6 deletions .claude/skills/ha-merge-queue/SKILL.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,7 +27,7 @@ verify every finalist with the per-PR checks below.

## Verify each finalist

Check all five. A PR fails the shortlist if any one fails.
Check all six conditions. A PR fails the shortlist if any of checks 1 through 5 fail.

Paginate every list response before deciding. Check runs, reviews and review threads are all
paged, typically 30 per page, and a full-suite Home Assistant PR runs to 40-odd check runs —
Expand DownExpand Up@@ -90,12 +90,27 @@ Compare the returned count against the reported total and keep fetching until th
discount one for the category it appears to fall into; an unaddressed defect is a
blocker whether or not anyone is arguing about it.

6. **Peer-Review Checklist Verification (Priority Boost)** — inspect the PR body text for
the template checkbox: `- [x] I have reviewed two other [open pull requests][prs] in this repository.`
- **Checked (`[x]`):** Give this PR higher priority in ranking to reward contributors helping
clear the review backlog.
- **Unchecked (`[ ]` or missing):** Keep in queue with standard priority (do not disqualify).

## Report

Rank by how little work each PR needs: `clean` first, then `blocked` with everything else
green. For each PR give the number as a full markdown link, the integration or core area,
one line on what it does, and its blocking state. Plenty of `home-assistant/core` PRs touch
helpers, the framework, the recorder or repo tooling and have no integration at all — name
Rank and order candidates primarily by their status readiness (`clean` first, then `blocked`
with everything else green), and **secondarily by peer-review participation**:

1. **Clean PRs** with the `[x] I have reviewed two other open pull requests...` checkbox checked.
2. **Clean PRs** without the checkbox checked.
3. **Blocked/Near-miss PRs** with the `[x] I have reviewed two other open pull requests...` checkbox checked.
4. **Blocked/Near-miss PRs** without the checkbox checked.

For each PR give the number as a full markdown link, the integration or core area,
one line on what it does, its blocking state, and explicitly note if the author checked the
peer-review box (e.g., "⭐ *Contributor reviewed 2 PRs*").

Plenty of `home-assistant/core` PRs touch helpers, the framework, the recorder or repo tooling and have no integration at all — name
what they touch instead, rather than dropping them or inventing one.

Then list the near-misses separately, each with the one action that unblocks it. The
Expand All@@ -115,4 +130,4 @@ change but carries no `breaking-change` label will silently miss the release not
- Only report in the CONSOLE. DO NOT ACT ON GITHUB — no comments, no reviews, no merges,
no pushes to contributor branches. Per `AI_POLICY.md`, a human decides and acts.
- Never call a PR ready on green CI alone. Read the diff of every PR you shortlist; CI
cannot tell you whether the change is correct or wanted.
cannot tell you whether the change is correct or wanted.
134 changes: 116 additions & 18 deletions homeassistant/components/centriconnect/config_flow.py
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
"""Config flow for the CentriConnect/MyPropane API integration."""

from collections.abc import Callable, Mapping
import logging
from typing import Any, override

Expand All@@ -11,7 +12,7 @@
CentriConnectNotFoundError,
CentriConnectTooManyRequestsError,
)
import voluptuous as vol
import probatio

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_DEVICE_ID, CONF_PASSWORD, CONF_USERNAME
Expand All@@ -22,11 +23,25 @@

_LOGGER = logging.getLogger(__name__)

STEP_USER_DATA_SCHEMA = vol.Schema(
STEP_RECONFIGURE_DATA_SCHEMA = probatio.Schema(
{
vol.Required(CONF_USERNAME): str,
vol.Required(CONF_DEVICE_ID): str,
vol.Required(CONF_PASSWORD): str,
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_PASSWORD): str,
}
)

STEP_REAUTHENTICATE_DATA_SCHEMA = probatio.Schema(
{
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_PASSWORD): str,
}
)

STEP_USER_DATA_SCHEMA = probatio.Schema(
{
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_DEVICE_ID): str,
probatio.Required(CONF_PASSWORD): str,
}
)

Expand DownExpand Up@@ -57,34 +72,117 @@ class CentriConnectConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for CentriConnect/MyPropane API."""

VERSION = 1

@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
_device_id: str | None = None

async def _handle_flow(
self,
step_id: str,
data_schema: probatio.Schema,
user_input: dict[str, Any] | None,
update_user_input: Callable[[dict[str, Any]], dict[str, Any]],
on_success: Callable[[dict[str, Any], dict[str, Any]], ConfigFlowResult],
) -> ConfigFlowResult:
"""Handle the initial step."""
"""Handle the flow for both user and reconfigure steps."""
errors: dict[str, str] = {}
if user_input is not None:
try:
info = await validate_input(self.hass, user_input)
except CentriConnectConnectionError, CentriConnectTooManyRequestsError:
info = await validate_input(self.hass, update_user_input(user_input))
except (
CentriConnectConnectionError,
CentriConnectTooManyRequestsError,
):
errors["base"] = "cannot_connect"
except CentriConnectNotFoundError:
errors["base"] = "invalid_auth"
except CentriConnectEmptyResponseError, CentriConnectDecodeError:
errors["base"] = "unknown"
except Exception:
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
await self.async_set_unique_id(
unique_id=info[CENTRICONNECT_DEVICE_ID], raise_on_progress=True
)
self._abort_if_unique_id_configured(
updates=user_input, reload_on_update=True
)
return self.async_create_entry(title=info["title"], data=user_input)
return on_success(info, user_input)

return self.async_show_form(
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
step_id=step_id, data_schema=data_schema, errors=errors
)

async def async_step_reconfigure(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle reconfiguration of the integration."""
old_entry = self._get_reconfigure_entry()

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_mismatch(reason="wrong_device")
return self.async_update_reload_and_abort(
old_entry, data_updates=user_input
)

return await self._handle_flow(
step_id="reconfigure",
data_schema=STEP_RECONFIGURE_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: {
**user_input,
CONF_DEVICE_ID: old_entry.data[CONF_DEVICE_ID],
},
on_success=_on_success,
)

async def async_step_reauth(
self, entry_data: Mapping[str, Any]
) -> ConfigFlowResult:
"""Handle configuration by re-auth."""
self._device_id = entry_data[CONF_DEVICE_ID]
return await self.async_step_reauth_confirm()

async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Perform reauthentication upon an API authentication error."""

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_mismatch(reason="wrong_device")
return self.async_update_reload_and_abort(
self._get_reauth_entry(), data_updates=user_input
)

return await self._handle_flow(
step_id="reauth_confirm",
data_schema=STEP_REAUTHENTICATE_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: {
**user_input,
CONF_DEVICE_ID: self._device_id,
},
on_success=_on_success,
)

@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the initial step."""

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_configured(
updates=user_input, reload_on_update=True
)
return self.async_create_entry(title=info["title"], data=user_input)

return await self._handle_flow(
step_id="user",
data_schema=STEP_USER_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: user_input,
on_success=_on_success,
)
4 changes: 2 additions & 2 deletions homeassistant/components/centriconnect/quality_scale.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,7 +42,7 @@ rules:
integration-owner: done
log-when-unavailable: done
parallel-updates: done
reauthentication-flow: todo
reauthentication-flow: done
test-coverage: done

# Gold
Expand DownExpand Up@@ -70,7 +70,7 @@ rules:
entity-translations: done
exception-translations: done
icon-translations: done
reconfiguration-flow: todo
reconfiguration-flow: done
repair-issues:
status: exempt
comment: No user-actionable repair scenarios identified for this integration.
Expand Down
27 changes: 26 additions & 1 deletion homeassistant/components/centriconnect/strings.json
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,39 @@
{
"config": {
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
"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%]",
"wrong_device": "This CentriConnect/MyPropane device does not match the existing device ID. Please make sure you entered the credentials correctly."
},
"error": {
"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%]"
},
"step": {
"reauth_confirm": {
"data": {
"password": "[%key:component::centriconnect::config::step::user::data::password%]",
"username": "[%key:component::centriconnect::config::step::user::data::username%]"
},
"data_description": {
"password": "[%key:component::centriconnect::config::step::user::data_description::password%]",
"username": "[%key:component::centriconnect::config::step::user::data_description::username%]"
},
"description": "[%key:component::centriconnect::config::step::user::description%]"
},
"reconfigure": {
"data": {
"password": "[%key:component::centriconnect::config::step::user::data::password%]",
"username": "[%key:component::centriconnect::config::step::user::data::username%]"
},
"data_description": {
"password": "[%key:component::centriconnect::config::step::user::data_description::password%]",
"username": "[%key:component::centriconnect::config::step::user::data_description::username%]"
},
"description": "[%key:component::centriconnect::config::step::user::description%]"
},
"user": {
"data": {
"device_id": "Device ID",
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/google_cloud/manifest.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@
"integration_type": "service",
"iot_class": "cloud_push",
"requirements": [
"google-cloud-texttospeech==2.25.1",
"google-cloud-speech==2.31.1"
"google-cloud-texttospeech==2.37.0",
"google-cloud-speech==2.40.0"
]
}
3 changes: 2 additions & 1 deletion homeassistant/components/ipp/config_flow.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,7 +27,7 @@
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo

from .const import CONF_BASE_PATH, CONF_SERIAL, DOMAIN
from .const import CONF_BASE_PATH, CONF_SERIAL, DOMAIN, REQUEST_TIMEOUT

_LOGGER = logging.getLogger(__name__)

Expand All@@ -45,6 +45,7 @@ async def validate_input(hass: HomeAssistant, data: dict) -> dict[str, Any]:
tls=data[CONF_SSL],
verify_ssl=data[CONF_VERIFY_SSL],
session=session,
request_timeout=REQUEST_TIMEOUT,
)

printer = await ipp.printer()
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/ipp/const.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,6 +14,9 @@
ATTR_STATE_REASON = "state_reason"
ATTR_URI_SUPPORTED = "uri_supported"

# Printers waking from sleep can take well over pyipp's own default
REQUEST_TIMEOUT = 30

# Config Keys
CONF_BASE_PATH = "base_path"
CONF_SERIAL = "serial"
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/ipp/coordinator.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,7 +12,7 @@
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import CONF_BASE_PATH, DOMAIN
from .const import CONF_BASE_PATH, DOMAIN, REQUEST_TIMEOUT

SCAN_INTERVAL = timedelta(seconds=60)

Expand All@@ -36,6 +36,7 @@ def __init__(self, hass: HomeAssistant, config_entry: IPPConfigEntry) -> None:
tls=config_entry.data[CONF_SSL],
verify_ssl=config_entry.data[CONF_VERIFY_SSL],
session=async_get_clientsession(hass, config_entry.data[CONF_VERIFY_SSL]),
request_timeout=REQUEST_TIMEOUT,
)

super().__init__(
Expand Down
9 changes: 9 additions & 0 deletions homeassistant/components/lunatone/icons.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
{
"entity": {
"sensor": {
"dali_line_status": {
"default": "mdi:current-ac"
}
}
}
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [pull] dev from home-assistant:dev by pull[bot] · Pull Request #2408 · code/app-python-home-assistant-core · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
381db53
Add ventilation quickmode switches to ViCare (#179430)
lackas Aug 29, 2026
52adc20
Add Priority Status sensor to Lyric integration (#177065)
clutch2sft Aug 29, 2026
99192f5
Add serial number to Roborock devices (#180465)
ximex Aug 29, 2026
d75f497
Add Tailscale connected to control binary sensor (#179506)
AlfonsoDehesa Aug 29, 2026
b6b40e2
Include contributor reviewed 2 PRs in ha merge queue skill (#180631)
silamon Aug 29, 2026
2f50531
Scan every supported wireless interface in Mikrotik (#180636)
chemelli74 Aug 29, 2026
05c2618
Add 100% coverage for coordinator in Mikrotik (#180637)
chemelli74 Aug 29, 2026
76f77d0
Add 100% coverage to light in Midea (#180640)
chemelli74 Aug 29, 2026
8a89fa8
Give a sleeping printer time to wake up (#180616)
frenck Aug 29, 2026
6f9d552
Add DALI line status diagnostic sensor to lunatone (#179706)
MoonDevLT Aug 29, 2026
b4826e7
Add 100% coverage to coordinator in Shelly (#180644)
chemelli74 Aug 29, 2026
0313d49
Add 100% coverage to coordinator in Fritz (#180647)
chemelli74 Aug 29, 2026
74a364c
Add 100% coverage to sensor in Fritz (#180646)
chemelli74 Aug 29, 2026
8575b67
Add 100% coverage to todo in Alexa Devices (#180638)
chemelli74 Aug 29, 2026
93791ed
Add 100% coverage to binary_sensor in Midea (#180642)
chemelli74 Aug 29, 2026
6a6f930
Split the Elgato user flow init from its data (#180654)
frenck Aug 29, 2026
a1f7924
Split the Peblar user flow init from its data (#180653)
frenck Aug 29, 2026
6a1fe7c
Split the Twente Milieu user flow init from its data (#180645)
frenck Aug 29, 2026
db71607
Split the Tailwind user flow init from its data (#180648)
frenck Aug 29, 2026
e50ca95
Split the Tailscale user flow init from its data (#180649)
frenck Aug 29, 2026
959970d
Split the SolarEdge user flow init from its data (#180650)
frenck Aug 29, 2026
755a049
Split the Season user flow init from its data (#180651)
frenck Aug 29, 2026
fd790dd
Split the PVOutput user flow init from its data (#180652)
frenck Aug 29, 2026
d2d35fe
Split the Whois user flow init from its data (#180643)
frenck Aug 29, 2026
8afadfa
Split the AdGuard Home user flow init from its data (#180639)
frenck Aug 29, 2026
8fc0cc5
Split the WLED user flow init from its data (#180641)
frenck Aug 29, 2026
6d5256e
Mark Vistapool entities unavailable while the push connection is down…
fdebrus Aug 29, 2026
6eabc44
Bump google cloud dependencies (#180625)
silamon Aug 29, 2026
12fc18f
Bump probatio to 0.11.4 (#180655)
frenck Aug 29, 2026
018694c
Bump uiprotect to 16.6.1 (#180670)
RaHehl Aug 29, 2026
41dbe41
Split the Samsung SyncThru user flow init from its data (#180661)
frenck Aug 29, 2026
bf43038
Split The Things Network user flow init from its data (#180660)
frenck Aug 29, 2026
f008a3a
Split the Syncthing user flow init from its data (#180662)
frenck Aug 29, 2026
856a73f
Split the Soma user flow init from its data (#180664)
frenck Aug 29, 2026
40b951a
Split the StarLine user flow init from its data (#180663)
frenck Aug 29, 2026
7bb0412
Split the Smarla user flow init from its data (#180665)
frenck Aug 29, 2026
4b5930c
Split the SleepIQ user flow init from its data (#180666)
frenck Aug 29, 2026
57aecb2
Split the SkyBell user flow init from its data (#180674)
frenck Aug 29, 2026
7fd88d5
Split the 17TRACK user flow init from its data (#180675)
frenck Aug 29, 2026
c186313
Split the ROVA user flow init from its data (#180676)
frenck Aug 29, 2026
47fad86
Split the Slack user flow init from its data (#180673)
frenck Aug 29, 2026
a1eba84
Split the ROMY user flow init from its data (#180680)
frenck Aug 29, 2026
5c94fb9
Add battery support to SolarEdge Modbus (#180657)
frenck Aug 29, 2026
60be162
Split the Redgtech user flow init from its data (#180681)
frenck Aug 29, 2026
a9fbc0d
Add reconfigure and reauth flows for CentriConnect (#180215)
gresrun Aug 29, 2026
915d135
Split the PoolSense user flow init from its data (#180685)
frenck Aug 29, 2026
e2e687b
Split the Pterodactyl user flow init from its data (#180684)
frenck Aug 29, 2026
fddd796
Split the Pushover user flow init from its data (#180682)
frenck Aug 29, 2026
b31c625
Split the Pushbullet user flow init from its data (#180683)
frenck Aug 29, 2026
3052056
Add binary sensors to SolarEdge Modbus (#180687)
frenck Aug 29, 2026
b50835d
Add number entities to SolarEdge Modbus (#180691)
frenck Aug 29, 2026
5914747
Bump midea-local to 10.1.0 (#180694)
rokam Aug 29, 2026
e4455e9
Add state_class to UniFi device temperature sensor (#180688)
bob-laz Aug 29, 2026
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
27 changes: 21 additions & 6 deletions .claude/skills/ha-merge-queue/SKILL.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,7 +27,7 @@ verify every finalist with the per-PR checks below.

## Verify each finalist

Check all five. A PR fails the shortlist if any one fails.
Check all six conditions. A PR fails the shortlist if any of checks 1 through 5 fail.

Paginate every list response before deciding. Check runs, reviews and review threads are all
paged, typically 30 per page, and a full-suite Home Assistant PR runs to 40-odd check runs —
Expand DownExpand Up@@ -90,12 +90,27 @@ Compare the returned count against the reported total and keep fetching until th
discount one for the category it appears to fall into; an unaddressed defect is a
blocker whether or not anyone is arguing about it.

6. **Peer-Review Checklist Verification (Priority Boost)** — inspect the PR body text for
the template checkbox: `- [x] I have reviewed two other [open pull requests][prs] in this repository.`
- **Checked (`[x]`):** Give this PR higher priority in ranking to reward contributors helping
clear the review backlog.
- **Unchecked (`[ ]` or missing):** Keep in queue with standard priority (do not disqualify).

## Report

Rank by how little work each PR needs: `clean` first, then `blocked` with everything else
green. For each PR give the number as a full markdown link, the integration or core area,
one line on what it does, and its blocking state. Plenty of `home-assistant/core` PRs touch
helpers, the framework, the recorder or repo tooling and have no integration at all — name
Rank and order candidates primarily by their status readiness (`clean` first, then `blocked`
with everything else green), and **secondarily by peer-review participation**:

1. **Clean PRs** with the `[x] I have reviewed two other open pull requests...` checkbox checked.
2. **Clean PRs** without the checkbox checked.
3. **Blocked/Near-miss PRs** with the `[x] I have reviewed two other open pull requests...` checkbox checked.
4. **Blocked/Near-miss PRs** without the checkbox checked.

For each PR give the number as a full markdown link, the integration or core area,
one line on what it does, its blocking state, and explicitly note if the author checked the
peer-review box (e.g., "⭐ *Contributor reviewed 2 PRs*").

Plenty of `home-assistant/core` PRs touch helpers, the framework, the recorder or repo tooling and have no integration at all — name
what they touch instead, rather than dropping them or inventing one.

Then list the near-misses separately, each with the one action that unblocks it. The
Expand All@@ -115,4 +130,4 @@ change but carries no `breaking-change` label will silently miss the release not
- Only report in the CONSOLE. DO NOT ACT ON GITHUB — no comments, no reviews, no merges,
no pushes to contributor branches. Per `AI_POLICY.md`, a human decides and acts.
- Never call a PR ready on green CI alone. Read the diff of every PR you shortlist; CI
cannot tell you whether the change is correct or wanted.
cannot tell you whether the change is correct or wanted.
134 changes: 116 additions & 18 deletions homeassistant/components/centriconnect/config_flow.py
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
"""Config flow for the CentriConnect/MyPropane API integration."""

from collections.abc import Callable, Mapping
import logging
from typing import Any, override

Expand All@@ -11,7 +12,7 @@
CentriConnectNotFoundError,
CentriConnectTooManyRequestsError,
)
import voluptuous as vol
import probatio

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_DEVICE_ID, CONF_PASSWORD, CONF_USERNAME
Expand All@@ -22,11 +23,25 @@

_LOGGER = logging.getLogger(__name__)

STEP_USER_DATA_SCHEMA = vol.Schema(
STEP_RECONFIGURE_DATA_SCHEMA = probatio.Schema(
{
vol.Required(CONF_USERNAME): str,
vol.Required(CONF_DEVICE_ID): str,
vol.Required(CONF_PASSWORD): str,
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_PASSWORD): str,
}
)

STEP_REAUTHENTICATE_DATA_SCHEMA = probatio.Schema(
{
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_PASSWORD): str,
}
)

STEP_USER_DATA_SCHEMA = probatio.Schema(
{
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_DEVICE_ID): str,
probatio.Required(CONF_PASSWORD): str,
}
)

Expand DownExpand Up@@ -57,34 +72,117 @@ class CentriConnectConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for CentriConnect/MyPropane API."""

VERSION = 1

@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
_device_id: str | None = None

async def _handle_flow(
self,
step_id: str,
data_schema: probatio.Schema,
user_input: dict[str, Any] | None,
update_user_input: Callable[[dict[str, Any]], dict[str, Any]],
on_success: Callable[[dict[str, Any], dict[str, Any]], ConfigFlowResult],
) -> ConfigFlowResult:
"""Handle the initial step."""
"""Handle the flow for both user and reconfigure steps."""
errors: dict[str, str] = {}
if user_input is not None:
try:
info = await validate_input(self.hass, user_input)
except CentriConnectConnectionError, CentriConnectTooManyRequestsError:
info = await validate_input(self.hass, update_user_input(user_input))
except (
CentriConnectConnectionError,
CentriConnectTooManyRequestsError,
):
errors["base"] = "cannot_connect"
except CentriConnectNotFoundError:
errors["base"] = "invalid_auth"
except CentriConnectEmptyResponseError, CentriConnectDecodeError:
errors["base"] = "unknown"
except Exception:
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
await self.async_set_unique_id(
unique_id=info[CENTRICONNECT_DEVICE_ID], raise_on_progress=True
)
self._abort_if_unique_id_configured(
updates=user_input, reload_on_update=True
)
return self.async_create_entry(title=info["title"], data=user_input)
return on_success(info, user_input)

return self.async_show_form(
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
step_id=step_id, data_schema=data_schema, errors=errors
)

async def async_step_reconfigure(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle reconfiguration of the integration."""
old_entry = self._get_reconfigure_entry()

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_mismatch(reason="wrong_device")
return self.async_update_reload_and_abort(
old_entry, data_updates=user_input
)

return await self._handle_flow(
step_id="reconfigure",
data_schema=STEP_RECONFIGURE_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: {
**user_input,
CONF_DEVICE_ID: old_entry.data[CONF_DEVICE_ID],
},
on_success=_on_success,
)

async def async_step_reauth(
self, entry_data: Mapping[str, Any]
) -> ConfigFlowResult:
"""Handle configuration by re-auth."""
self._device_id = entry_data[CONF_DEVICE_ID]
return await self.async_step_reauth_confirm()

async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Perform reauthentication upon an API authentication error."""

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_mismatch(reason="wrong_device")
return self.async_update_reload_and_abort(
self._get_reauth_entry(), data_updates=user_input
)

return await self._handle_flow(
step_id="reauth_confirm",
data_schema=STEP_REAUTHENTICATE_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: {
**user_input,
CONF_DEVICE_ID: self._device_id,
},
on_success=_on_success,
)

@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the initial step."""

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_configured(
updates=user_input, reload_on_update=True
)
return self.async_create_entry(title=info["title"], data=user_input)

return await self._handle_flow(
step_id="user",
data_schema=STEP_USER_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: user_input,
on_success=_on_success,
)
4 changes: 2 additions & 2 deletions homeassistant/components/centriconnect/quality_scale.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,7 +42,7 @@ rules:
integration-owner: done
log-when-unavailable: done
parallel-updates: done
reauthentication-flow: todo
reauthentication-flow: done
test-coverage: done

# Gold
Expand DownExpand Up@@ -70,7 +70,7 @@ rules:
entity-translations: done
exception-translations: done
icon-translations: done
reconfiguration-flow: todo
reconfiguration-flow: done
repair-issues:
status: exempt
comment: No user-actionable repair scenarios identified for this integration.
Expand Down
27 changes: 26 additions & 1 deletion homeassistant/components/centriconnect/strings.json
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,39 @@
{
"config": {
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
"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%]",
"wrong_device": "This CentriConnect/MyPropane device does not match the existing device ID. Please make sure you entered the credentials correctly."
},
"error": {
"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%]"
},
"step": {
"reauth_confirm": {
"data": {
"password": "[%key:component::centriconnect::config::step::user::data::password%]",
"username": "[%key:component::centriconnect::config::step::user::data::username%]"
},
"data_description": {
"password": "[%key:component::centriconnect::config::step::user::data_description::password%]",
"username": "[%key:component::centriconnect::config::step::user::data_description::username%]"
},
"description": "[%key:component::centriconnect::config::step::user::description%]"
},
"reconfigure": {
"data": {
"password": "[%key:component::centriconnect::config::step::user::data::password%]",
"username": "[%key:component::centriconnect::config::step::user::data::username%]"
},
"data_description": {
"password": "[%key:component::centriconnect::config::step::user::data_description::password%]",
"username": "[%key:component::centriconnect::config::step::user::data_description::username%]"
},
"description": "[%key:component::centriconnect::config::step::user::description%]"
},
"user": {
"data": {
"device_id": "Device ID",
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/google_cloud/manifest.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@
"integration_type": "service",
"iot_class": "cloud_push",
"requirements": [
"google-cloud-texttospeech==2.25.1",
"google-cloud-speech==2.31.1"
"google-cloud-texttospeech==2.37.0",
"google-cloud-speech==2.40.0"
]
}
3 changes: 2 additions & 1 deletion homeassistant/components/ipp/config_flow.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,7 +27,7 @@
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo

from .const import CONF_BASE_PATH, CONF_SERIAL, DOMAIN
from .const import CONF_BASE_PATH, CONF_SERIAL, DOMAIN, REQUEST_TIMEOUT

_LOGGER = logging.getLogger(__name__)

Expand All@@ -45,6 +45,7 @@ async def validate_input(hass: HomeAssistant, data: dict) -> dict[str, Any]:
tls=data[CONF_SSL],
verify_ssl=data[CONF_VERIFY_SSL],
session=session,
request_timeout=REQUEST_TIMEOUT,
)

printer = await ipp.printer()
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/ipp/const.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,6 +14,9 @@
ATTR_STATE_REASON = "state_reason"
ATTR_URI_SUPPORTED = "uri_supported"

# Printers waking from sleep can take well over pyipp's own default
REQUEST_TIMEOUT = 30

# Config Keys
CONF_BASE_PATH = "base_path"
CONF_SERIAL = "serial"
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/ipp/coordinator.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,7 +12,7 @@
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import CONF_BASE_PATH, DOMAIN
from .const import CONF_BASE_PATH, DOMAIN, REQUEST_TIMEOUT

SCAN_INTERVAL = timedelta(seconds=60)

Expand All@@ -36,6 +36,7 @@ def __init__(self, hass: HomeAssistant, config_entry: IPPConfigEntry) -> None:
tls=config_entry.data[CONF_SSL],
verify_ssl=config_entry.data[CONF_VERIFY_SSL],
session=async_get_clientsession(hass, config_entry.data[CONF_VERIFY_SSL]),
request_timeout=REQUEST_TIMEOUT,
)

super().__init__(
Expand Down
9 changes: 9 additions & 0 deletions homeassistant/components/lunatone/icons.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
{
"entity": {
"sensor": {
"dali_line_status": {
"default": "mdi:current-ac"
}
}
}
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [pull] dev from home-assistant:dev by pull[bot] · Pull Request #2408 · code/app-python-home-assistant-core · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
381db53
Add ventilation quickmode switches to ViCare (#179430)
lackas Aug 29, 2026
52adc20
Add Priority Status sensor to Lyric integration (#177065)
clutch2sft Aug 29, 2026
99192f5
Add serial number to Roborock devices (#180465)
ximex Aug 29, 2026
d75f497
Add Tailscale connected to control binary sensor (#179506)
AlfonsoDehesa Aug 29, 2026
b6b40e2
Include contributor reviewed 2 PRs in ha merge queue skill (#180631)
silamon Aug 29, 2026
2f50531
Scan every supported wireless interface in Mikrotik (#180636)
chemelli74 Aug 29, 2026
05c2618
Add 100% coverage for coordinator in Mikrotik (#180637)
chemelli74 Aug 29, 2026
76f77d0
Add 100% coverage to light in Midea (#180640)
chemelli74 Aug 29, 2026
8a89fa8
Give a sleeping printer time to wake up (#180616)
frenck Aug 29, 2026
6f9d552
Add DALI line status diagnostic sensor to lunatone (#179706)
MoonDevLT Aug 29, 2026
b4826e7
Add 100% coverage to coordinator in Shelly (#180644)
chemelli74 Aug 29, 2026
0313d49
Add 100% coverage to coordinator in Fritz (#180647)
chemelli74 Aug 29, 2026
74a364c
Add 100% coverage to sensor in Fritz (#180646)
chemelli74 Aug 29, 2026
8575b67
Add 100% coverage to todo in Alexa Devices (#180638)
chemelli74 Aug 29, 2026
93791ed
Add 100% coverage to binary_sensor in Midea (#180642)
chemelli74 Aug 29, 2026
6a6f930
Split the Elgato user flow init from its data (#180654)
frenck Aug 29, 2026
a1f7924
Split the Peblar user flow init from its data (#180653)
frenck Aug 29, 2026
6a1fe7c
Split the Twente Milieu user flow init from its data (#180645)
frenck Aug 29, 2026
db71607
Split the Tailwind user flow init from its data (#180648)
frenck Aug 29, 2026
e50ca95
Split the Tailscale user flow init from its data (#180649)
frenck Aug 29, 2026
959970d
Split the SolarEdge user flow init from its data (#180650)
frenck Aug 29, 2026
755a049
Split the Season user flow init from its data (#180651)
frenck Aug 29, 2026
fd790dd
Split the PVOutput user flow init from its data (#180652)
frenck Aug 29, 2026
d2d35fe
Split the Whois user flow init from its data (#180643)
frenck Aug 29, 2026
8afadfa
Split the AdGuard Home user flow init from its data (#180639)
frenck Aug 29, 2026
8fc0cc5
Split the WLED user flow init from its data (#180641)
frenck Aug 29, 2026
6d5256e
Mark Vistapool entities unavailable while the push connection is down…
fdebrus Aug 29, 2026
6eabc44
Bump google cloud dependencies (#180625)
silamon Aug 29, 2026
12fc18f
Bump probatio to 0.11.4 (#180655)
frenck Aug 29, 2026
018694c
Bump uiprotect to 16.6.1 (#180670)
RaHehl Aug 29, 2026
41dbe41
Split the Samsung SyncThru user flow init from its data (#180661)
frenck Aug 29, 2026
bf43038
Split The Things Network user flow init from its data (#180660)
frenck Aug 29, 2026
f008a3a
Split the Syncthing user flow init from its data (#180662)
frenck Aug 29, 2026
856a73f
Split the Soma user flow init from its data (#180664)
frenck Aug 29, 2026
40b951a
Split the StarLine user flow init from its data (#180663)
frenck Aug 29, 2026
7bb0412
Split the Smarla user flow init from its data (#180665)
frenck Aug 29, 2026
4b5930c
Split the SleepIQ user flow init from its data (#180666)
frenck Aug 29, 2026
57aecb2
Split the SkyBell user flow init from its data (#180674)
frenck Aug 29, 2026
7fd88d5
Split the 17TRACK user flow init from its data (#180675)
frenck Aug 29, 2026
c186313
Split the ROVA user flow init from its data (#180676)
frenck Aug 29, 2026
47fad86
Split the Slack user flow init from its data (#180673)
frenck Aug 29, 2026
a1eba84
Split the ROMY user flow init from its data (#180680)
frenck Aug 29, 2026
5c94fb9
Add battery support to SolarEdge Modbus (#180657)
frenck Aug 29, 2026
60be162
Split the Redgtech user flow init from its data (#180681)
frenck Aug 29, 2026
a9fbc0d
Add reconfigure and reauth flows for CentriConnect (#180215)
gresrun Aug 29, 2026
915d135
Split the PoolSense user flow init from its data (#180685)
frenck Aug 29, 2026
e2e687b
Split the Pterodactyl user flow init from its data (#180684)
frenck Aug 29, 2026
fddd796
Split the Pushover user flow init from its data (#180682)
frenck Aug 29, 2026
b31c625
Split the Pushbullet user flow init from its data (#180683)
frenck Aug 29, 2026
3052056
Add binary sensors to SolarEdge Modbus (#180687)
frenck Aug 29, 2026
b50835d
Add number entities to SolarEdge Modbus (#180691)
frenck Aug 29, 2026
5914747
Bump midea-local to 10.1.0 (#180694)
rokam Aug 29, 2026
e4455e9
Add state_class to UniFi device temperature sensor (#180688)
bob-laz Aug 29, 2026
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
27 changes: 21 additions & 6 deletions .claude/skills/ha-merge-queue/SKILL.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,7 +27,7 @@ verify every finalist with the per-PR checks below.

## Verify each finalist

Check all five. A PR fails the shortlist if any one fails.
Check all six conditions. A PR fails the shortlist if any of checks 1 through 5 fail.

Paginate every list response before deciding. Check runs, reviews and review threads are all
paged, typically 30 per page, and a full-suite Home Assistant PR runs to 40-odd check runs —
Expand DownExpand Up@@ -90,12 +90,27 @@ Compare the returned count against the reported total and keep fetching until th
discount one for the category it appears to fall into; an unaddressed defect is a
blocker whether or not anyone is arguing about it.

6. **Peer-Review Checklist Verification (Priority Boost)** — inspect the PR body text for
the template checkbox: `- [x] I have reviewed two other [open pull requests][prs] in this repository.`
- **Checked (`[x]`):** Give this PR higher priority in ranking to reward contributors helping
clear the review backlog.
- **Unchecked (`[ ]` or missing):** Keep in queue with standard priority (do not disqualify).

## Report

Rank by how little work each PR needs: `clean` first, then `blocked` with everything else
green. For each PR give the number as a full markdown link, the integration or core area,
one line on what it does, and its blocking state. Plenty of `home-assistant/core` PRs touch
helpers, the framework, the recorder or repo tooling and have no integration at all — name
Rank and order candidates primarily by their status readiness (`clean` first, then `blocked`
with everything else green), and **secondarily by peer-review participation**:

1. **Clean PRs** with the `[x] I have reviewed two other open pull requests...` checkbox checked.
2. **Clean PRs** without the checkbox checked.
3. **Blocked/Near-miss PRs** with the `[x] I have reviewed two other open pull requests...` checkbox checked.
4. **Blocked/Near-miss PRs** without the checkbox checked.

For each PR give the number as a full markdown link, the integration or core area,
one line on what it does, its blocking state, and explicitly note if the author checked the
peer-review box (e.g., "⭐ *Contributor reviewed 2 PRs*").

Plenty of `home-assistant/core` PRs touch helpers, the framework, the recorder or repo tooling and have no integration at all — name
what they touch instead, rather than dropping them or inventing one.

Then list the near-misses separately, each with the one action that unblocks it. The
Expand All@@ -115,4 +130,4 @@ change but carries no `breaking-change` label will silently miss the release not
- Only report in the CONSOLE. DO NOT ACT ON GITHUB — no comments, no reviews, no merges,
no pushes to contributor branches. Per `AI_POLICY.md`, a human decides and acts.
- Never call a PR ready on green CI alone. Read the diff of every PR you shortlist; CI
cannot tell you whether the change is correct or wanted.
cannot tell you whether the change is correct or wanted.
134 changes: 116 additions & 18 deletions homeassistant/components/centriconnect/config_flow.py
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
"""Config flow for the CentriConnect/MyPropane API integration."""

from collections.abc import Callable, Mapping
import logging
from typing import Any, override

Expand All@@ -11,7 +12,7 @@
CentriConnectNotFoundError,
CentriConnectTooManyRequestsError,
)
import voluptuous as vol
import probatio

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_DEVICE_ID, CONF_PASSWORD, CONF_USERNAME
Expand All@@ -22,11 +23,25 @@

_LOGGER = logging.getLogger(__name__)

STEP_USER_DATA_SCHEMA = vol.Schema(
STEP_RECONFIGURE_DATA_SCHEMA = probatio.Schema(
{
vol.Required(CONF_USERNAME): str,
vol.Required(CONF_DEVICE_ID): str,
vol.Required(CONF_PASSWORD): str,
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_PASSWORD): str,
}
)

STEP_REAUTHENTICATE_DATA_SCHEMA = probatio.Schema(
{
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_PASSWORD): str,
}
)

STEP_USER_DATA_SCHEMA = probatio.Schema(
{
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_DEVICE_ID): str,
probatio.Required(CONF_PASSWORD): str,
}
)

Expand DownExpand Up@@ -57,34 +72,117 @@ class CentriConnectConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for CentriConnect/MyPropane API."""

VERSION = 1

@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
_device_id: str | None = None

async def _handle_flow(
self,
step_id: str,
data_schema: probatio.Schema,
user_input: dict[str, Any] | None,
update_user_input: Callable[[dict[str, Any]], dict[str, Any]],
on_success: Callable[[dict[str, Any], dict[str, Any]], ConfigFlowResult],
) -> ConfigFlowResult:
"""Handle the initial step."""
"""Handle the flow for both user and reconfigure steps."""
errors: dict[str, str] = {}
if user_input is not None:
try:
info = await validate_input(self.hass, user_input)
except CentriConnectConnectionError, CentriConnectTooManyRequestsError:
info = await validate_input(self.hass, update_user_input(user_input))
except (
CentriConnectConnectionError,
CentriConnectTooManyRequestsError,
):
errors["base"] = "cannot_connect"
except CentriConnectNotFoundError:
errors["base"] = "invalid_auth"
except CentriConnectEmptyResponseError, CentriConnectDecodeError:
errors["base"] = "unknown"
except Exception:
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
await self.async_set_unique_id(
unique_id=info[CENTRICONNECT_DEVICE_ID], raise_on_progress=True
)
self._abort_if_unique_id_configured(
updates=user_input, reload_on_update=True
)
return self.async_create_entry(title=info["title"], data=user_input)
return on_success(info, user_input)

return self.async_show_form(
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
step_id=step_id, data_schema=data_schema, errors=errors
)

async def async_step_reconfigure(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle reconfiguration of the integration."""
old_entry = self._get_reconfigure_entry()

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_mismatch(reason="wrong_device")
return self.async_update_reload_and_abort(
old_entry, data_updates=user_input
)

return await self._handle_flow(
step_id="reconfigure",
data_schema=STEP_RECONFIGURE_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: {
**user_input,
CONF_DEVICE_ID: old_entry.data[CONF_DEVICE_ID],
},
on_success=_on_success,
)

async def async_step_reauth(
self, entry_data: Mapping[str, Any]
) -> ConfigFlowResult:
"""Handle configuration by re-auth."""
self._device_id = entry_data[CONF_DEVICE_ID]
return await self.async_step_reauth_confirm()

async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Perform reauthentication upon an API authentication error."""

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_mismatch(reason="wrong_device")
return self.async_update_reload_and_abort(
self._get_reauth_entry(), data_updates=user_input
)

return await self._handle_flow(
step_id="reauth_confirm",
data_schema=STEP_REAUTHENTICATE_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: {
**user_input,
CONF_DEVICE_ID: self._device_id,
},
on_success=_on_success,
)

@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the initial step."""

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_configured(
updates=user_input, reload_on_update=True
)
return self.async_create_entry(title=info["title"], data=user_input)

return await self._handle_flow(
step_id="user",
data_schema=STEP_USER_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: user_input,
on_success=_on_success,
)
4 changes: 2 additions & 2 deletions homeassistant/components/centriconnect/quality_scale.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,7 +42,7 @@ rules:
integration-owner: done
log-when-unavailable: done
parallel-updates: done
reauthentication-flow: todo
reauthentication-flow: done
test-coverage: done

# Gold
Expand DownExpand Up@@ -70,7 +70,7 @@ rules:
entity-translations: done
exception-translations: done
icon-translations: done
reconfiguration-flow: todo
reconfiguration-flow: done
repair-issues:
status: exempt
comment: No user-actionable repair scenarios identified for this integration.
Expand Down
27 changes: 26 additions & 1 deletion homeassistant/components/centriconnect/strings.json
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,39 @@
{
"config": {
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
"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%]",
"wrong_device": "This CentriConnect/MyPropane device does not match the existing device ID. Please make sure you entered the credentials correctly."
},
"error": {
"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%]"
},
"step": {
"reauth_confirm": {
"data": {
"password": "[%key:component::centriconnect::config::step::user::data::password%]",
"username": "[%key:component::centriconnect::config::step::user::data::username%]"
},
"data_description": {
"password": "[%key:component::centriconnect::config::step::user::data_description::password%]",
"username": "[%key:component::centriconnect::config::step::user::data_description::username%]"
},
"description": "[%key:component::centriconnect::config::step::user::description%]"
},
"reconfigure": {
"data": {
"password": "[%key:component::centriconnect::config::step::user::data::password%]",
"username": "[%key:component::centriconnect::config::step::user::data::username%]"
},
"data_description": {
"password": "[%key:component::centriconnect::config::step::user::data_description::password%]",
"username": "[%key:component::centriconnect::config::step::user::data_description::username%]"
},
"description": "[%key:component::centriconnect::config::step::user::description%]"
},
"user": {
"data": {
"device_id": "Device ID",
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/google_cloud/manifest.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@
"integration_type": "service",
"iot_class": "cloud_push",
"requirements": [
"google-cloud-texttospeech==2.25.1",
"google-cloud-speech==2.31.1"
"google-cloud-texttospeech==2.37.0",
"google-cloud-speech==2.40.0"
]
}
3 changes: 2 additions & 1 deletion homeassistant/components/ipp/config_flow.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,7 +27,7 @@
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo

from .const import CONF_BASE_PATH, CONF_SERIAL, DOMAIN
from .const import CONF_BASE_PATH, CONF_SERIAL, DOMAIN, REQUEST_TIMEOUT

_LOGGER = logging.getLogger(__name__)

Expand All@@ -45,6 +45,7 @@ async def validate_input(hass: HomeAssistant, data: dict) -> dict[str, Any]:
tls=data[CONF_SSL],
verify_ssl=data[CONF_VERIFY_SSL],
session=session,
request_timeout=REQUEST_TIMEOUT,
)

printer = await ipp.printer()
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/ipp/const.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,6 +14,9 @@
ATTR_STATE_REASON = "state_reason"
ATTR_URI_SUPPORTED = "uri_supported"

# Printers waking from sleep can take well over pyipp's own default
REQUEST_TIMEOUT = 30

# Config Keys
CONF_BASE_PATH = "base_path"
CONF_SERIAL = "serial"
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/ipp/coordinator.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,7 +12,7 @@
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import CONF_BASE_PATH, DOMAIN
from .const import CONF_BASE_PATH, DOMAIN, REQUEST_TIMEOUT

SCAN_INTERVAL = timedelta(seconds=60)

Expand All@@ -36,6 +36,7 @@ def __init__(self, hass: HomeAssistant, config_entry: IPPConfigEntry) -> None:
tls=config_entry.data[CONF_SSL],
verify_ssl=config_entry.data[CONF_VERIFY_SSL],
session=async_get_clientsession(hass, config_entry.data[CONF_VERIFY_SSL]),
request_timeout=REQUEST_TIMEOUT,
)

super().__init__(
Expand Down
9 changes: 9 additions & 0 deletions homeassistant/components/lunatone/icons.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
{
"entity": {
"sensor": {
"dali_line_status": {
"default": "mdi:current-ac"
}
}
}
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' [pull] dev from home-assistant:dev by pull[bot] · Pull Request #2408 · code/app-python-home-assistant-core · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
381db53
Add ventilation quickmode switches to ViCare (#179430)
lackas Aug 29, 2026
52adc20
Add Priority Status sensor to Lyric integration (#177065)
clutch2sft Aug 29, 2026
99192f5
Add serial number to Roborock devices (#180465)
ximex Aug 29, 2026
d75f497
Add Tailscale connected to control binary sensor (#179506)
AlfonsoDehesa Aug 29, 2026
b6b40e2
Include contributor reviewed 2 PRs in ha merge queue skill (#180631)
silamon Aug 29, 2026
2f50531
Scan every supported wireless interface in Mikrotik (#180636)
chemelli74 Aug 29, 2026
05c2618
Add 100% coverage for coordinator in Mikrotik (#180637)
chemelli74 Aug 29, 2026
76f77d0
Add 100% coverage to light in Midea (#180640)
chemelli74 Aug 29, 2026
8a89fa8
Give a sleeping printer time to wake up (#180616)
frenck Aug 29, 2026
6f9d552
Add DALI line status diagnostic sensor to lunatone (#179706)
MoonDevLT Aug 29, 2026
b4826e7
Add 100% coverage to coordinator in Shelly (#180644)
chemelli74 Aug 29, 2026
0313d49
Add 100% coverage to coordinator in Fritz (#180647)
chemelli74 Aug 29, 2026
74a364c
Add 100% coverage to sensor in Fritz (#180646)
chemelli74 Aug 29, 2026
8575b67
Add 100% coverage to todo in Alexa Devices (#180638)
chemelli74 Aug 29, 2026
93791ed
Add 100% coverage to binary_sensor in Midea (#180642)
chemelli74 Aug 29, 2026
6a6f930
Split the Elgato user flow init from its data (#180654)
frenck Aug 29, 2026
a1f7924
Split the Peblar user flow init from its data (#180653)
frenck Aug 29, 2026
6a1fe7c
Split the Twente Milieu user flow init from its data (#180645)
frenck Aug 29, 2026
db71607
Split the Tailwind user flow init from its data (#180648)
frenck Aug 29, 2026
e50ca95
Split the Tailscale user flow init from its data (#180649)
frenck Aug 29, 2026
959970d
Split the SolarEdge user flow init from its data (#180650)
frenck Aug 29, 2026
755a049
Split the Season user flow init from its data (#180651)
frenck Aug 29, 2026
fd790dd
Split the PVOutput user flow init from its data (#180652)
frenck Aug 29, 2026
d2d35fe
Split the Whois user flow init from its data (#180643)
frenck Aug 29, 2026
8afadfa
Split the AdGuard Home user flow init from its data (#180639)
frenck Aug 29, 2026
8fc0cc5
Split the WLED user flow init from its data (#180641)
frenck Aug 29, 2026
6d5256e
Mark Vistapool entities unavailable while the push connection is down…
fdebrus Aug 29, 2026
6eabc44
Bump google cloud dependencies (#180625)
silamon Aug 29, 2026
12fc18f
Bump probatio to 0.11.4 (#180655)
frenck Aug 29, 2026
018694c
Bump uiprotect to 16.6.1 (#180670)
RaHehl Aug 29, 2026
41dbe41
Split the Samsung SyncThru user flow init from its data (#180661)
frenck Aug 29, 2026
bf43038
Split The Things Network user flow init from its data (#180660)
frenck Aug 29, 2026
f008a3a
Split the Syncthing user flow init from its data (#180662)
frenck Aug 29, 2026
856a73f
Split the Soma user flow init from its data (#180664)
frenck Aug 29, 2026
40b951a
Split the StarLine user flow init from its data (#180663)
frenck Aug 29, 2026
7bb0412
Split the Smarla user flow init from its data (#180665)
frenck Aug 29, 2026
4b5930c
Split the SleepIQ user flow init from its data (#180666)
frenck Aug 29, 2026
57aecb2
Split the SkyBell user flow init from its data (#180674)
frenck Aug 29, 2026
7fd88d5
Split the 17TRACK user flow init from its data (#180675)
frenck Aug 29, 2026
c186313
Split the ROVA user flow init from its data (#180676)
frenck Aug 29, 2026
47fad86
Split the Slack user flow init from its data (#180673)
frenck Aug 29, 2026
a1eba84
Split the ROMY user flow init from its data (#180680)
frenck Aug 29, 2026
5c94fb9
Add battery support to SolarEdge Modbus (#180657)
frenck Aug 29, 2026
60be162
Split the Redgtech user flow init from its data (#180681)
frenck Aug 29, 2026
a9fbc0d
Add reconfigure and reauth flows for CentriConnect (#180215)
gresrun Aug 29, 2026
915d135
Split the PoolSense user flow init from its data (#180685)
frenck Aug 29, 2026
e2e687b
Split the Pterodactyl user flow init from its data (#180684)
frenck Aug 29, 2026
fddd796
Split the Pushover user flow init from its data (#180682)
frenck Aug 29, 2026
b31c625
Split the Pushbullet user flow init from its data (#180683)
frenck Aug 29, 2026
3052056
Add binary sensors to SolarEdge Modbus (#180687)
frenck Aug 29, 2026
b50835d
Add number entities to SolarEdge Modbus (#180691)
frenck Aug 29, 2026
5914747
Bump midea-local to 10.1.0 (#180694)
rokam Aug 29, 2026
e4455e9
Add state_class to UniFi device temperature sensor (#180688)
bob-laz Aug 29, 2026
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
27 changes: 21 additions & 6 deletions .claude/skills/ha-merge-queue/SKILL.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,7 +27,7 @@ verify every finalist with the per-PR checks below.

## Verify each finalist

Check all five. A PR fails the shortlist if any one fails.
Check all six conditions. A PR fails the shortlist if any of checks 1 through 5 fail.

Paginate every list response before deciding. Check runs, reviews and review threads are all
paged, typically 30 per page, and a full-suite Home Assistant PR runs to 40-odd check runs —
Expand DownExpand Up@@ -90,12 +90,27 @@ Compare the returned count against the reported total and keep fetching until th
discount one for the category it appears to fall into; an unaddressed defect is a
blocker whether or not anyone is arguing about it.

6. **Peer-Review Checklist Verification (Priority Boost)** — inspect the PR body text for
the template checkbox: `- [x] I have reviewed two other [open pull requests][prs] in this repository.`
- **Checked (`[x]`):** Give this PR higher priority in ranking to reward contributors helping
clear the review backlog.
- **Unchecked (`[ ]` or missing):** Keep in queue with standard priority (do not disqualify).

## Report

Rank by how little work each PR needs: `clean` first, then `blocked` with everything else
green. For each PR give the number as a full markdown link, the integration or core area,
one line on what it does, and its blocking state. Plenty of `home-assistant/core` PRs touch
helpers, the framework, the recorder or repo tooling and have no integration at all — name
Rank and order candidates primarily by their status readiness (`clean` first, then `blocked`
with everything else green), and **secondarily by peer-review participation**:

1. **Clean PRs** with the `[x] I have reviewed two other open pull requests...` checkbox checked.
2. **Clean PRs** without the checkbox checked.
3. **Blocked/Near-miss PRs** with the `[x] I have reviewed two other open pull requests...` checkbox checked.
4. **Blocked/Near-miss PRs** without the checkbox checked.

For each PR give the number as a full markdown link, the integration or core area,
one line on what it does, its blocking state, and explicitly note if the author checked the
peer-review box (e.g., "⭐ *Contributor reviewed 2 PRs*").

Plenty of `home-assistant/core` PRs touch helpers, the framework, the recorder or repo tooling and have no integration at all — name
what they touch instead, rather than dropping them or inventing one.

Then list the near-misses separately, each with the one action that unblocks it. The
Expand All@@ -115,4 +130,4 @@ change but carries no `breaking-change` label will silently miss the release not
- Only report in the CONSOLE. DO NOT ACT ON GITHUB — no comments, no reviews, no merges,
no pushes to contributor branches. Per `AI_POLICY.md`, a human decides and acts.
- Never call a PR ready on green CI alone. Read the diff of every PR you shortlist; CI
cannot tell you whether the change is correct or wanted.
cannot tell you whether the change is correct or wanted.
134 changes: 116 additions & 18 deletions homeassistant/components/centriconnect/config_flow.py
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
"""Config flow for the CentriConnect/MyPropane API integration."""

from collections.abc import Callable, Mapping
import logging
from typing import Any, override

Expand All@@ -11,7 +12,7 @@
CentriConnectNotFoundError,
CentriConnectTooManyRequestsError,
)
import voluptuous as vol
import probatio

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_DEVICE_ID, CONF_PASSWORD, CONF_USERNAME
Expand All@@ -22,11 +23,25 @@

_LOGGER = logging.getLogger(__name__)

STEP_USER_DATA_SCHEMA = vol.Schema(
STEP_RECONFIGURE_DATA_SCHEMA = probatio.Schema(
{
vol.Required(CONF_USERNAME): str,
vol.Required(CONF_DEVICE_ID): str,
vol.Required(CONF_PASSWORD): str,
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_PASSWORD): str,
}
)

STEP_REAUTHENTICATE_DATA_SCHEMA = probatio.Schema(
{
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_PASSWORD): str,
}
)

STEP_USER_DATA_SCHEMA = probatio.Schema(
{
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_DEVICE_ID): str,
probatio.Required(CONF_PASSWORD): str,
}
)

Expand DownExpand Up@@ -57,34 +72,117 @@ class CentriConnectConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for CentriConnect/MyPropane API."""

VERSION = 1

@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
_device_id: str | None = None

async def _handle_flow(
self,
step_id: str,
data_schema: probatio.Schema,
user_input: dict[str, Any] | None,
update_user_input: Callable[[dict[str, Any]], dict[str, Any]],
on_success: Callable[[dict[str, Any], dict[str, Any]], ConfigFlowResult],
) -> ConfigFlowResult:
"""Handle the initial step."""
"""Handle the flow for both user and reconfigure steps."""
errors: dict[str, str] = {}
if user_input is not None:
try:
info = await validate_input(self.hass, user_input)
except CentriConnectConnectionError, CentriConnectTooManyRequestsError:
info = await validate_input(self.hass, update_user_input(user_input))
except (
CentriConnectConnectionError,
CentriConnectTooManyRequestsError,
):
errors["base"] = "cannot_connect"
except CentriConnectNotFoundError:
errors["base"] = "invalid_auth"
except CentriConnectEmptyResponseError, CentriConnectDecodeError:
errors["base"] = "unknown"
except Exception:
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
await self.async_set_unique_id(
unique_id=info[CENTRICONNECT_DEVICE_ID], raise_on_progress=True
)
self._abort_if_unique_id_configured(
updates=user_input, reload_on_update=True
)
return self.async_create_entry(title=info["title"], data=user_input)
return on_success(info, user_input)

return self.async_show_form(
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
step_id=step_id, data_schema=data_schema, errors=errors
)

async def async_step_reconfigure(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle reconfiguration of the integration."""
old_entry = self._get_reconfigure_entry()

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_mismatch(reason="wrong_device")
return self.async_update_reload_and_abort(
old_entry, data_updates=user_input
)

return await self._handle_flow(
step_id="reconfigure",
data_schema=STEP_RECONFIGURE_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: {
**user_input,
CONF_DEVICE_ID: old_entry.data[CONF_DEVICE_ID],
},
on_success=_on_success,
)

async def async_step_reauth(
self, entry_data: Mapping[str, Any]
) -> ConfigFlowResult:
"""Handle configuration by re-auth."""
self._device_id = entry_data[CONF_DEVICE_ID]
return await self.async_step_reauth_confirm()

async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Perform reauthentication upon an API authentication error."""

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_mismatch(reason="wrong_device")
return self.async_update_reload_and_abort(
self._get_reauth_entry(), data_updates=user_input
)

return await self._handle_flow(
step_id="reauth_confirm",
data_schema=STEP_REAUTHENTICATE_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: {
**user_input,
CONF_DEVICE_ID: self._device_id,
},
on_success=_on_success,
)

@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the initial step."""

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_configured(
updates=user_input, reload_on_update=True
)
return self.async_create_entry(title=info["title"], data=user_input)

return await self._handle_flow(
step_id="user",
data_schema=STEP_USER_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: user_input,
on_success=_on_success,
)
4 changes: 2 additions & 2 deletions homeassistant/components/centriconnect/quality_scale.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,7 +42,7 @@ rules:
integration-owner: done
log-when-unavailable: done
parallel-updates: done
reauthentication-flow: todo
reauthentication-flow: done
test-coverage: done

# Gold
Expand DownExpand Up@@ -70,7 +70,7 @@ rules:
entity-translations: done
exception-translations: done
icon-translations: done
reconfiguration-flow: todo
reconfiguration-flow: done
repair-issues:
status: exempt
comment: No user-actionable repair scenarios identified for this integration.
Expand Down
27 changes: 26 additions & 1 deletion homeassistant/components/centriconnect/strings.json
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,39 @@
{
"config": {
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
"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%]",
"wrong_device": "This CentriConnect/MyPropane device does not match the existing device ID. Please make sure you entered the credentials correctly."
},
"error": {
"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%]"
},
"step": {
"reauth_confirm": {
"data": {
"password": "[%key:component::centriconnect::config::step::user::data::password%]",
"username": "[%key:component::centriconnect::config::step::user::data::username%]"
},
"data_description": {
"password": "[%key:component::centriconnect::config::step::user::data_description::password%]",
"username": "[%key:component::centriconnect::config::step::user::data_description::username%]"
},
"description": "[%key:component::centriconnect::config::step::user::description%]"
},
"reconfigure": {
"data": {
"password": "[%key:component::centriconnect::config::step::user::data::password%]",
"username": "[%key:component::centriconnect::config::step::user::data::username%]"
},
"data_description": {
"password": "[%key:component::centriconnect::config::step::user::data_description::password%]",
"username": "[%key:component::centriconnect::config::step::user::data_description::username%]"
},
"description": "[%key:component::centriconnect::config::step::user::description%]"
},
"user": {
"data": {
"device_id": "Device ID",
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/google_cloud/manifest.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@
"integration_type": "service",
"iot_class": "cloud_push",
"requirements": [
"google-cloud-texttospeech==2.25.1",
"google-cloud-speech==2.31.1"
"google-cloud-texttospeech==2.37.0",
"google-cloud-speech==2.40.0"
]
}
3 changes: 2 additions & 1 deletion homeassistant/components/ipp/config_flow.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,7 +27,7 @@
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo

from .const import CONF_BASE_PATH, CONF_SERIAL, DOMAIN
from .const import CONF_BASE_PATH, CONF_SERIAL, DOMAIN, REQUEST_TIMEOUT

_LOGGER = logging.getLogger(__name__)

Expand All@@ -45,6 +45,7 @@ async def validate_input(hass: HomeAssistant, data: dict) -> dict[str, Any]:
tls=data[CONF_SSL],
verify_ssl=data[CONF_VERIFY_SSL],
session=session,
request_timeout=REQUEST_TIMEOUT,
)

printer = await ipp.printer()
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/ipp/const.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,6 +14,9 @@
ATTR_STATE_REASON = "state_reason"
ATTR_URI_SUPPORTED = "uri_supported"

# Printers waking from sleep can take well over pyipp's own default
REQUEST_TIMEOUT = 30

# Config Keys
CONF_BASE_PATH = "base_path"
CONF_SERIAL = "serial"
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/ipp/coordinator.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,7 +12,7 @@
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import CONF_BASE_PATH, DOMAIN
from .const import CONF_BASE_PATH, DOMAIN, REQUEST_TIMEOUT

SCAN_INTERVAL = timedelta(seconds=60)

Expand All@@ -36,6 +36,7 @@ def __init__(self, hass: HomeAssistant, config_entry: IPPConfigEntry) -> None:
tls=config_entry.data[CONF_SSL],
verify_ssl=config_entry.data[CONF_VERIFY_SSL],
session=async_get_clientsession(hass, config_entry.data[CONF_VERIFY_SSL]),
request_timeout=REQUEST_TIMEOUT,
)

super().__init__(
Expand Down
9 changes: 9 additions & 0 deletions homeassistant/components/lunatone/icons.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
{
"entity": {
"sensor": {
"dali_line_status": {
"default": "mdi:current-ac"
}
}
}
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [pull] dev from home-assistant:dev by pull[bot] · Pull Request #2408 · code/app-python-home-assistant-core · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
381db53
Add ventilation quickmode switches to ViCare (#179430)
lackas Aug 29, 2026
52adc20
Add Priority Status sensor to Lyric integration (#177065)
clutch2sft Aug 29, 2026
99192f5
Add serial number to Roborock devices (#180465)
ximex Aug 29, 2026
d75f497
Add Tailscale connected to control binary sensor (#179506)
AlfonsoDehesa Aug 29, 2026
b6b40e2
Include contributor reviewed 2 PRs in ha merge queue skill (#180631)
silamon Aug 29, 2026
2f50531
Scan every supported wireless interface in Mikrotik (#180636)
chemelli74 Aug 29, 2026
05c2618
Add 100% coverage for coordinator in Mikrotik (#180637)
chemelli74 Aug 29, 2026
76f77d0
Add 100% coverage to light in Midea (#180640)
chemelli74 Aug 29, 2026
8a89fa8
Give a sleeping printer time to wake up (#180616)
frenck Aug 29, 2026
6f9d552
Add DALI line status diagnostic sensor to lunatone (#179706)
MoonDevLT Aug 29, 2026
b4826e7
Add 100% coverage to coordinator in Shelly (#180644)
chemelli74 Aug 29, 2026
0313d49
Add 100% coverage to coordinator in Fritz (#180647)
chemelli74 Aug 29, 2026
74a364c
Add 100% coverage to sensor in Fritz (#180646)
chemelli74 Aug 29, 2026
8575b67
Add 100% coverage to todo in Alexa Devices (#180638)
chemelli74 Aug 29, 2026
93791ed
Add 100% coverage to binary_sensor in Midea (#180642)
chemelli74 Aug 29, 2026
6a6f930
Split the Elgato user flow init from its data (#180654)
frenck Aug 29, 2026
a1f7924
Split the Peblar user flow init from its data (#180653)
frenck Aug 29, 2026
6a1fe7c
Split the Twente Milieu user flow init from its data (#180645)
frenck Aug 29, 2026
db71607
Split the Tailwind user flow init from its data (#180648)
frenck Aug 29, 2026
e50ca95
Split the Tailscale user flow init from its data (#180649)
frenck Aug 29, 2026
959970d
Split the SolarEdge user flow init from its data (#180650)
frenck Aug 29, 2026
755a049
Split the Season user flow init from its data (#180651)
frenck Aug 29, 2026
fd790dd
Split the PVOutput user flow init from its data (#180652)
frenck Aug 29, 2026
d2d35fe
Split the Whois user flow init from its data (#180643)
frenck Aug 29, 2026
8afadfa
Split the AdGuard Home user flow init from its data (#180639)
frenck Aug 29, 2026
8fc0cc5
Split the WLED user flow init from its data (#180641)
frenck Aug 29, 2026
6d5256e
Mark Vistapool entities unavailable while the push connection is down…
fdebrus Aug 29, 2026
6eabc44
Bump google cloud dependencies (#180625)
silamon Aug 29, 2026
12fc18f
Bump probatio to 0.11.4 (#180655)
frenck Aug 29, 2026
018694c
Bump uiprotect to 16.6.1 (#180670)
RaHehl Aug 29, 2026
41dbe41
Split the Samsung SyncThru user flow init from its data (#180661)
frenck Aug 29, 2026
bf43038
Split The Things Network user flow init from its data (#180660)
frenck Aug 29, 2026
f008a3a
Split the Syncthing user flow init from its data (#180662)
frenck Aug 29, 2026
856a73f
Split the Soma user flow init from its data (#180664)
frenck Aug 29, 2026
40b951a
Split the StarLine user flow init from its data (#180663)
frenck Aug 29, 2026
7bb0412
Split the Smarla user flow init from its data (#180665)
frenck Aug 29, 2026
4b5930c
Split the SleepIQ user flow init from its data (#180666)
frenck Aug 29, 2026
57aecb2
Split the SkyBell user flow init from its data (#180674)
frenck Aug 29, 2026
7fd88d5
Split the 17TRACK user flow init from its data (#180675)
frenck Aug 29, 2026
c186313
Split the ROVA user flow init from its data (#180676)
frenck Aug 29, 2026
47fad86
Split the Slack user flow init from its data (#180673)
frenck Aug 29, 2026
a1eba84
Split the ROMY user flow init from its data (#180680)
frenck Aug 29, 2026
5c94fb9
Add battery support to SolarEdge Modbus (#180657)
frenck Aug 29, 2026
60be162
Split the Redgtech user flow init from its data (#180681)
frenck Aug 29, 2026
a9fbc0d
Add reconfigure and reauth flows for CentriConnect (#180215)
gresrun Aug 29, 2026
915d135
Split the PoolSense user flow init from its data (#180685)
frenck Aug 29, 2026
e2e687b
Split the Pterodactyl user flow init from its data (#180684)
frenck Aug 29, 2026
fddd796
Split the Pushover user flow init from its data (#180682)
frenck Aug 29, 2026
b31c625
Split the Pushbullet user flow init from its data (#180683)
frenck Aug 29, 2026
3052056
Add binary sensors to SolarEdge Modbus (#180687)
frenck Aug 29, 2026
b50835d
Add number entities to SolarEdge Modbus (#180691)
frenck Aug 29, 2026
5914747
Bump midea-local to 10.1.0 (#180694)
rokam Aug 29, 2026
e4455e9
Add state_class to UniFi device temperature sensor (#180688)
bob-laz Aug 29, 2026
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
27 changes: 21 additions & 6 deletions .claude/skills/ha-merge-queue/SKILL.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,7 +27,7 @@ verify every finalist with the per-PR checks below.

## Verify each finalist

Check all five. A PR fails the shortlist if any one fails.
Check all six conditions. A PR fails the shortlist if any of checks 1 through 5 fail.

Paginate every list response before deciding. Check runs, reviews and review threads are all
paged, typically 30 per page, and a full-suite Home Assistant PR runs to 40-odd check runs —
Expand DownExpand Up@@ -90,12 +90,27 @@ Compare the returned count against the reported total and keep fetching until th
discount one for the category it appears to fall into; an unaddressed defect is a
blocker whether or not anyone is arguing about it.

6. **Peer-Review Checklist Verification (Priority Boost)** — inspect the PR body text for
the template checkbox: `- [x] I have reviewed two other [open pull requests][prs] in this repository.`
- **Checked (`[x]`):** Give this PR higher priority in ranking to reward contributors helping
clear the review backlog.
- **Unchecked (`[ ]` or missing):** Keep in queue with standard priority (do not disqualify).

## Report

Rank by how little work each PR needs: `clean` first, then `blocked` with everything else
green. For each PR give the number as a full markdown link, the integration or core area,
one line on what it does, and its blocking state. Plenty of `home-assistant/core` PRs touch
helpers, the framework, the recorder or repo tooling and have no integration at all — name
Rank and order candidates primarily by their status readiness (`clean` first, then `blocked`
with everything else green), and **secondarily by peer-review participation**:

1. **Clean PRs** with the `[x] I have reviewed two other open pull requests...` checkbox checked.
2. **Clean PRs** without the checkbox checked.
3. **Blocked/Near-miss PRs** with the `[x] I have reviewed two other open pull requests...` checkbox checked.
4. **Blocked/Near-miss PRs** without the checkbox checked.

For each PR give the number as a full markdown link, the integration or core area,
one line on what it does, its blocking state, and explicitly note if the author checked the
peer-review box (e.g., "⭐ *Contributor reviewed 2 PRs*").

Plenty of `home-assistant/core` PRs touch helpers, the framework, the recorder or repo tooling and have no integration at all — name
what they touch instead, rather than dropping them or inventing one.

Then list the near-misses separately, each with the one action that unblocks it. The
Expand All@@ -115,4 +130,4 @@ change but carries no `breaking-change` label will silently miss the release not
- Only report in the CONSOLE. DO NOT ACT ON GITHUB — no comments, no reviews, no merges,
no pushes to contributor branches. Per `AI_POLICY.md`, a human decides and acts.
- Never call a PR ready on green CI alone. Read the diff of every PR you shortlist; CI
cannot tell you whether the change is correct or wanted.
cannot tell you whether the change is correct or wanted.
134 changes: 116 additions & 18 deletions homeassistant/components/centriconnect/config_flow.py
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
"""Config flow for the CentriConnect/MyPropane API integration."""

from collections.abc import Callable, Mapping
import logging
from typing import Any, override

Expand All@@ -11,7 +12,7 @@
CentriConnectNotFoundError,
CentriConnectTooManyRequestsError,
)
import voluptuous as vol
import probatio

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_DEVICE_ID, CONF_PASSWORD, CONF_USERNAME
Expand All@@ -22,11 +23,25 @@

_LOGGER = logging.getLogger(__name__)

STEP_USER_DATA_SCHEMA = vol.Schema(
STEP_RECONFIGURE_DATA_SCHEMA = probatio.Schema(
{
vol.Required(CONF_USERNAME): str,
vol.Required(CONF_DEVICE_ID): str,
vol.Required(CONF_PASSWORD): str,
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_PASSWORD): str,
}
)

STEP_REAUTHENTICATE_DATA_SCHEMA = probatio.Schema(
{
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_PASSWORD): str,
}
)

STEP_USER_DATA_SCHEMA = probatio.Schema(
{
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_DEVICE_ID): str,
probatio.Required(CONF_PASSWORD): str,
}
)

Expand DownExpand Up@@ -57,34 +72,117 @@ class CentriConnectConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for CentriConnect/MyPropane API."""

VERSION = 1

@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
_device_id: str | None = None

async def _handle_flow(
self,
step_id: str,
data_schema: probatio.Schema,
user_input: dict[str, Any] | None,
update_user_input: Callable[[dict[str, Any]], dict[str, Any]],
on_success: Callable[[dict[str, Any], dict[str, Any]], ConfigFlowResult],
) -> ConfigFlowResult:
"""Handle the initial step."""
"""Handle the flow for both user and reconfigure steps."""
errors: dict[str, str] = {}
if user_input is not None:
try:
info = await validate_input(self.hass, user_input)
except CentriConnectConnectionError, CentriConnectTooManyRequestsError:
info = await validate_input(self.hass, update_user_input(user_input))
except (
CentriConnectConnectionError,
CentriConnectTooManyRequestsError,
):
errors["base"] = "cannot_connect"
except CentriConnectNotFoundError:
errors["base"] = "invalid_auth"
except CentriConnectEmptyResponseError, CentriConnectDecodeError:
errors["base"] = "unknown"
except Exception:
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
await self.async_set_unique_id(
unique_id=info[CENTRICONNECT_DEVICE_ID], raise_on_progress=True
)
self._abort_if_unique_id_configured(
updates=user_input, reload_on_update=True
)
return self.async_create_entry(title=info["title"], data=user_input)
return on_success(info, user_input)

return self.async_show_form(
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
step_id=step_id, data_schema=data_schema, errors=errors
)

async def async_step_reconfigure(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle reconfiguration of the integration."""
old_entry = self._get_reconfigure_entry()

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_mismatch(reason="wrong_device")
return self.async_update_reload_and_abort(
old_entry, data_updates=user_input
)

return await self._handle_flow(
step_id="reconfigure",
data_schema=STEP_RECONFIGURE_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: {
**user_input,
CONF_DEVICE_ID: old_entry.data[CONF_DEVICE_ID],
},
on_success=_on_success,
)

async def async_step_reauth(
self, entry_data: Mapping[str, Any]
) -> ConfigFlowResult:
"""Handle configuration by re-auth."""
self._device_id = entry_data[CONF_DEVICE_ID]
return await self.async_step_reauth_confirm()

async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Perform reauthentication upon an API authentication error."""

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_mismatch(reason="wrong_device")
return self.async_update_reload_and_abort(
self._get_reauth_entry(), data_updates=user_input
)

return await self._handle_flow(
step_id="reauth_confirm",
data_schema=STEP_REAUTHENTICATE_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: {
**user_input,
CONF_DEVICE_ID: self._device_id,
},
on_success=_on_success,
)

@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the initial step."""

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_configured(
updates=user_input, reload_on_update=True
)
return self.async_create_entry(title=info["title"], data=user_input)

return await self._handle_flow(
step_id="user",
data_schema=STEP_USER_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: user_input,
on_success=_on_success,
)
4 changes: 2 additions & 2 deletions homeassistant/components/centriconnect/quality_scale.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,7 +42,7 @@ rules:
integration-owner: done
log-when-unavailable: done
parallel-updates: done
reauthentication-flow: todo
reauthentication-flow: done
test-coverage: done

# Gold
Expand DownExpand Up@@ -70,7 +70,7 @@ rules:
entity-translations: done
exception-translations: done
icon-translations: done
reconfiguration-flow: todo
reconfiguration-flow: done
repair-issues:
status: exempt
comment: No user-actionable repair scenarios identified for this integration.
Expand Down
27 changes: 26 additions & 1 deletion homeassistant/components/centriconnect/strings.json
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,39 @@
{
"config": {
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
"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%]",
"wrong_device": "This CentriConnect/MyPropane device does not match the existing device ID. Please make sure you entered the credentials correctly."
},
"error": {
"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%]"
},
"step": {
"reauth_confirm": {
"data": {
"password": "[%key:component::centriconnect::config::step::user::data::password%]",
"username": "[%key:component::centriconnect::config::step::user::data::username%]"
},
"data_description": {
"password": "[%key:component::centriconnect::config::step::user::data_description::password%]",
"username": "[%key:component::centriconnect::config::step::user::data_description::username%]"
},
"description": "[%key:component::centriconnect::config::step::user::description%]"
},
"reconfigure": {
"data": {
"password": "[%key:component::centriconnect::config::step::user::data::password%]",
"username": "[%key:component::centriconnect::config::step::user::data::username%]"
},
"data_description": {
"password": "[%key:component::centriconnect::config::step::user::data_description::password%]",
"username": "[%key:component::centriconnect::config::step::user::data_description::username%]"
},
"description": "[%key:component::centriconnect::config::step::user::description%]"
},
"user": {
"data": {
"device_id": "Device ID",
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/google_cloud/manifest.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@
"integration_type": "service",
"iot_class": "cloud_push",
"requirements": [
"google-cloud-texttospeech==2.25.1",
"google-cloud-speech==2.31.1"
"google-cloud-texttospeech==2.37.0",
"google-cloud-speech==2.40.0"
]
}
3 changes: 2 additions & 1 deletion homeassistant/components/ipp/config_flow.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,7 +27,7 @@
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo

from .const import CONF_BASE_PATH, CONF_SERIAL, DOMAIN
from .const import CONF_BASE_PATH, CONF_SERIAL, DOMAIN, REQUEST_TIMEOUT

_LOGGER = logging.getLogger(__name__)

Expand All@@ -45,6 +45,7 @@ async def validate_input(hass: HomeAssistant, data: dict) -> dict[str, Any]:
tls=data[CONF_SSL],
verify_ssl=data[CONF_VERIFY_SSL],
session=session,
request_timeout=REQUEST_TIMEOUT,
)

printer = await ipp.printer()
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/ipp/const.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,6 +14,9 @@
ATTR_STATE_REASON = "state_reason"
ATTR_URI_SUPPORTED = "uri_supported"

# Printers waking from sleep can take well over pyipp's own default
REQUEST_TIMEOUT = 30

# Config Keys
CONF_BASE_PATH = "base_path"
CONF_SERIAL = "serial"
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/ipp/coordinator.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,7 +12,7 @@
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import CONF_BASE_PATH, DOMAIN
from .const import CONF_BASE_PATH, DOMAIN, REQUEST_TIMEOUT

SCAN_INTERVAL = timedelta(seconds=60)

Expand All@@ -36,6 +36,7 @@ def __init__(self, hass: HomeAssistant, config_entry: IPPConfigEntry) -> None:
tls=config_entry.data[CONF_SSL],
verify_ssl=config_entry.data[CONF_VERIFY_SSL],
session=async_get_clientsession(hass, config_entry.data[CONF_VERIFY_SSL]),
request_timeout=REQUEST_TIMEOUT,
)

super().__init__(
Expand Down
9 changes: 9 additions & 0 deletions homeassistant/components/lunatone/icons.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
{
"entity": {
"sensor": {
"dali_line_status": {
"default": "mdi:current-ac"
}
}
}
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); [pull] dev from home-assistant:dev by pull[bot] · Pull Request #2408 · code/app-python-home-assistant-core · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
381db53
Add ventilation quickmode switches to ViCare (#179430)
lackas Aug 29, 2026
52adc20
Add Priority Status sensor to Lyric integration (#177065)
clutch2sft Aug 29, 2026
99192f5
Add serial number to Roborock devices (#180465)
ximex Aug 29, 2026
d75f497
Add Tailscale connected to control binary sensor (#179506)
AlfonsoDehesa Aug 29, 2026
b6b40e2
Include contributor reviewed 2 PRs in ha merge queue skill (#180631)
silamon Aug 29, 2026
2f50531
Scan every supported wireless interface in Mikrotik (#180636)
chemelli74 Aug 29, 2026
05c2618
Add 100% coverage for coordinator in Mikrotik (#180637)
chemelli74 Aug 29, 2026
76f77d0
Add 100% coverage to light in Midea (#180640)
chemelli74 Aug 29, 2026
8a89fa8
Give a sleeping printer time to wake up (#180616)
frenck Aug 29, 2026
6f9d552
Add DALI line status diagnostic sensor to lunatone (#179706)
MoonDevLT Aug 29, 2026
b4826e7
Add 100% coverage to coordinator in Shelly (#180644)
chemelli74 Aug 29, 2026
0313d49
Add 100% coverage to coordinator in Fritz (#180647)
chemelli74 Aug 29, 2026
74a364c
Add 100% coverage to sensor in Fritz (#180646)
chemelli74 Aug 29, 2026
8575b67
Add 100% coverage to todo in Alexa Devices (#180638)
chemelli74 Aug 29, 2026
93791ed
Add 100% coverage to binary_sensor in Midea (#180642)
chemelli74 Aug 29, 2026
6a6f930
Split the Elgato user flow init from its data (#180654)
frenck Aug 29, 2026
a1f7924
Split the Peblar user flow init from its data (#180653)
frenck Aug 29, 2026
6a1fe7c
Split the Twente Milieu user flow init from its data (#180645)
frenck Aug 29, 2026
db71607
Split the Tailwind user flow init from its data (#180648)
frenck Aug 29, 2026
e50ca95
Split the Tailscale user flow init from its data (#180649)
frenck Aug 29, 2026
959970d
Split the SolarEdge user flow init from its data (#180650)
frenck Aug 29, 2026
755a049
Split the Season user flow init from its data (#180651)
frenck Aug 29, 2026
fd790dd
Split the PVOutput user flow init from its data (#180652)
frenck Aug 29, 2026
d2d35fe
Split the Whois user flow init from its data (#180643)
frenck Aug 29, 2026
8afadfa
Split the AdGuard Home user flow init from its data (#180639)
frenck Aug 29, 2026
8fc0cc5
Split the WLED user flow init from its data (#180641)
frenck Aug 29, 2026
6d5256e
Mark Vistapool entities unavailable while the push connection is down…
fdebrus Aug 29, 2026
6eabc44
Bump google cloud dependencies (#180625)
silamon Aug 29, 2026
12fc18f
Bump probatio to 0.11.4 (#180655)
frenck Aug 29, 2026
018694c
Bump uiprotect to 16.6.1 (#180670)
RaHehl Aug 29, 2026
41dbe41
Split the Samsung SyncThru user flow init from its data (#180661)
frenck Aug 29, 2026
bf43038
Split The Things Network user flow init from its data (#180660)
frenck Aug 29, 2026
f008a3a
Split the Syncthing user flow init from its data (#180662)
frenck Aug 29, 2026
856a73f
Split the Soma user flow init from its data (#180664)
frenck Aug 29, 2026
40b951a
Split the StarLine user flow init from its data (#180663)
frenck Aug 29, 2026
7bb0412
Split the Smarla user flow init from its data (#180665)
frenck Aug 29, 2026
4b5930c
Split the SleepIQ user flow init from its data (#180666)
frenck Aug 29, 2026
57aecb2
Split the SkyBell user flow init from its data (#180674)
frenck Aug 29, 2026
7fd88d5
Split the 17TRACK user flow init from its data (#180675)
frenck Aug 29, 2026
c186313
Split the ROVA user flow init from its data (#180676)
frenck Aug 29, 2026
47fad86
Split the Slack user flow init from its data (#180673)
frenck Aug 29, 2026
a1eba84
Split the ROMY user flow init from its data (#180680)
frenck Aug 29, 2026
5c94fb9
Add battery support to SolarEdge Modbus (#180657)
frenck Aug 29, 2026
60be162
Split the Redgtech user flow init from its data (#180681)
frenck Aug 29, 2026
a9fbc0d
Add reconfigure and reauth flows for CentriConnect (#180215)
gresrun Aug 29, 2026
915d135
Split the PoolSense user flow init from its data (#180685)
frenck Aug 29, 2026
e2e687b
Split the Pterodactyl user flow init from its data (#180684)
frenck Aug 29, 2026
fddd796
Split the Pushover user flow init from its data (#180682)
frenck Aug 29, 2026
b31c625
Split the Pushbullet user flow init from its data (#180683)
frenck Aug 29, 2026
3052056
Add binary sensors to SolarEdge Modbus (#180687)
frenck Aug 29, 2026
b50835d
Add number entities to SolarEdge Modbus (#180691)
frenck Aug 29, 2026
5914747
Bump midea-local to 10.1.0 (#180694)
rokam Aug 29, 2026
e4455e9
Add state_class to UniFi device temperature sensor (#180688)
bob-laz Aug 29, 2026
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
27 changes: 21 additions & 6 deletions .claude/skills/ha-merge-queue/SKILL.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,7 +27,7 @@ verify every finalist with the per-PR checks below.

## Verify each finalist

Check all five. A PR fails the shortlist if any one fails.
Check all six conditions. A PR fails the shortlist if any of checks 1 through 5 fail.

Paginate every list response before deciding. Check runs, reviews and review threads are all
paged, typically 30 per page, and a full-suite Home Assistant PR runs to 40-odd check runs —
Expand DownExpand Up@@ -90,12 +90,27 @@ Compare the returned count against the reported total and keep fetching until th
discount one for the category it appears to fall into; an unaddressed defect is a
blocker whether or not anyone is arguing about it.

6. **Peer-Review Checklist Verification (Priority Boost)** — inspect the PR body text for
the template checkbox: `- [x] I have reviewed two other [open pull requests][prs] in this repository.`
- **Checked (`[x]`):** Give this PR higher priority in ranking to reward contributors helping
clear the review backlog.
- **Unchecked (`[ ]` or missing):** Keep in queue with standard priority (do not disqualify).

## Report

Rank by how little work each PR needs: `clean` first, then `blocked` with everything else
green. For each PR give the number as a full markdown link, the integration or core area,
one line on what it does, and its blocking state. Plenty of `home-assistant/core` PRs touch
helpers, the framework, the recorder or repo tooling and have no integration at all — name
Rank and order candidates primarily by their status readiness (`clean` first, then `blocked`
with everything else green), and **secondarily by peer-review participation**:

1. **Clean PRs** with the `[x] I have reviewed two other open pull requests...` checkbox checked.
2. **Clean PRs** without the checkbox checked.
3. **Blocked/Near-miss PRs** with the `[x] I have reviewed two other open pull requests...` checkbox checked.
4. **Blocked/Near-miss PRs** without the checkbox checked.

For each PR give the number as a full markdown link, the integration or core area,
one line on what it does, its blocking state, and explicitly note if the author checked the
peer-review box (e.g., "⭐ *Contributor reviewed 2 PRs*").

Plenty of `home-assistant/core` PRs touch helpers, the framework, the recorder or repo tooling and have no integration at all — name
what they touch instead, rather than dropping them or inventing one.

Then list the near-misses separately, each with the one action that unblocks it. The
Expand All@@ -115,4 +130,4 @@ change but carries no `breaking-change` label will silently miss the release not
- Only report in the CONSOLE. DO NOT ACT ON GITHUB — no comments, no reviews, no merges,
no pushes to contributor branches. Per `AI_POLICY.md`, a human decides and acts.
- Never call a PR ready on green CI alone. Read the diff of every PR you shortlist; CI
cannot tell you whether the change is correct or wanted.
cannot tell you whether the change is correct or wanted.
134 changes: 116 additions & 18 deletions homeassistant/components/centriconnect/config_flow.py
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
"""Config flow for the CentriConnect/MyPropane API integration."""

from collections.abc import Callable, Mapping
import logging
from typing import Any, override

Expand All@@ -11,7 +12,7 @@
CentriConnectNotFoundError,
CentriConnectTooManyRequestsError,
)
import voluptuous as vol
import probatio

from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_DEVICE_ID, CONF_PASSWORD, CONF_USERNAME
Expand All@@ -22,11 +23,25 @@

_LOGGER = logging.getLogger(__name__)

STEP_USER_DATA_SCHEMA = vol.Schema(
STEP_RECONFIGURE_DATA_SCHEMA = probatio.Schema(
{
vol.Required(CONF_USERNAME): str,
vol.Required(CONF_DEVICE_ID): str,
vol.Required(CONF_PASSWORD): str,
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_PASSWORD): str,
}
)

STEP_REAUTHENTICATE_DATA_SCHEMA = probatio.Schema(
{
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_PASSWORD): str,
}
)

STEP_USER_DATA_SCHEMA = probatio.Schema(
{
probatio.Required(CONF_USERNAME): str,
probatio.Required(CONF_DEVICE_ID): str,
probatio.Required(CONF_PASSWORD): str,
}
)

Expand DownExpand Up@@ -57,34 +72,117 @@ class CentriConnectConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for CentriConnect/MyPropane API."""

VERSION = 1

@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
_device_id: str | None = None

async def _handle_flow(
self,
step_id: str,
data_schema: probatio.Schema,
user_input: dict[str, Any] | None,
update_user_input: Callable[[dict[str, Any]], dict[str, Any]],
on_success: Callable[[dict[str, Any], dict[str, Any]], ConfigFlowResult],
) -> ConfigFlowResult:
"""Handle the initial step."""
"""Handle the flow for both user and reconfigure steps."""
errors: dict[str, str] = {}
if user_input is not None:
try:
info = await validate_input(self.hass, user_input)
except CentriConnectConnectionError, CentriConnectTooManyRequestsError:
info = await validate_input(self.hass, update_user_input(user_input))
except (
CentriConnectConnectionError,
CentriConnectTooManyRequestsError,
):
errors["base"] = "cannot_connect"
except CentriConnectNotFoundError:
errors["base"] = "invalid_auth"
except CentriConnectEmptyResponseError, CentriConnectDecodeError:
errors["base"] = "unknown"
except Exception:
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
else:
await self.async_set_unique_id(
unique_id=info[CENTRICONNECT_DEVICE_ID], raise_on_progress=True
)
self._abort_if_unique_id_configured(
updates=user_input, reload_on_update=True
)
return self.async_create_entry(title=info["title"], data=user_input)
return on_success(info, user_input)

return self.async_show_form(
step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors
step_id=step_id, data_schema=data_schema, errors=errors
)

async def async_step_reconfigure(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle reconfiguration of the integration."""
old_entry = self._get_reconfigure_entry()

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_mismatch(reason="wrong_device")
return self.async_update_reload_and_abort(
old_entry, data_updates=user_input
)

return await self._handle_flow(
step_id="reconfigure",
data_schema=STEP_RECONFIGURE_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: {
**user_input,
CONF_DEVICE_ID: old_entry.data[CONF_DEVICE_ID],
},
on_success=_on_success,
)

async def async_step_reauth(
self, entry_data: Mapping[str, Any]
) -> ConfigFlowResult:
"""Handle configuration by re-auth."""
self._device_id = entry_data[CONF_DEVICE_ID]
return await self.async_step_reauth_confirm()

async def async_step_reauth_confirm(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Perform reauthentication upon an API authentication error."""

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_mismatch(reason="wrong_device")
return self.async_update_reload_and_abort(
self._get_reauth_entry(), data_updates=user_input
)

return await self._handle_flow(
step_id="reauth_confirm",
data_schema=STEP_REAUTHENTICATE_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: {
**user_input,
CONF_DEVICE_ID: self._device_id,
},
on_success=_on_success,
)

@override
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Handle the initial step."""

def _on_success(
info: dict[str, Any], user_input: dict[str, Any]
) -> ConfigFlowResult:
self._abort_if_unique_id_configured(
updates=user_input, reload_on_update=True
)
return self.async_create_entry(title=info["title"], data=user_input)

return await self._handle_flow(
step_id="user",
data_schema=STEP_USER_DATA_SCHEMA,
user_input=user_input,
update_user_input=lambda user_input: user_input,
on_success=_on_success,
)
4 changes: 2 additions & 2 deletions homeassistant/components/centriconnect/quality_scale.yaml
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,7 +42,7 @@ rules:
integration-owner: done
log-when-unavailable: done
parallel-updates: done
reauthentication-flow: todo
reauthentication-flow: done
test-coverage: done

# Gold
Expand DownExpand Up@@ -70,7 +70,7 @@ rules:
entity-translations: done
exception-translations: done
icon-translations: done
reconfiguration-flow: todo
reconfiguration-flow: done
repair-issues:
status: exempt
comment: No user-actionable repair scenarios identified for this integration.
Expand Down
27 changes: 26 additions & 1 deletion homeassistant/components/centriconnect/strings.json
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,39 @@
{
"config": {
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
"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%]",
"wrong_device": "This CentriConnect/MyPropane device does not match the existing device ID. Please make sure you entered the credentials correctly."
},
"error": {
"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%]"
},
"step": {
"reauth_confirm": {
"data": {
"password": "[%key:component::centriconnect::config::step::user::data::password%]",
"username": "[%key:component::centriconnect::config::step::user::data::username%]"
},
"data_description": {
"password": "[%key:component::centriconnect::config::step::user::data_description::password%]",
"username": "[%key:component::centriconnect::config::step::user::data_description::username%]"
},
"description": "[%key:component::centriconnect::config::step::user::description%]"
},
"reconfigure": {
"data": {
"password": "[%key:component::centriconnect::config::step::user::data::password%]",
"username": "[%key:component::centriconnect::config::step::user::data::username%]"
},
"data_description": {
"password": "[%key:component::centriconnect::config::step::user::data_description::password%]",
"username": "[%key:component::centriconnect::config::step::user::data_description::username%]"
},
"description": "[%key:component::centriconnect::config::step::user::description%]"
},
"user": {
"data": {
"device_id": "Device ID",
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/google_cloud/manifest.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@
"integration_type": "service",
"iot_class": "cloud_push",
"requirements": [
"google-cloud-texttospeech==2.25.1",
"google-cloud-speech==2.31.1"
"google-cloud-texttospeech==2.37.0",
"google-cloud-speech==2.40.0"
]
}
3 changes: 2 additions & 1 deletion homeassistant/components/ipp/config_flow.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,7 +27,7 @@
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.service_info.zeroconf import ZeroconfServiceInfo

from .const import CONF_BASE_PATH, CONF_SERIAL, DOMAIN
from .const import CONF_BASE_PATH, CONF_SERIAL, DOMAIN, REQUEST_TIMEOUT

_LOGGER = logging.getLogger(__name__)

Expand All@@ -45,6 +45,7 @@ async def validate_input(hass: HomeAssistant, data: dict) -> dict[str, Any]:
tls=data[CONF_SSL],
verify_ssl=data[CONF_VERIFY_SSL],
session=session,
request_timeout=REQUEST_TIMEOUT,
)

printer = await ipp.printer()
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/ipp/const.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,6 +14,9 @@
ATTR_STATE_REASON = "state_reason"
ATTR_URI_SUPPORTED = "uri_supported"

# Printers waking from sleep can take well over pyipp's own default
REQUEST_TIMEOUT = 30

# Config Keys
CONF_BASE_PATH = "base_path"
CONF_SERIAL = "serial"
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/ipp/coordinator.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,7 +12,7 @@
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import CONF_BASE_PATH, DOMAIN
from .const import CONF_BASE_PATH, DOMAIN, REQUEST_TIMEOUT

SCAN_INTERVAL = timedelta(seconds=60)

Expand All@@ -36,6 +36,7 @@ def __init__(self, hass: HomeAssistant, config_entry: IPPConfigEntry) -> None:
tls=config_entry.data[CONF_SSL],
verify_ssl=config_entry.data[CONF_VERIFY_SSL],
session=async_get_clientsession(hass, config_entry.data[CONF_VERIFY_SSL]),
request_timeout=REQUEST_TIMEOUT,
)

super().__init__(
Expand Down
9 changes: 9 additions & 0 deletions homeassistant/components/lunatone/icons.json
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
{
"entity": {
"sensor": {
"dali_line_status": {
"default": "mdi:current-ac"
}
}
}
}
Loading
Loading