Skip to content

Commit 7348241

Browse files
authored
Merge branch 'dev' into fluss/button-connectivity-availability
2 parents 50a8c72 + 77bd6a7 commit 7348241

7,562 files changed

Lines changed: 23870 additions & 20606 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/ha-integration-knowledge/SKILL.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@ description: Everything you need to know to build, test and review Home Assistan
1515
- For entity actions and entity services, avoid requesting redundant defensive checks for fields already enforced by Home Assistant validation schemas and entity filters; only request extra guards when values bypass validation or are transformed unsafely.
1616
- When validation guarantees a key is present, prefer direct dictionary indexing (`data["key"]`) over `.get("key")` so invalid assumptions fail fast.
1717
- Integrations should be thin wrappers. Protocol parsing, device state machines, or other domain logic belong in a separate PyPI library, not in the integration itself. If unsure, ask before inlining.
18-
- "potato" is a forbidden word for an integration and should never be used.
18+
- Integrations should not implement fixes or workarounds for limitations in libraries. Instead, the library should be updated to fix the issue.
1919

2020
The following platforms have extra guidelines:
2121
- **Diagnostics**: [`platform-diagnostics.md`](platform-diagnostics.md) for diagnostic data collection
2222
- **Repairs**: [`platform-repairs.md`](platform-repairs.md) for user-actionable repair issues
2323

24+
## Entity platforms
25+
26+
- Ensure `async_added_to_hass()` and `async_will_remove_from_hass()` have symmetrical behavior. For example, if a subscription is created in `async_added_to_hass()`, it should be unsubscribed in `async_will_remove_from_hass()`. Also, if something is torn down in `async_will_remove_from_hass()`, it should be set up in `async_added_to_hass()`.
2427

2528
## Integration Quality Scale
2629

.github/copilot-instructions.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
# Copilot code review instructions
66

77
- Start review comments with a short, one-sentence summary of the suggested fix.
8-
- Do not add comments about code style, formatting or linting issues.
8+
- Do not comment on code style, formatting or linting issues.
9+
- A Pull Request with a dependency version bump should only contain changes required for the version bump. If the PR includes other changes, request that they are removed from the PR.
910

1011
# GitHub Copilot & Claude Code Instructions
1112

@@ -21,21 +22,20 @@ This repository contains the core of Home Assistant, a Python 3 based home autom
2122

2223
## Python Syntax Notes
2324

24-
- Python 3.14 explicitly allows `except TypeA, TypeB:` without parentheses. Never flag this as an issue since Home Assistant officially supports Python 3.14.
25+
- Home Assistant officially supports Python 3.14 as its minimum version. Do not flag syntax or features that require Python 3.14 as issues, and do not suggest workarounds for older Python versions.
26+
- Python 3.14 explicitly allows `except TypeA, TypeB:` without parentheses. Never flag this as an issue.
27+
- Python 3.14 evaluates annotations lazily (PEP 649). Forward references in annotations do not need to be quoted — annotations can reference names defined later in the module without quoting them or using `from __future__ import annotations`. Do not flag unquoted forward references in annotations as issues.
2528

2629
## Testing
2730

28-
When writing or modifying tests, ensure all test function parameters have type annotations.
29-
Prefer concrete types (for example, `HomeAssistant`, `MockConfigEntry`, etc.) over `Any`.
31+
- When writing or modifying tests, ensure all test function parameters have type annotations.
32+
- Prefer concrete types (for example, `HomeAssistant`, `MockConfigEntry`, etc.) over `Any`.
33+
- Avoid using conditions/branching in tests. Instead, either split tests or adjust the test parametrization to cover all cases without branching.
34+
- If multiple tests share most of their code, use `pytest.mark.parametrize` to merge them into a single parameterized test instead of duplicating the body.
3035

3136
## Good practices
3237

33-
Integrations with Platinum or Gold level in the Integration Quality Scale reflect a high standard of code quality and maintainability. When looking for examples of something, these are good places to start. The level is indicated in the manifest.json of the integration.
34-
35-
When reviewing entity actions, do not suggest extra defensive checks for input fields that are already validated by Home Assistant's service/action schemas and entity selection filters. Suggest additional guards only when data bypasses those validators or is transformed into a less-safe form.
36-
When validation guarantees a dict key exists, prefer direct key access (`data["key"]`) instead of `.get("key")` so contract violations are surfaced instead of silently masked.
37-
38-
39-
# Skills
40-
41-
- ha-integration-knowledge: .claude/skills/ha-integration-knowledge/SKILL.md
38+
- Integrations with Platinum or Gold level in the Integration Quality Scale reflect a high standard of code quality and maintainability. When looking for examples of something, these are good places to start. The level is indicated in the manifest.json of the integration.
39+
- When reviewing entity actions, do not suggest extra defensive checks for input fields that are already validated by Home Assistant's service/action schemas and entity selection filters. Suggest additional guards only when data bypasses those validators or is transformed into a less-safe form.
40+
- When validation guarantees a dict key exists, prefer direct key access (`data["key"]`) instead of `.get("key")` so contract violations are surfaced instead of silently masked.
41+
- Do not add comments that just restate the code on the following line(s) (e.g. `# Check if initialized` above `if self.initialized:`). Comments should only explain why — non-obvious constraints, surprising behavior, or workarounds — never what.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
applyTo: "homeassistant/components/**, tests/components/**"
3+
excludeAgent: "cloud-agent"
4+
---
5+
6+
<!-- Automatically generated by gen_copilot_instructions.py, do not edit -->
7+
8+
9+
## File Locations
10+
- **Integration code**: `./homeassistant/components/<integration_domain>/`
11+
- **Integration tests**: `./tests/components/<integration_domain>/`
12+
13+
## General guidelines
14+
15+
- When looking for examples, prefer integrations with the platinum or gold quality scale level first.
16+
- Polling intervals are NOT user-configurable. Never add scan_interval, update_interval, or polling frequency options to config flows or config entries.
17+
- Do NOT allow users to set config entry names in config flows. Names are automatically generated or can be customized later in UI. Exception: helper integrations may allow custom names.
18+
- For entity actions and entity services, avoid requesting redundant defensive checks for fields already enforced by Home Assistant validation schemas and entity filters; only request extra guards when values bypass validation or are transformed unsafely.
19+
- When validation guarantees a key is present, prefer direct dictionary indexing (`data["key"]`) over `.get("key")` so invalid assumptions fail fast.
20+
- Integrations should be thin wrappers. Protocol parsing, device state machines, or other domain logic belong in a separate PyPI library, not in the integration itself. If unsure, ask before inlining.
21+
- Integrations should not implement fixes or workarounds for limitations in libraries. Instead, the library should be updated to fix the issue.
22+
23+
The following platforms have extra guidelines:
24+
- **Diagnostics**: [`platform-diagnostics.md`](platform-diagnostics.md) for diagnostic data collection
25+
- **Repairs**: [`platform-repairs.md`](platform-repairs.md) for user-actionable repair issues
26+
27+
## Entity platforms
28+
29+
- Ensure `async_added_to_hass()` and `async_will_remove_from_hass()` have symmetrical behavior. For example, if a subscription is created in `async_added_to_hass()`, it should be unsubscribed in `async_will_remove_from_hass()`. Also, if something is torn down in `async_will_remove_from_hass()`, it should be set up in `async_added_to_hass()`.
30+
31+
## Integration Quality Scale
32+
33+
- When validating the quality scale rules, check them at https://developers.home-assistant.io/docs/core/integration-quality-scale/rules
34+
- When implementing or reviewing an integration, always consider the quality scale rules, since they promote best practices.
35+
36+
Template scale file: `./script/scaffold/templates/integration/integration/quality_scale.yaml`
37+
38+
### How Rules Apply
39+
1. **Check `manifest.json`**: Look for `"quality_scale"` key to determine integration level
40+
2. **Bronze Rules**: Always required for any integration with quality scale
41+
3. **Higher Tier Rules**: Only apply if integration targets that tier or higher
42+
4. **Rule Status**: Check `quality_scale.yaml` in integration folder for:
43+
- `done`: Rule implemented
44+
- `exempt`: Rule doesn't apply (with reason in comment)
45+
- `todo`: Rule needs implementation
46+
47+
48+
## Testing Requirements
49+
50+
- Tests should avoid interacting or mocking internal integration details. For more info, see https://developers.home-assistant.io/docs/development_testing/#writing-tests-for-integrations

.github/renovate.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"pep621",
77
"pip_requirements",
88
"pre-commit",
9-
"regex",
9+
"custom.regex",
1010
"homeassistant-manifest"
1111
],
1212

@@ -27,8 +27,9 @@
2727
]
2828
},
2929

30-
"regexManagers": [
30+
"customManagers": [
3131
{
32+
"customType": "regex",
3233
"description": "Update ruff required-version in pyproject.toml",
3334
"managerFilePatterns": ["/^pyproject\\.toml$/"],
3435
"matchStrings": ["required-version = \">=(?<currentValue>[\\d.]+)\""],

.github/workflows/builder.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ env:
1414
UV_HTTP_TIMEOUT: 60
1515
UV_SYSTEM_PYTHON: "true"
1616
# Base image version from https://github.com/home-assistant/docker
17-
BASE_IMAGE_VERSION: "2026.01.0"
17+
BASE_IMAGE_VERSION: "2026.04.0"
1818
ARCHITECTURES: '["amd64", "aarch64"]'
1919

2020
permissions: {}

.github/workflows/ci.yaml

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,8 @@ on:
3838

3939
env:
4040
CACHE_VERSION: 3
41-
UV_CACHE_VERSION: 1
4241
MYPY_CACHE_VERSION: 1
43-
HA_SHORT_VERSION: "2026.5"
42+
HA_SHORT_VERSION: "2026.6"
4443
ADDITIONAL_PYTHON_VERSIONS: "[]"
4544
# 10.3 is the oldest supported version
4645
# - 10.3.32 is the version currently shipped with Synology (as of 17 Feb 2022)
@@ -358,32 +357,33 @@ jobs:
358357
with:
359358
python-version: ${{ matrix.python-version }}
360359
check-latest: true
361-
- name: Generate partial uv restore key
362-
id: generate-uv-key
363-
run: |
364-
uv_version=$(cat requirements.txt | grep uv | cut -d '=' -f 3)
365-
echo "version=${uv_version}" >> $GITHUB_OUTPUT
366-
echo "key=uv-${UV_CACHE_VERSION}-${uv_version}-${HA_SHORT_VERSION}-$(date -u '+%Y-%m-%dT%H:%M:%s')" >> $GITHUB_OUTPUT
367360
- name: Restore base Python virtual environment
368361
id: cache-venv
369-
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
362+
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
370363
with:
371364
path: venv
372365
key: >-
373366
${{ runner.os }}-${{ runner.arch }}-${{ steps.python.outputs.python-version }}-${{
374367
needs.info.outputs.python_cache_key }}
368+
- name: Generate partial uv restore key
369+
if: steps.cache-venv.outputs.cache-hit != 'true'
370+
id: generate-uv-key
371+
env:
372+
RUNNER_OS: ${{ runner.os }}
373+
RUNNER_ARCH: ${{ runner.arch }}
374+
PYTHON_VERSION: ${{ steps.python.outputs.python-version }}
375+
HASH_FILES: ${{ hashFiles('requirements.txt', 'requirements_all.txt', 'requirements_test.txt', 'homeassistant/package_constraints.txt') }}
376+
run: |
377+
partial_key="${RUNNER_OS}-${RUNNER_ARCH}-${PYTHON_VERSION}-uv-"
378+
echo "partial_key=${partial_key}" >> $GITHUB_OUTPUT
379+
echo "full_key=${partial_key}${HASH_FILES}" >> $GITHUB_OUTPUT
375380
- name: Restore uv wheel cache
376381
if: steps.cache-venv.outputs.cache-hit != 'true'
377-
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
382+
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
378383
with:
379384
path: ${{ env.UV_CACHE_DIR }}
380-
key: >-
381-
${{ runner.os }}-${{ runner.arch }}-${{ steps.python.outputs.python-version }}-${{
382-
steps.generate-uv-key.outputs.key }}
383-
restore-keys: |
384-
${{ runner.os }}-${{ runner.arch }}-${{ steps.python.outputs.python-version }}-uv-${{
385-
env.UV_CACHE_VERSION }}-${{ steps.generate-uv-key.outputs.version }}-${{
386-
env.HA_SHORT_VERSION }}-
385+
key: ${{ steps.generate-uv-key.outputs.full_key }}
386+
restore-keys: ${{ steps.generate-uv-key.outputs.partial_key }}
387387
- name: Check if apt cache exists
388388
id: cache-apt-check
389389
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
@@ -398,6 +398,7 @@ jobs:
398398
if: |
399399
steps.cache-venv.outputs.cache-hit != 'true'
400400
|| steps.cache-apt-check.outputs.cache-hit != 'true'
401+
id: install-os-deps
401402
timeout-minutes: 10
402403
env:
403404
APT_CACHE_HIT: ${{ steps.cache-apt-check.outputs.cache-hit }}
@@ -431,7 +432,10 @@ jobs:
431432
sudo chmod -R 755 ${APT_CACHE_BASE}
432433
fi
433434
- name: Save apt cache
434-
if: steps.cache-apt-check.outputs.cache-hit != 'true'
435+
if: |
436+
always()
437+
&& steps.cache-apt-check.outputs.cache-hit != 'true'
438+
&& steps.install-os-deps.outcome == 'success'
435439
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
436440
with:
437441
path: |
@@ -441,15 +445,15 @@ jobs:
441445
${{ runner.os }}-${{ runner.arch }}-${{ needs.info.outputs.apt_cache_key }}
442446
- name: Create Python virtual environment
443447
if: steps.cache-venv.outputs.cache-hit != 'true'
448+
id: create-venv
444449
run: |
445450
python -m venv venv
446451
. venv/bin/activate
447452
python --version
448453
pip install "$(grep '^uv' < requirements.txt)"
449454
uv pip install -U "pip>=25.2"
450455
uv pip install -r requirements.txt
451-
python -m script.gen_requirements_all ci
452-
uv pip install -r requirements_all_pytest.txt -r requirements_test.txt
456+
uv pip install -r requirements_all.txt -r requirements_test.txt
453457
uv pip install -e . --config-settings editable_mode=compat
454458
- name: Dump pip freeze
455459
run: |
@@ -465,12 +469,29 @@ jobs:
465469
overwrite: true
466470
- name: Remove pip_freeze
467471
run: rm pip_freeze.txt
468-
- name: Remove generated requirements_all
469-
if: steps.cache-venv.outputs.cache-hit != 'true'
470-
run: rm requirements_all_pytest.txt requirements_all_wheels_*.txt
471472
- name: Check dirty
472473
run: |
473474
./script/check_dirty
475+
- name: Prune uv cache
476+
if: steps.cache-venv.outputs.cache-hit != 'true'
477+
id: prune-uv-cache
478+
run: |
479+
. venv/bin/activate
480+
uv cache prune --ci
481+
- name: Save uv wheel cache
482+
if: steps.cache-venv.outputs.cache-hit != 'true'
483+
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
484+
with:
485+
path: ${{ env.UV_CACHE_DIR }}
486+
key: ${{ steps.generate-uv-key.outputs.full_key }}
487+
- name: Save base Python virtual environment
488+
if: always() && steps.create-venv.outcome == 'success'
489+
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
490+
with:
491+
path: venv
492+
key: >-
493+
${{ runner.os }}-${{ runner.arch }}-${{ steps.python.outputs.python-version }}-${{
494+
needs.info.outputs.python_cache_key }}
474495
475496
hassfest:
476497
name: Check hassfest

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/astral-sh/ruff-pre-commit
3-
rev: v0.15.10
3+
rev: v0.15.12
44
hooks:
55
- id: ruff-check
66
args:

.python-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.14.2
1+
3.14.4

AGENTS.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,20 @@ This repository contains the core of Home Assistant, a Python 3 based home autom
1212

1313
## Python Syntax Notes
1414

15-
- Python 3.14 explicitly allows `except TypeA, TypeB:` without parentheses. Never flag this as an issue since Home Assistant officially supports Python 3.14.
15+
- Home Assistant officially supports Python 3.14 as its minimum version. Do not flag syntax or features that require Python 3.14 as issues, and do not suggest workarounds for older Python versions.
16+
- Python 3.14 explicitly allows `except TypeA, TypeB:` without parentheses. Never flag this as an issue.
17+
- Python 3.14 evaluates annotations lazily (PEP 649). Forward references in annotations do not need to be quoted — annotations can reference names defined later in the module without quoting them or using `from __future__ import annotations`. Do not flag unquoted forward references in annotations as issues.
1618

1719
## Testing
1820

19-
When writing or modifying tests, ensure all test function parameters have type annotations.
20-
Prefer concrete types (for example, `HomeAssistant`, `MockConfigEntry`, etc.) over `Any`.
21+
- When writing or modifying tests, ensure all test function parameters have type annotations.
22+
- Prefer concrete types (for example, `HomeAssistant`, `MockConfigEntry`, etc.) over `Any`.
23+
- Avoid using conditions/branching in tests. Instead, either split tests or adjust the test parametrization to cover all cases without branching.
24+
- If multiple tests share most of their code, use `pytest.mark.parametrize` to merge them into a single parameterized test instead of duplicating the body.
2125

2226
## Good practices
2327

24-
Integrations with Platinum or Gold level in the Integration Quality Scale reflect a high standard of code quality and maintainability. When looking for examples of something, these are good places to start. The level is indicated in the manifest.json of the integration.
25-
26-
When reviewing entity actions, do not suggest extra defensive checks for input fields that are already validated by Home Assistant's service/action schemas and entity selection filters. Suggest additional guards only when data bypasses those validators or is transformed into a less-safe form.
27-
When validation guarantees a dict key exists, prefer direct key access (`data["key"]`) instead of `.get("key")` so contract violations are surfaced instead of silently masked.
28+
- Integrations with Platinum or Gold level in the Integration Quality Scale reflect a high standard of code quality and maintainability. When looking for examples of something, these are good places to start. The level is indicated in the manifest.json of the integration.
29+
- When reviewing entity actions, do not suggest extra defensive checks for input fields that are already validated by Home Assistant's service/action schemas and entity selection filters. Suggest additional guards only when data bypasses those validators or is transformed into a less-safe form.
30+
- When validation guarantees a dict key exists, prefer direct key access (`data["key"]`) instead of `.get("key")` so contract violations are surfaced instead of silently masked.
31+
- Do not add comments that just restate the code on the following line(s) (e.g. `# Check if initialized` above `if self.initialized:`). Comments should only explain why — non-obvious constraints, surprising behavior, or workarounds — never what.

CODEOWNERS

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)