mirror of
https://github.com/esphome/esphome.git
synced 2026-06-24 13:45:15 +00:00
Merge branch 'dev' into jesserockz-2026-331
This commit is contained in:
@@ -1 +0,0 @@
|
|||||||
442b8197be00e6fee6b1b64b07a0e3b3558188fddf1d9c510565da884687c451
|
|
||||||
7
.github/actions/build-image/action.yaml
vendored
7
.github/actions/build-image/action.yaml
vendored
@@ -15,11 +15,6 @@ inputs:
|
|||||||
description: "Version to build"
|
description: "Version to build"
|
||||||
required: true
|
required: true
|
||||||
example: "2023.12.0"
|
example: "2023.12.0"
|
||||||
base_os:
|
|
||||||
description: "Base OS to use"
|
|
||||||
required: false
|
|
||||||
default: "debian"
|
|
||||||
example: "debian"
|
|
||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
@@ -60,7 +55,6 @@ runs:
|
|||||||
build-args: |
|
build-args: |
|
||||||
BUILD_TYPE=${{ inputs.build_type }}
|
BUILD_TYPE=${{ inputs.build_type }}
|
||||||
BUILD_VERSION=${{ inputs.version }}
|
BUILD_VERSION=${{ inputs.version }}
|
||||||
BUILD_OS=${{ inputs.base_os }}
|
|
||||||
outputs: |
|
outputs: |
|
||||||
type=image,name=ghcr.io/${{ steps.tags.outputs.image_name }},push-by-digest=true,name-canonical=true,push=true
|
type=image,name=ghcr.io/${{ steps.tags.outputs.image_name }},push-by-digest=true,name-canonical=true,push=true
|
||||||
|
|
||||||
@@ -86,7 +80,6 @@ runs:
|
|||||||
build-args: |
|
build-args: |
|
||||||
BUILD_TYPE=${{ inputs.build_type }}
|
BUILD_TYPE=${{ inputs.build_type }}
|
||||||
BUILD_VERSION=${{ inputs.version }}
|
BUILD_VERSION=${{ inputs.version }}
|
||||||
BUILD_OS=${{ inputs.base_os }}
|
|
||||||
outputs: |
|
outputs: |
|
||||||
type=image,name=docker.io/${{ steps.tags.outputs.image_name }},push-by-digest=true,name-canonical=true,push=true
|
type=image,name=docker.io/${{ steps.tags.outputs.image_name }},push-by-digest=true,name-canonical=true,push=true
|
||||||
|
|
||||||
|
|||||||
14
.github/actions/cache-esp-idf/action.yml
vendored
14
.github/actions/cache-esp-idf/action.yml
vendored
@@ -2,8 +2,8 @@ name: Cache ESP-IDF
|
|||||||
description: >
|
description: >
|
||||||
Resolve the pinned ESP-IDF version and cache the native ESP-IDF install
|
Resolve the pinned ESP-IDF version and cache the native ESP-IDF install
|
||||||
(toolchains + source) at ~/.esphome-idf. Every job that installs ESP-IDF
|
(toolchains + source) at ~/.esphome-idf. Every job that installs ESP-IDF
|
||||||
natively (clang-tidy for IDF/Arduino and the native-IDF component build)
|
natively (clang-tidy for IDF/Arduino and the component test batches) shares
|
||||||
shares one cache, since the install is identical (ESPHOME_IDF_DEFAULT_TARGETS
|
one cache, since the install is identical (ESPHOME_IDF_DEFAULT_TARGETS
|
||||||
defaults to "all", so all toolchains are present regardless of the chip).
|
defaults to "all", so all toolchains are present regardless of the chip).
|
||||||
Callers must set env ESPHOME_ESP_IDF_PREFIX: ~/.esphome-idf and have the
|
Callers must set env ESPHOME_ESP_IDF_PREFIX: ~/.esphome-idf and have the
|
||||||
Python venv already restored.
|
Python venv already restored.
|
||||||
@@ -11,6 +11,12 @@ inputs:
|
|||||||
framework:
|
framework:
|
||||||
description: 'Which pinned IDF version to key on: "espidf" (recommended) or "arduino".'
|
description: 'Which pinned IDF version to key on: "espidf" (recommended) or "arduino".'
|
||||||
default: espidf
|
default: espidf
|
||||||
|
restore-only:
|
||||||
|
description: >
|
||||||
|
When "true", only restore -- never save the cache, even on dev. Use from
|
||||||
|
jobs that may not produce an ESP-IDF install (e.g. a component batch with
|
||||||
|
no esp32 target), so a partial/empty install is never written to the key.
|
||||||
|
default: "false"
|
||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
steps:
|
steps:
|
||||||
@@ -33,13 +39,13 @@ runs:
|
|||||||
# PRs), and PRs are restore-only -- they never push multi-GB artifacts into
|
# PRs), and PRs are restore-only -- they never push multi-GB artifacts into
|
||||||
# their own scope / the repo quota (e.g. on a version-bump PR).
|
# their own scope / the repo quota (e.g. on a version-bump PR).
|
||||||
- name: Cache ESP-IDF install (write on dev)
|
- name: Cache ESP-IDF install (write on dev)
|
||||||
if: github.ref == 'refs/heads/dev'
|
if: github.ref == 'refs/heads/dev' && inputs.restore-only != 'true'
|
||||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||||
with:
|
with:
|
||||||
path: ~/.esphome-idf
|
path: ~/.esphome-idf
|
||||||
key: ${{ runner.os }}-esphome-idf-${{ steps.version.outputs.version }}
|
key: ${{ runner.os }}-esphome-idf-${{ steps.version.outputs.version }}
|
||||||
- name: Cache ESP-IDF install (restore-only off dev)
|
- name: Cache ESP-IDF install (restore-only off dev)
|
||||||
if: github.ref != 'refs/heads/dev'
|
if: github.ref != 'refs/heads/dev' || inputs.restore-only == 'true'
|
||||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||||
with:
|
with:
|
||||||
path: ~/.esphome-idf
|
path: ~/.esphome-idf
|
||||||
|
|||||||
2
.github/workflows/auto-label-pr.yml
vendored
2
.github/workflows/auto-label-pr.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
|||||||
if: github.event.pull_request.state == 'open' && (github.event.action != 'labeled' || github.event.sender.type != 'Bot')
|
if: github.event.pull_request.state == 'open' && (github.event.action != 'labeled' || github.event.sender.type != 'Bot')
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
|
|
||||||
- name: Generate a token
|
- name: Generate a token
|
||||||
id: generate-token
|
id: generate-token
|
||||||
|
|||||||
2
.github/workflows/ci-api-proto.yml
vendored
2
.github/workflows/ci-api-proto.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||||
with:
|
with:
|
||||||
|
|||||||
76
.github/workflows/ci-clang-tidy-hash.yml
vendored
76
.github/workflows/ci-clang-tidy-hash.yml
vendored
@@ -1,76 +0,0 @@
|
|||||||
name: Clang-tidy Hash CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- ".clang-tidy"
|
|
||||||
- "platformio.ini"
|
|
||||||
- "requirements_dev.txt"
|
|
||||||
- "sdkconfig.defaults"
|
|
||||||
- ".clang-tidy.hash"
|
|
||||||
- "script/clang_tidy_hash.py"
|
|
||||||
- ".github/workflows/ci-clang-tidy-hash.yml"
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read # actions/checkout for the PR head
|
|
||||||
pull-requests: write # pulls.createReview / listReviews / dismissReview when the clang-tidy hash is out of date
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
verify-hash:
|
|
||||||
name: Verify clang-tidy hash
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
||||||
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
||||||
with:
|
|
||||||
python-version: "3.11"
|
|
||||||
|
|
||||||
- name: Verify hash
|
|
||||||
run: |
|
|
||||||
python script/clang_tidy_hash.py --verify
|
|
||||||
|
|
||||||
- if: failure()
|
|
||||||
name: Show hash details
|
|
||||||
run: |
|
|
||||||
python script/clang_tidy_hash.py
|
|
||||||
echo "## Job Failed" | tee -a $GITHUB_STEP_SUMMARY
|
|
||||||
echo "You have modified clang-tidy configuration but have not updated the hash." | tee -a $GITHUB_STEP_SUMMARY
|
|
||||||
echo "Please run 'script/clang_tidy_hash.py --update' and commit the changes." | tee -a $GITHUB_STEP_SUMMARY
|
|
||||||
|
|
||||||
- if: failure() && github.event.pull_request.head.repo.full_name == github.repository
|
|
||||||
name: Request changes
|
|
||||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
await github.rest.pulls.createReview({
|
|
||||||
pull_number: context.issue.number,
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
event: 'REQUEST_CHANGES',
|
|
||||||
body: 'You have modified clang-tidy configuration but have not updated the hash.\nPlease run `script/clang_tidy_hash.py --update` and commit the changes.'
|
|
||||||
})
|
|
||||||
|
|
||||||
- if: success() && github.event.pull_request.head.repo.full_name == github.repository
|
|
||||||
name: Dismiss review
|
|
||||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
let reviews = await github.rest.pulls.listReviews({
|
|
||||||
pull_number: context.issue.number,
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo
|
|
||||||
});
|
|
||||||
for (let review of reviews.data) {
|
|
||||||
if (review.user.login === 'github-actions[bot]' && review.state === 'CHANGES_REQUESTED') {
|
|
||||||
await github.rest.pulls.dismissReview({
|
|
||||||
pull_number: context.issue.number,
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
review_id: review.id,
|
|
||||||
message: 'Clang-tidy hash now matches configuration.'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
186
.github/workflows/ci-docker.yml
vendored
186
.github/workflows/ci-docker.yml
vendored
@@ -1,28 +1,41 @@
|
|||||||
---
|
---
|
||||||
name: CI for docker images
|
name: CI for docker images
|
||||||
|
|
||||||
# Only run when docker paths change
|
# Only run on PRs that touch the docker image, its build inputs, or any code
|
||||||
|
# whose toolchain the compile smoke test exercises (core + target platforms).
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
|
||||||
branches: [dev, beta, release]
|
|
||||||
paths:
|
|
||||||
- "docker/**"
|
|
||||||
- ".github/workflows/ci-docker.yml"
|
|
||||||
- "requirements*.txt"
|
|
||||||
- "platformio.ini"
|
|
||||||
- "script/platformio_install_deps.py"
|
|
||||||
|
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
|
# Docker image and its build inputs.
|
||||||
- "docker/**"
|
- "docker/**"
|
||||||
- ".github/workflows/ci-docker.yml"
|
- ".github/workflows/ci-docker.yml"
|
||||||
- "requirements*.txt"
|
- "requirements*.txt"
|
||||||
|
- "pyproject.toml"
|
||||||
- "platformio.ini"
|
- "platformio.ini"
|
||||||
|
- "esphome/idf_component.yml"
|
||||||
- "script/platformio_install_deps.py"
|
- "script/platformio_install_deps.py"
|
||||||
|
# Core, build pipeline, toolchain, and target-platform changes can change
|
||||||
|
# how a toolchain is set up or built, so re-run the per-toolchain compile
|
||||||
|
# smoke test when they change.
|
||||||
|
- "esphome/core/**"
|
||||||
|
- "esphome/writer.py"
|
||||||
|
- "esphome/build_gen/**"
|
||||||
|
- "esphome/espidf/**"
|
||||||
|
- "esphome/platformio/**"
|
||||||
|
- "esphome/components/bk72xx/**"
|
||||||
|
- "esphome/components/esp32/**"
|
||||||
|
- "esphome/components/esp8266/**"
|
||||||
|
- "esphome/components/host/**"
|
||||||
|
- "esphome/components/libretiny/**"
|
||||||
|
- "esphome/components/ln882x/**"
|
||||||
|
- "esphome/components/nrf52/**"
|
||||||
|
- "esphome/components/rp2040/**"
|
||||||
|
- "esphome/components/rtl87xx/**"
|
||||||
|
- "esphome/components/zephyr/**"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read # actions/checkout only; the build does not push images
|
contents: read # actions/checkout only
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
# yamllint disable-line rule:line-length
|
# yamllint disable-line rule:line-length
|
||||||
@@ -33,6 +46,9 @@ jobs:
|
|||||||
check-docker:
|
check-docker:
|
||||||
name: Build docker containers
|
name: Build docker containers
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
permissions:
|
||||||
|
contents: read # actions/checkout to load Dockerfile and build context
|
||||||
|
packages: write # push branch-tagged images to ghcr.io for local testing
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -41,8 +57,11 @@ jobs:
|
|||||||
- "ha-addon"
|
- "ha-addon"
|
||||||
- "docker"
|
- "docker"
|
||||||
# - "lint"
|
# - "lint"
|
||||||
|
outputs:
|
||||||
|
tag: ${{ steps.tag.outputs.tag }}
|
||||||
|
push: ${{ steps.tag.outputs.push }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||||
with:
|
with:
|
||||||
@@ -50,14 +69,149 @@ jobs:
|
|||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
|
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
|
||||||
|
|
||||||
- name: Set TAG
|
- name: Determine tag and whether to push
|
||||||
|
id: tag
|
||||||
run: |
|
run: |
|
||||||
echo "TAG=check" >> $GITHUB_ENV
|
# Sanitize the branch name into a valid docker tag: replace invalid
|
||||||
|
# characters, ensure the first character is valid (tags must start
|
||||||
|
# with [A-Za-z0-9_]), and cap the length at 128 characters.
|
||||||
|
branch="${{ github.head_ref || github.ref_name }}"
|
||||||
|
tag="${branch//[^a-zA-Z0-9_.-]/-}"
|
||||||
|
case "$tag" in
|
||||||
|
[a-zA-Z0-9_]*) ;;
|
||||||
|
*) tag="pr-${tag}" ;;
|
||||||
|
esac
|
||||||
|
tag="${tag:0:128}"
|
||||||
|
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
|
||||||
|
# Only push branch images for same-repo pull requests. Push events
|
||||||
|
# only fire for dev/beta/release, whose images are owned by the
|
||||||
|
# release pipeline -- never overwrite those from here.
|
||||||
|
if [ "${{ github.event_name }}" = "pull_request" ] \
|
||||||
|
&& [ "${{ github.repository }}" = "esphome/esphome" ] \
|
||||||
|
&& [ "${{ github.event.pull_request.head.repo.full_name }}" = "esphome/esphome" ]; then
|
||||||
|
echo "push=true" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "push=false" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Log in to the GitHub container registry
|
||||||
|
if: steps.tag.outputs.push == 'true'
|
||||||
|
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Run build
|
- name: Run build
|
||||||
run: |
|
run: |
|
||||||
docker/build.py \
|
docker/build.py \
|
||||||
--tag "${TAG}" \
|
--tag "${{ steps.tag.outputs.tag }}" \
|
||||||
--arch "${{ matrix.os == 'ubuntu-24.04-arm' && 'aarch64' || 'amd64' }}" \
|
--arch "${{ matrix.os == 'ubuntu-24.04-arm' && 'aarch64' || 'amd64' }}" \
|
||||||
--build-type "${{ matrix.build_type }}" \
|
--build-type "${{ matrix.build_type }}" \
|
||||||
build
|
--registry ghcr \
|
||||||
|
build ${{ steps.tag.outputs.push == 'true' && '--push --no-cache-to' || '' }} ${{ (matrix.os == 'ubuntu-24.04' && matrix.build_type == 'docker') && '--load' || '' }}
|
||||||
|
|
||||||
|
# The amd64 "docker" image is also loaded locally (above) and handed to
|
||||||
|
# compile-test as an artifact, so the smoke test reuses this build instead
|
||||||
|
# of building the image a second time. Using an artifact (rather than the
|
||||||
|
# pushed image) keeps it working for fork PRs, which never push to ghcr.io.
|
||||||
|
- name: Export image for compile-test
|
||||||
|
if: matrix.os == 'ubuntu-24.04' && matrix.build_type == 'docker'
|
||||||
|
run: docker save "ghcr.io/esphome/esphome-amd64:${{ steps.tag.outputs.tag }}" | gzip > compile-test-image.tar.gz
|
||||||
|
|
||||||
|
- name: Upload compile-test image artifact
|
||||||
|
if: matrix.os == 'ubuntu-24.04' && matrix.build_type == 'docker'
|
||||||
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||||
|
with:
|
||||||
|
# The tar is already gzipped, so upload it as-is. archive: false skips
|
||||||
|
# the redundant zip and makes the file name the artifact name (the
|
||||||
|
# `name` input is ignored in that mode).
|
||||||
|
path: compile-test-image.tar.gz
|
||||||
|
retention-days: 1
|
||||||
|
archive: false
|
||||||
|
|
||||||
|
manifest:
|
||||||
|
name: Push ${{ matrix.build_type }} manifest to ghcr.io
|
||||||
|
needs: [check-docker]
|
||||||
|
if: needs.check-docker.outputs.push == 'true'
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
permissions:
|
||||||
|
contents: read # actions/checkout to run docker/build.py
|
||||||
|
packages: write # buildx imagetools writes the multi-arch tag to ghcr.io
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
build_type:
|
||||||
|
- "ha-addon"
|
||||||
|
- "docker"
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||||
|
with:
|
||||||
|
python-version: "3.11"
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
|
||||||
|
|
||||||
|
- name: Log in to the GitHub container registry
|
||||||
|
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Create and push manifest
|
||||||
|
run: |
|
||||||
|
docker/build.py \
|
||||||
|
--tag "${{ needs.check-docker.outputs.tag }}" \
|
||||||
|
--build-type "${{ matrix.build_type }}" \
|
||||||
|
--registry ghcr \
|
||||||
|
manifest
|
||||||
|
|
||||||
|
# Smoke-test the built image by compiling one minimal config per target
|
||||||
|
# platform / toolchain. This catches missing system dependencies in the image
|
||||||
|
# that only surface when a given toolchain is downloaded and run. The image is
|
||||||
|
# the amd64 "docker" build produced by check-docker (shared as an artifact).
|
||||||
|
compile-test:
|
||||||
|
name: Compile ${{ matrix.id }}
|
||||||
|
needs: check-docker
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
permissions:
|
||||||
|
contents: read # actions/checkout to load the test configs
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
# Cap concurrency so this smoke test doesn't hog all the shared runners.
|
||||||
|
max-parallel: 2
|
||||||
|
matrix:
|
||||||
|
# One entry per distinct toolchain. ESP32 variants (c3/c6/s2/s3/p4)
|
||||||
|
# share a toolchain bundle, so esp32 is exercised on the base variant
|
||||||
|
# across the full framework x toolchain cross-product (arduino/esp-idf
|
||||||
|
# framework, each built with the platformio and native esp-idf
|
||||||
|
# toolchains) so both toolchains stay covered regardless of which one is
|
||||||
|
# the default.
|
||||||
|
id:
|
||||||
|
- esp8266-arduino
|
||||||
|
- esp32-arduino-platformio
|
||||||
|
- esp32-arduino-esp-idf
|
||||||
|
- esp32-idf-platformio
|
||||||
|
- esp32-idf-esp-idf
|
||||||
|
- rp2040-arduino
|
||||||
|
- bk72xx-arduino
|
||||||
|
- rtl87xx-arduino
|
||||||
|
- ln882x-arduino
|
||||||
|
- nrf52
|
||||||
|
- host
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
|
- name: Download image artifact
|
||||||
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||||
|
with:
|
||||||
|
name: compile-test-image.tar.gz
|
||||||
|
- name: Load image
|
||||||
|
run: docker load --input compile-test-image.tar.gz
|
||||||
|
- name: Compile ${{ matrix.id }}
|
||||||
|
run: |
|
||||||
|
docker run --rm \
|
||||||
|
-v "${{ github.workspace }}/docker/test_configs:/config" \
|
||||||
|
"ghcr.io/esphome/esphome-amd64:${{ needs.check-docker.outputs.tag }}" \
|
||||||
|
compile "${{ matrix.id }}.yaml"
|
||||||
|
|||||||
2
.github/workflows/ci-github-scripts.yml
vendored
2
.github/workflows/ci-github-scripts.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
working-directory: .github/scripts/auto-label-pr
|
working-directory: .github/scripts/auto-label-pr
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Check out code from base repository
|
- name: Check out code from base repository
|
||||||
if: steps.pr.outputs.skip != 'true'
|
if: steps.pr.outputs.skip != 'true'
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Always check out from the base repository (esphome/esphome), never from forks
|
# Always check out from the base repository (esphome/esphome), never from forks
|
||||||
# Use the PR's target branch to ensure we run trusted code from the main repo
|
# Use the PR's target branch to ensure we run trusted code from the main repo
|
||||||
|
|||||||
183
.github/workflows/ci.yml
vendored
183
.github/workflows/ci.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
|||||||
cache-key: ${{ steps.cache-key.outputs.key }}
|
cache-key: ${{ steps.cache-key.outputs.key }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
- name: Generate cache-key
|
- name: Generate cache-key
|
||||||
id: cache-key
|
id: cache-key
|
||||||
run: echo key="${{ hashFiles('requirements.txt', 'requirements_dev.txt', 'requirements_test.txt', '.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT
|
run: echo key="${{ hashFiles('requirements.txt', 'requirements_dev.txt', 'requirements_test.txt', '.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT
|
||||||
@@ -74,7 +74,7 @@ jobs:
|
|||||||
if: needs.determine-jobs.outputs.python-linters == 'true'
|
if: needs.determine-jobs.outputs.python-linters == 'true'
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
- name: Restore Python
|
- name: Restore Python
|
||||||
uses: ./.github/actions/restore-python
|
uses: ./.github/actions/restore-python
|
||||||
with:
|
with:
|
||||||
@@ -97,7 +97,7 @@ jobs:
|
|||||||
if: needs.determine-jobs.outputs.core-ci == 'true'
|
if: needs.determine-jobs.outputs.core-ci == 'true'
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
- name: Restore Python
|
- name: Restore Python
|
||||||
uses: ./.github/actions/restore-python
|
uses: ./.github/actions/restore-python
|
||||||
with:
|
with:
|
||||||
@@ -124,7 +124,7 @@ jobs:
|
|||||||
if: needs.determine-jobs.outputs.import-time == 'true'
|
if: needs.determine-jobs.outputs.import-time == 'true'
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
- name: Restore Python
|
- name: Restore Python
|
||||||
uses: ./.github/actions/restore-python
|
uses: ./.github/actions/restore-python
|
||||||
with:
|
with:
|
||||||
@@ -152,11 +152,11 @@ jobs:
|
|||||||
if: needs.determine-jobs.outputs.device-builder == 'true'
|
if: needs.determine-jobs.outputs.device-builder == 'true'
|
||||||
steps:
|
steps:
|
||||||
- name: Check out esphome (this PR)
|
- name: Check out esphome (this PR)
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
path: esphome
|
path: esphome
|
||||||
- name: Check out esphome/device-builder
|
- name: Check out esphome/device-builder
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
repository: esphome/device-builder
|
repository: esphome/device-builder
|
||||||
ref: main
|
ref: main
|
||||||
@@ -225,7 +225,7 @@ jobs:
|
|||||||
if: needs.determine-jobs.outputs.core-ci == 'true'
|
if: needs.determine-jobs.outputs.core-ci == 'true'
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
- name: Restore Python
|
- name: Restore Python
|
||||||
id: restore-python
|
id: restore-python
|
||||||
uses: ./.github/actions/restore-python
|
uses: ./.github/actions/restore-python
|
||||||
@@ -270,8 +270,8 @@ jobs:
|
|||||||
python-linters: ${{ steps.determine.outputs.python-linters }}
|
python-linters: ${{ steps.determine.outputs.python-linters }}
|
||||||
import-time: ${{ steps.determine.outputs.import-time }}
|
import-time: ${{ steps.determine.outputs.import-time }}
|
||||||
device-builder: ${{ steps.determine.outputs.device-builder }}
|
device-builder: ${{ steps.determine.outputs.device-builder }}
|
||||||
native-idf: ${{ steps.determine.outputs.native-idf }}
|
esp32-platformio: ${{ steps.determine.outputs.esp32-platformio }}
|
||||||
native-idf-components: ${{ steps.determine.outputs.native-idf-components }}
|
esp32-platformio-components: ${{ steps.determine.outputs.esp32-platformio-components }}
|
||||||
changed-components: ${{ steps.determine.outputs.changed-components }}
|
changed-components: ${{ steps.determine.outputs.changed-components }}
|
||||||
changed-components-with-tests: ${{ steps.determine.outputs.changed-components-with-tests }}
|
changed-components-with-tests: ${{ steps.determine.outputs.changed-components-with-tests }}
|
||||||
directly-changed-components-with-tests: ${{ steps.determine.outputs.directly-changed-components-with-tests }}
|
directly-changed-components-with-tests: ${{ steps.determine.outputs.directly-changed-components-with-tests }}
|
||||||
@@ -285,7 +285,7 @@ jobs:
|
|||||||
benchmarks: ${{ steps.determine.outputs.benchmarks }}
|
benchmarks: ${{ steps.determine.outputs.benchmarks }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Fetch enough history to find the merge base
|
# Fetch enough history to find the merge base
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
@@ -324,8 +324,8 @@ jobs:
|
|||||||
echo "python-linters=$(echo "$output" | jq -r '.python_linters')" >> $GITHUB_OUTPUT
|
echo "python-linters=$(echo "$output" | jq -r '.python_linters')" >> $GITHUB_OUTPUT
|
||||||
echo "import-time=$(echo "$output" | jq -r '.import_time')" >> $GITHUB_OUTPUT
|
echo "import-time=$(echo "$output" | jq -r '.import_time')" >> $GITHUB_OUTPUT
|
||||||
echo "device-builder=$(echo "$output" | jq -r '.device_builder')" >> $GITHUB_OUTPUT
|
echo "device-builder=$(echo "$output" | jq -r '.device_builder')" >> $GITHUB_OUTPUT
|
||||||
echo "native-idf=$(echo "$output" | jq -r '.native_idf')" >> $GITHUB_OUTPUT
|
echo "esp32-platformio=$(echo "$output" | jq -r '.esp32_platformio')" >> $GITHUB_OUTPUT
|
||||||
echo "native-idf-components=$(echo "$output" | jq -r '.native_idf_components')" >> $GITHUB_OUTPUT
|
echo "esp32-platformio-components=$(echo "$output" | jq -r '.esp32_platformio_components')" >> $GITHUB_OUTPUT
|
||||||
echo "changed-components=$(echo "$output" | jq -c '.changed_components')" >> $GITHUB_OUTPUT
|
echo "changed-components=$(echo "$output" | jq -c '.changed_components')" >> $GITHUB_OUTPUT
|
||||||
echo "changed-components-with-tests=$(echo "$output" | jq -c '.changed_components_with_tests')" >> $GITHUB_OUTPUT
|
echo "changed-components-with-tests=$(echo "$output" | jq -c '.changed_components_with_tests')" >> $GITHUB_OUTPUT
|
||||||
echo "directly-changed-components-with-tests=$(echo "$output" | jq -c '.directly_changed_components_with_tests')" >> $GITHUB_OUTPUT
|
echo "directly-changed-components-with-tests=$(echo "$output" | jq -c '.directly_changed_components_with_tests')" >> $GITHUB_OUTPUT
|
||||||
@@ -357,7 +357,7 @@ jobs:
|
|||||||
bucket: ${{ fromJson(needs.determine-jobs.outputs.integration-test-buckets) }}
|
bucket: ${{ fromJson(needs.determine-jobs.outputs.integration-test-buckets) }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
- name: Set up Python 3.13
|
- name: Set up Python 3.13
|
||||||
id: python
|
id: python
|
||||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||||
@@ -409,7 +409,7 @@ jobs:
|
|||||||
if: github.event_name == 'pull_request' && (needs.determine-jobs.outputs.cpp-unit-tests-run-all == 'true' || needs.determine-jobs.outputs.cpp-unit-tests-components != '[]')
|
if: github.event_name == 'pull_request' && (needs.determine-jobs.outputs.cpp-unit-tests-run-all == 'true' || needs.determine-jobs.outputs.cpp-unit-tests-components != '[]')
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
|
|
||||||
- name: Restore Python
|
- name: Restore Python
|
||||||
uses: ./.github/actions/restore-python
|
uses: ./.github/actions/restore-python
|
||||||
@@ -438,7 +438,7 @@ jobs:
|
|||||||
(github.event_name == 'pull_request' && needs.determine-jobs.outputs.benchmarks == 'true')
|
(github.event_name == 'pull_request' && needs.determine-jobs.outputs.benchmarks == 'true')
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
|
|
||||||
- name: Restore Python
|
- name: Restore Python
|
||||||
uses: ./.github/actions/restore-python
|
uses: ./.github/actions/restore-python
|
||||||
@@ -456,7 +456,7 @@ jobs:
|
|||||||
echo "binary=$BINARY" >> $GITHUB_OUTPUT
|
echo "binary=$BINARY" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Run CodSpeed benchmarks
|
- name: Run CodSpeed benchmarks
|
||||||
uses: CodSpeedHQ/action@9d332c4d90b43981c3e55ae8e38e68709996240f # v4.17.0
|
uses: CodSpeedHQ/action@63f3e98b61959fe67f146a3ff022e4136fe9bb9c # v4.17.6
|
||||||
with:
|
with:
|
||||||
run: |
|
run: |
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
@@ -496,7 +496,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Need history for HEAD~1 to work for checking changed files
|
# Need history for HEAD~1 to work for checking changed files
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
@@ -522,7 +522,6 @@ jobs:
|
|||||||
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
|
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
|
||||||
|
|
||||||
- name: Cache ESP-IDF install
|
- name: Cache ESP-IDF install
|
||||||
# Shared with the IDF tidy + native-IDF build jobs (same install).
|
|
||||||
if: matrix.cache_idf
|
if: matrix.cache_idf
|
||||||
uses: ./.github/actions/cache-esp-idf
|
uses: ./.github/actions/cache-esp-idf
|
||||||
with:
|
with:
|
||||||
@@ -537,15 +536,12 @@ jobs:
|
|||||||
id: check_full_scan
|
id: check_full_scan
|
||||||
run: |
|
run: |
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
# determine-jobs.clang-tidy-full-scan is true when core C++ changed
|
# determine-jobs.clang-tidy-full-scan is true when core C++ or a
|
||||||
# OR the ci-run-all label forced --force-all. Independent of the
|
# clang-tidy-relevant config file changed, or the ci-run-all label
|
||||||
# hash check, both must produce a full scan in the job itself.
|
# forced --force-all.
|
||||||
if [ "${{ needs.determine-jobs.outputs.clang-tidy-full-scan }}" = "true" ]; then
|
if [ "${{ needs.determine-jobs.outputs.clang-tidy-full-scan }}" = "true" ]; then
|
||||||
echo "full_scan=true" >> $GITHUB_OUTPUT
|
echo "full_scan=true" >> $GITHUB_OUTPUT
|
||||||
echo "reason=determine_jobs" >> $GITHUB_OUTPUT
|
echo "reason=determine_jobs" >> $GITHUB_OUTPUT
|
||||||
elif python script/clang_tidy_hash.py --check; then
|
|
||||||
echo "full_scan=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "reason=hash_changed" >> $GITHUB_OUTPUT
|
|
||||||
else
|
else
|
||||||
echo "full_scan=false" >> $GITHUB_OUTPUT
|
echo "full_scan=false" >> $GITHUB_OUTPUT
|
||||||
echo "reason=normal" >> $GITHUB_OUTPUT
|
echo "reason=normal" >> $GITHUB_OUTPUT
|
||||||
@@ -583,7 +579,7 @@ jobs:
|
|||||||
ESPHOME_ESP_IDF_PREFIX: ~/.esphome-idf
|
ESPHOME_ESP_IDF_PREFIX: ~/.esphome-idf
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Need history for HEAD~1 to work for checking changed files
|
# Need history for HEAD~1 to work for checking changed files
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
@@ -595,7 +591,6 @@ jobs:
|
|||||||
cache-key: ${{ needs.common.outputs.cache-key }}
|
cache-key: ${{ needs.common.outputs.cache-key }}
|
||||||
|
|
||||||
- name: Cache ESP-IDF install
|
- name: Cache ESP-IDF install
|
||||||
# Shared with the Arduino tidy + native-IDF build jobs (same install).
|
|
||||||
uses: ./.github/actions/cache-esp-idf
|
uses: ./.github/actions/cache-esp-idf
|
||||||
|
|
||||||
- name: Register problem matchers
|
- name: Register problem matchers
|
||||||
@@ -607,15 +602,12 @@ jobs:
|
|||||||
id: check_full_scan
|
id: check_full_scan
|
||||||
run: |
|
run: |
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
# determine-jobs.clang-tidy-full-scan is true when core C++ changed
|
# determine-jobs.clang-tidy-full-scan is true when core C++ or a
|
||||||
# OR the ci-run-all label forced --force-all. Independent of the
|
# clang-tidy-relevant config file changed, or the ci-run-all label
|
||||||
# hash check, both must produce a full scan in the job itself.
|
# forced --force-all.
|
||||||
if [ "${{ needs.determine-jobs.outputs.clang-tidy-full-scan }}" = "true" ]; then
|
if [ "${{ needs.determine-jobs.outputs.clang-tidy-full-scan }}" = "true" ]; then
|
||||||
echo "full_scan=true" >> $GITHUB_OUTPUT
|
echo "full_scan=true" >> $GITHUB_OUTPUT
|
||||||
echo "reason=determine_jobs" >> $GITHUB_OUTPUT
|
echo "reason=determine_jobs" >> $GITHUB_OUTPUT
|
||||||
elif python script/clang_tidy_hash.py --check; then
|
|
||||||
echo "full_scan=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "reason=hash_changed" >> $GITHUB_OUTPUT
|
|
||||||
else
|
else
|
||||||
echo "full_scan=false" >> $GITHUB_OUTPUT
|
echo "full_scan=false" >> $GITHUB_OUTPUT
|
||||||
echo "reason=normal" >> $GITHUB_OUTPUT
|
echo "reason=normal" >> $GITHUB_OUTPUT
|
||||||
@@ -667,7 +659,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Need history for HEAD~1 to work for checking changed files
|
# Need history for HEAD~1 to work for checking changed files
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
@@ -679,7 +671,6 @@ jobs:
|
|||||||
cache-key: ${{ needs.common.outputs.cache-key }}
|
cache-key: ${{ needs.common.outputs.cache-key }}
|
||||||
|
|
||||||
- name: Cache ESP-IDF install
|
- name: Cache ESP-IDF install
|
||||||
# Shared with the Arduino tidy + native-IDF build jobs (same install).
|
|
||||||
uses: ./.github/actions/cache-esp-idf
|
uses: ./.github/actions/cache-esp-idf
|
||||||
|
|
||||||
- name: Register problem matchers
|
- name: Register problem matchers
|
||||||
@@ -691,15 +682,12 @@ jobs:
|
|||||||
id: check_full_scan
|
id: check_full_scan
|
||||||
run: |
|
run: |
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
# determine-jobs.clang-tidy-full-scan is true when core C++ changed
|
# determine-jobs.clang-tidy-full-scan is true when core C++ or a
|
||||||
# OR the ci-run-all label forced --force-all. Independent of the
|
# clang-tidy-relevant config file changed, or the ci-run-all label
|
||||||
# hash check, both must produce a full scan in the job itself.
|
# forced --force-all.
|
||||||
if [ "${{ needs.determine-jobs.outputs.clang-tidy-full-scan }}" = "true" ]; then
|
if [ "${{ needs.determine-jobs.outputs.clang-tidy-full-scan }}" = "true" ]; then
|
||||||
echo "full_scan=true" >> $GITHUB_OUTPUT
|
echo "full_scan=true" >> $GITHUB_OUTPUT
|
||||||
echo "reason=determine_jobs" >> $GITHUB_OUTPUT
|
echo "reason=determine_jobs" >> $GITHUB_OUTPUT
|
||||||
elif python script/clang_tidy_hash.py --check; then
|
|
||||||
echo "full_scan=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "reason=hash_changed" >> $GITHUB_OUTPUT
|
|
||||||
else
|
else
|
||||||
echo "full_scan=false" >> $GITHUB_OUTPUT
|
echo "full_scan=false" >> $GITHUB_OUTPUT
|
||||||
echo "reason=normal" >> $GITHUB_OUTPUT
|
echo "reason=normal" >> $GITHUB_OUTPUT
|
||||||
@@ -755,7 +743,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
# Need history for HEAD~1 to work for checking changed files
|
# Need history for HEAD~1 to work for checking changed files
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
@@ -767,7 +755,6 @@ jobs:
|
|||||||
cache-key: ${{ needs.common.outputs.cache-key }}
|
cache-key: ${{ needs.common.outputs.cache-key }}
|
||||||
|
|
||||||
- name: Cache ESP-IDF install
|
- name: Cache ESP-IDF install
|
||||||
# Shared with the IDF/Arduino clang-tidy jobs + native-IDF build (same install).
|
|
||||||
uses: ./.github/actions/cache-esp-idf
|
uses: ./.github/actions/cache-esp-idf
|
||||||
|
|
||||||
- name: Register problem matchers
|
- name: Register problem matchers
|
||||||
@@ -779,15 +766,12 @@ jobs:
|
|||||||
id: check_full_scan
|
id: check_full_scan
|
||||||
run: |
|
run: |
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
# determine-jobs.clang-tidy-full-scan is true when core C++ changed
|
# determine-jobs.clang-tidy-full-scan is true when core C++ or a
|
||||||
# OR the ci-run-all label forced --force-all. Independent of the
|
# clang-tidy-relevant config file changed, or the ci-run-all label
|
||||||
# hash check, both must produce a full scan in the job itself.
|
# forced --force-all.
|
||||||
if [ "${{ needs.determine-jobs.outputs.clang-tidy-full-scan }}" = "true" ]; then
|
if [ "${{ needs.determine-jobs.outputs.clang-tidy-full-scan }}" = "true" ]; then
|
||||||
echo "full_scan=true" >> $GITHUB_OUTPUT
|
echo "full_scan=true" >> $GITHUB_OUTPUT
|
||||||
echo "reason=determine_jobs" >> $GITHUB_OUTPUT
|
echo "reason=determine_jobs" >> $GITHUB_OUTPUT
|
||||||
elif python script/clang_tidy_hash.py --check; then
|
|
||||||
echo "full_scan=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "reason=hash_changed" >> $GITHUB_OUTPUT
|
|
||||||
else
|
else
|
||||||
echo "full_scan=false" >> $GITHUB_OUTPUT
|
echo "full_scan=false" >> $GITHUB_OUTPUT
|
||||||
echo "reason=normal" >> $GITHUB_OUTPUT
|
echo "reason=normal" >> $GITHUB_OUTPUT
|
||||||
@@ -817,6 +801,10 @@ jobs:
|
|||||||
- common
|
- common
|
||||||
- determine-jobs
|
- determine-jobs
|
||||||
if: github.event_name == 'pull_request' && fromJSON(needs.determine-jobs.outputs.component-test-count) > 0
|
if: github.event_name == 'pull_request' && fromJSON(needs.determine-jobs.outputs.component-test-count) > 0
|
||||||
|
env:
|
||||||
|
# esp32 component builds use the native ESP-IDF toolchain (default), so
|
||||||
|
# share the tidy jobs' install location -- the restore below lands here.
|
||||||
|
ESPHOME_ESP_IDF_PREFIX: ~/.esphome-idf
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
max-parallel: ${{ (startsWith(github.base_ref, 'beta') || startsWith(github.base_ref, 'release')) && 8 || 4 }}
|
max-parallel: ${{ (startsWith(github.base_ref, 'beta') || startsWith(github.base_ref, 'release')) && 8 || 4 }}
|
||||||
@@ -838,12 +826,18 @@ jobs:
|
|||||||
version: 1.0
|
version: 1.0
|
||||||
|
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
- name: Restore Python
|
- name: Restore Python
|
||||||
uses: ./.github/actions/restore-python
|
uses: ./.github/actions/restore-python
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
cache-key: ${{ needs.common.outputs.cache-key }}
|
cache-key: ${{ needs.common.outputs.cache-key }}
|
||||||
|
- name: Cache ESP-IDF install (restore-only)
|
||||||
|
# A batch may contain no esp32 build, so never save -- just reuse the
|
||||||
|
# shared install the dev tidy jobs already cached when present.
|
||||||
|
uses: ./.github/actions/cache-esp-idf
|
||||||
|
with:
|
||||||
|
restore-only: true
|
||||||
- name: Validate and compile components with intelligent grouping
|
- name: Validate and compile components with intelligent grouping
|
||||||
run: |
|
run: |
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
@@ -947,23 +941,22 @@ jobs:
|
|||||||
echo "All components in this batch are validate-only -- skipping compile stage."
|
echo "All components in this batch are validate-only -- skipping compile stage."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
test-native-idf:
|
test-esp32-platformio:
|
||||||
name: Test components with native ESP-IDF
|
name: Test esp32 components with PlatformIO
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
- common
|
- common
|
||||||
- determine-jobs
|
- determine-jobs
|
||||||
if: github.event_name == 'pull_request' && needs.determine-jobs.outputs.native-idf == 'true'
|
if: github.event_name == 'pull_request' && needs.determine-jobs.outputs.esp32-platformio == 'true'
|
||||||
env:
|
env:
|
||||||
ESPHOME_ESP_IDF_PREFIX: ~/.esphome-idf
|
# Comma-joined subset of the esp32 PlatformIO representative component list,
|
||||||
# Comma-joined subset of the native-IDF representative component list,
|
# computed by script/determine-jobs.py (esp32_platformio_components_to_test).
|
||||||
# computed by script/determine-jobs.py (native_idf_components_to_test).
|
|
||||||
# Single source of truth -- the full list lives in
|
# Single source of truth -- the full list lives in
|
||||||
# script/determine-jobs.py::NATIVE_IDF_TEST_COMPONENTS.
|
# script/determine-jobs.py::ESP32_PLATFORMIO_TEST_COMPONENTS.
|
||||||
TEST_COMPONENTS: ${{ needs.determine-jobs.outputs.native-idf-components }}
|
TEST_COMPONENTS: ${{ needs.determine-jobs.outputs.esp32-platformio-components }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
|
|
||||||
- name: Restore Python
|
- name: Restore Python
|
||||||
uses: ./.github/actions/restore-python
|
uses: ./.github/actions/restore-python
|
||||||
@@ -971,66 +964,23 @@ jobs:
|
|||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
cache-key: ${{ needs.common.outputs.cache-key }}
|
cache-key: ${{ needs.common.outputs.cache-key }}
|
||||||
|
|
||||||
- name: Prepare build storage on /mnt
|
- name: Run PlatformIO compile test
|
||||||
# Bind-mount the larger /mnt disk over the IDF install + build dirs BEFORE
|
|
||||||
# restoring the cache, so the ~4.5GB restore lands on the roomier volume
|
|
||||||
# instead of being shadowed by a mount set up later in the run step.
|
|
||||||
run: |
|
|
||||||
root_avail=$(df -k / | awk 'NR==2 {print $4}')
|
|
||||||
mnt_avail=$(df -k /mnt 2>/dev/null | awk 'NR==2 {print $4}')
|
|
||||||
echo "Available space: / has ${root_avail}KB, /mnt has ${mnt_avail}KB"
|
|
||||||
if [ -n "$mnt_avail" ] && [ "$mnt_avail" -gt "$root_avail" ]; then
|
|
||||||
echo "Using /mnt for build files (more space available)"
|
|
||||||
sudo mkdir -p /mnt/esphome-idf
|
|
||||||
sudo chown $USER:$USER /mnt/esphome-idf
|
|
||||||
mkdir -p ~/.esphome-idf
|
|
||||||
sudo mount --bind /mnt/esphome-idf ~/.esphome-idf
|
|
||||||
sudo mkdir -p /mnt/test_build_components_build
|
|
||||||
sudo chown $USER:$USER /mnt/test_build_components_build
|
|
||||||
mkdir -p tests/test_build_components/build
|
|
||||||
sudo mount --bind /mnt/test_build_components_build tests/test_build_components/build
|
|
||||||
else
|
|
||||||
echo "Using / for build files (more space available than /mnt or /mnt unavailable)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Cache ESP-IDF install
|
|
||||||
# Shared with the IDF/Arduino clang-tidy jobs (same install); restores
|
|
||||||
# into the /mnt bind-mount prepared above when present.
|
|
||||||
uses: ./.github/actions/cache-esp-idf
|
|
||||||
|
|
||||||
- name: Run native ESP-IDF compile test
|
|
||||||
run: |
|
run: |
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
|
|
||||||
echo "Testing components: $TEST_COMPONENTS"
|
echo "Testing components: $TEST_COMPONENTS"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Show disk space before validation
|
# compile validates config first, so a separate config pass is
|
||||||
echo "Disk space before config validation:"
|
# redundant for this smoke test. ESP-IDF framework via PlatformIO:
|
||||||
df -h
|
python3 script/test_build_components.py -e compile -t esp32-idf -c "$TEST_COMPONENTS" -f --toolchain platformio
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Run config validation (auto-grouped by test_build_components.py)
|
|
||||||
python3 script/test_build_components.py -e config -t esp32-idf -c "$TEST_COMPONENTS" -f --toolchain esp-idf
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Config validation passed! Starting compilation..."
|
echo "ESP-IDF-via-PlatformIO build passed! Starting Arduino smoke test..."
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Show disk space before compilation
|
# Arduino framework via PlatformIO (only components with an esp32-ard test are built):
|
||||||
echo "Disk space before compilation:"
|
python3 script/test_build_components.py -e compile -t esp32-ard -c "$TEST_COMPONENTS" -f --toolchain platformio
|
||||||
df -h
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Run compilation (auto-grouped by test_build_components.py)
|
|
||||||
python3 script/test_build_components.py -e compile -t esp32-idf -c "$TEST_COMPONENTS" -f --toolchain esp-idf
|
|
||||||
|
|
||||||
- name: Save ESPHome cache
|
|
||||||
if: github.ref == 'refs/heads/dev'
|
|
||||||
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
|
||||||
with:
|
|
||||||
path: ~/.esphome-idf
|
|
||||||
key: ${{ runner.os }}-esphome-${{ needs.common.outputs.cache-key }}
|
|
||||||
|
|
||||||
pre-commit-ci-lite:
|
pre-commit-ci-lite:
|
||||||
name: pre-commit.ci lite
|
name: pre-commit.ci lite
|
||||||
@@ -1041,7 +991,7 @@ jobs:
|
|||||||
if: github.event_name == 'pull_request' && !startsWith(github.base_ref, 'beta') && !startsWith(github.base_ref, 'release') && needs.determine-jobs.outputs.core-ci == 'true'
|
if: github.event_name == 'pull_request' && !startsWith(github.base_ref, 'beta') && !startsWith(github.base_ref, 'release') && needs.determine-jobs.outputs.core-ci == 'true'
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code from GitHub
|
- name: Check out code from GitHub
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
- name: Restore Python
|
- name: Restore Python
|
||||||
uses: ./.github/actions/restore-python
|
uses: ./.github/actions/restore-python
|
||||||
with:
|
with:
|
||||||
@@ -1049,7 +999,7 @@ jobs:
|
|||||||
cache-key: ${{ needs.common.outputs.cache-key }}
|
cache-key: ${{ needs.common.outputs.cache-key }}
|
||||||
- uses: esphome/pre-commit-action@43cd1109c09c544d97196f7730ee5b2e0cc6d81e # v3.0.1 fork with pinned actions/cache
|
- uses: esphome/pre-commit-action@43cd1109c09c544d97196f7730ee5b2e0cc6d81e # v3.0.1 fork with pinned actions/cache
|
||||||
env:
|
env:
|
||||||
SKIP: pylint,clang-tidy-hash,ci-custom
|
SKIP: pylint,ci-custom
|
||||||
- uses: pre-commit-ci/lite-action@5d6cc0eb514c891a40562a58a8e71576c5c7fb43 # v1.1.0
|
- uses: pre-commit-ci/lite-action@5d6cc0eb514c891a40562a58a8e71576c5c7fb43 # v1.1.0
|
||||||
if: always()
|
if: always()
|
||||||
|
|
||||||
@@ -1067,7 +1017,7 @@ jobs:
|
|||||||
skip: ${{ steps.check-script.outputs.skip || steps.check-tests.outputs.skip }}
|
skip: ${{ steps.check-script.outputs.skip || steps.check-tests.outputs.skip }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out target branch
|
- name: Check out target branch
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.base_ref }}
|
ref: ${{ github.base_ref }}
|
||||||
|
|
||||||
@@ -1249,7 +1199,7 @@ jobs:
|
|||||||
flash_usage: ${{ steps.extract.outputs.flash_usage }}
|
flash_usage: ${{ steps.extract.outputs.flash_usage }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out PR branch
|
- name: Check out PR branch
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
- name: Restore Python
|
- name: Restore Python
|
||||||
uses: ./.github/actions/restore-python
|
uses: ./.github/actions/restore-python
|
||||||
with:
|
with:
|
||||||
@@ -1318,7 +1268,7 @@ jobs:
|
|||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
- name: Restore Python
|
- name: Restore Python
|
||||||
uses: ./.github/actions/restore-python
|
uses: ./.github/actions/restore-python
|
||||||
with:
|
with:
|
||||||
@@ -1365,7 +1315,7 @@ jobs:
|
|||||||
- determine-jobs
|
- determine-jobs
|
||||||
- device-builder
|
- device-builder
|
||||||
- test-build-components-split
|
- test-build-components-split
|
||||||
- test-native-idf
|
- test-esp32-platformio
|
||||||
- pre-commit-ci-lite
|
- pre-commit-ci-lite
|
||||||
- memory-impact-target-branch
|
- memory-impact-target-branch
|
||||||
- memory-impact-pr-branch
|
- memory-impact-pr-branch
|
||||||
@@ -1381,4 +1331,7 @@ jobs:
|
|||||||
# 1. The target branch has a build issue independent of this PR
|
# 1. The target branch has a build issue independent of this PR
|
||||||
# 2. This PR fixes a build issue on the target branch
|
# 2. This PR fixes a build issue on the target branch
|
||||||
# In either case, we only care that the PR branch builds successfully.
|
# In either case, we only care that the PR branch builds successfully.
|
||||||
echo "$NEEDS_JSON" | jq -e 'del(.["memory-impact-target-branch"]) | all(.result != "failure")'
|
# Every other job must have succeeded or been skipped; a "cancelled" or
|
||||||
|
# "failure" result fails this check so CI is not reported green when the
|
||||||
|
# workflow was cancelled.
|
||||||
|
echo "$NEEDS_JSON" | jq -e 'del(.["memory-impact-target-branch"]) | all(.result == "success" or .result == "skipped")'
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout base branch
|
- name: Checkout base branch
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.base.sha }}
|
ref: ${{ github.event.pull_request.base.sha }}
|
||||||
sparse-checkout: |
|
sparse-checkout: |
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout base branch
|
- name: Checkout base branch
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.base.sha }}
|
ref: ${{ github.event.pull_request.base.sha }}
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -52,7 +52,7 @@ jobs:
|
|||||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
|
|||||||
2
.github/workflows/pr-title-check.yml
vendored
2
.github/workflows/pr-title-check.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
|||||||
name: Validate PR title
|
name: Validate PR title
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
|
|
||||||
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||||
with:
|
with:
|
||||||
|
|||||||
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
|||||||
branch_build: ${{ steps.tag.outputs.branch_build }}
|
branch_build: ${{ steps.tag.outputs.branch_build }}
|
||||||
deploy_env: ${{ steps.tag.outputs.deploy_env }}
|
deploy_env: ${{ steps.tag.outputs.deploy_env }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
- name: Get tag
|
- name: Get tag
|
||||||
id: tag
|
id: tag
|
||||||
# yamllint disable rule:line-length
|
# yamllint disable rule:line-length
|
||||||
@@ -60,7 +60,7 @@ jobs:
|
|||||||
contents: read # actions/checkout to build the sdist/wheel
|
contents: read # actions/checkout to build the sdist/wheel
|
||||||
id-token: write # OIDC token for PyPI Trusted Publishing (pypa/gh-action-pypi-publish)
|
id-token: write # OIDC token for PyPI Trusted Publishing (pypa/gh-action-pypi-publish)
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||||
with:
|
with:
|
||||||
@@ -92,7 +92,7 @@ jobs:
|
|||||||
os: "ubuntu-24.04-arm"
|
os: "ubuntu-24.04-arm"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||||
with:
|
with:
|
||||||
@@ -168,7 +168,7 @@ jobs:
|
|||||||
- ghcr
|
- ghcr
|
||||||
- dockerhub
|
- dockerhub
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
|
|
||||||
- name: Download digests
|
- name: Download digests
|
||||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||||
|
|||||||
4
.github/workflows/sync-device-classes.yml
vendored
4
.github/workflows/sync-device-classes.yml
vendored
@@ -28,10 +28,10 @@ jobs:
|
|||||||
permission-pull-requests: write # pulls.create / pulls.update to open or refresh the sync PR
|
permission-pull-requests: write # pulls.create / pulls.update to open or refresh the sync PR
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
|
|
||||||
- name: Checkout Home Assistant
|
- name: Checkout Home Assistant
|
||||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||||
with:
|
with:
|
||||||
repository: home-assistant/core
|
repository: home-assistant/core
|
||||||
path: lib/home-assistant
|
path: lib/home-assistant
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ ci:
|
|||||||
autoupdate_commit_msg: 'pre-commit: autoupdate'
|
autoupdate_commit_msg: 'pre-commit: autoupdate'
|
||||||
autoupdate_schedule: off # Disabled until ruff versions are synced between deps and pre-commit
|
autoupdate_schedule: off # Disabled until ruff versions are synced between deps and pre-commit
|
||||||
# Skip hooks that have issues in pre-commit CI environment
|
# Skip hooks that have issues in pre-commit CI environment
|
||||||
skip: [pylint, clang-tidy-hash]
|
skip: [pylint]
|
||||||
|
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
@@ -59,13 +59,6 @@ repos:
|
|||||||
language: system
|
language: system
|
||||||
types: [python]
|
types: [python]
|
||||||
files: ^esphome/.+\.py$
|
files: ^esphome/.+\.py$
|
||||||
- id: clang-tidy-hash
|
|
||||||
name: Update clang-tidy hash
|
|
||||||
entry: python script/clang_tidy_hash.py --update-if-changed
|
|
||||||
language: python
|
|
||||||
files: ^(\.clang-tidy|platformio\.ini|requirements_dev\.txt|sdkconfig\.defaults|esphome/idf_component\.yml)$
|
|
||||||
pass_filenames: false
|
|
||||||
additional_dependencies: []
|
|
||||||
- id: ci-custom
|
- id: ci-custom
|
||||||
name: ci-custom
|
name: ci-custom
|
||||||
entry: python script/run-in-env.py script/ci-custom.py
|
entry: python script/run-in-env.py script/ci-custom.py
|
||||||
|
|||||||
13
AGENTS.md
13
AGENTS.md
@@ -59,6 +59,19 @@ This document provides essential context for AI models interacting with this pro
|
|||||||
- Protected/private fields: `lower_snake_case_with_trailing_underscore_`
|
- Protected/private fields: `lower_snake_case_with_trailing_underscore_`
|
||||||
- Favor descriptive names over abbreviations
|
- Favor descriptive names over abbreviations
|
||||||
|
|
||||||
|
* **Python Idioms:**
|
||||||
|
* **Assignment expressions (PEP 572):** Prefer the walrus operator (`:=`) wherever it removes a redundant lookup or a throwaway temporary. The most common case in component code is presence-checking a config key and then indexing it separately — fetch once with `.get()` and bind in the condition instead:
|
||||||
|
```python
|
||||||
|
# Bad - looks up CONF_BLAH twice
|
||||||
|
if CONF_BLAH in config:
|
||||||
|
cg.add(var.set_blah(config[CONF_BLAH]))
|
||||||
|
|
||||||
|
# Good - single lookup, value bound inline
|
||||||
|
if (blah := config.get(CONF_BLAH)) is not None:
|
||||||
|
cg.add(var.set_blah(blah))
|
||||||
|
```
|
||||||
|
The same applies to `while` loops and comprehensions where it avoids recomputing a value. Don't contort code to use it — reach for `:=` only when it genuinely cuts repetition or an extra assignment line.
|
||||||
|
|
||||||
* **C++ Field Visibility:**
|
* **C++ Field Visibility:**
|
||||||
* **Prefer `protected`:** Use `protected` for most class fields to enable extensibility and testing. Fields should be `lower_snake_case_with_trailing_underscore_`.
|
* **Prefer `protected`:** Use `protected` for most class fields to enable extensibility and testing. Fields should be `lower_snake_case_with_trailing_underscore_`.
|
||||||
* **Use `private` for safety-critical cases:** Use `private` visibility when direct field access could introduce bugs or violate invariants:
|
* **Use `private` for safety-critical cases:** Use `private` visibility when direct field access could introduce bugs or violate invariants:
|
||||||
|
|||||||
@@ -445,7 +445,7 @@ esphome/components/select/* @esphome/core
|
|||||||
esphome/components/sen0321/* @notjj
|
esphome/components/sen0321/* @notjj
|
||||||
esphome/components/sen21231/* @shreyaskarnik
|
esphome/components/sen21231/* @shreyaskarnik
|
||||||
esphome/components/sen5x/* @martgras
|
esphome/components/sen5x/* @martgras
|
||||||
esphome/components/sen6x/* @martgras @mebner86 @mikelawrence @tuct
|
esphome/components/sen6x/* @martgras @mebner86 @tuct
|
||||||
esphome/components/sendspin/* @kahrendt
|
esphome/components/sendspin/* @kahrendt
|
||||||
esphome/components/sendspin/media_player/* @kahrendt
|
esphome/components/sendspin/media_player/* @kahrendt
|
||||||
esphome/components/sendspin/media_source/* @kahrendt
|
esphome/components/sendspin/media_source/* @kahrendt
|
||||||
@@ -561,6 +561,7 @@ esphome/components/uart/packet_transport/* @clydebarrow
|
|||||||
esphome/components/udp/* @clydebarrow
|
esphome/components/udp/* @clydebarrow
|
||||||
esphome/components/ufire_ec/* @pvizeli
|
esphome/components/ufire_ec/* @pvizeli
|
||||||
esphome/components/ufire_ise/* @pvizeli
|
esphome/components/ufire_ise/* @pvizeli
|
||||||
|
esphome/components/ufm01/* @ljungqvist
|
||||||
esphome/components/ultrasonic/* @ssieb @swoboda1337
|
esphome/components/ultrasonic/* @ssieb @swoboda1337
|
||||||
esphome/components/update/* @jesserockz
|
esphome/components/update/* @jesserockz
|
||||||
esphome/components/uponor_smatrix/* @kroimon
|
esphome/components/uponor_smatrix/* @kroimon
|
||||||
|
|||||||
2
Doxyfile
2
Doxyfile
@@ -48,7 +48,7 @@ PROJECT_NAME = ESPHome
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = 2026.6.0-dev
|
PROJECT_NUMBER = 2026.7.0-dev
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
|
|||||||
104
THREAT_MODEL.md
Normal file
104
THREAT_MODEL.md
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
# ESPHome Threat Model
|
||||||
|
|
||||||
|
This document defines the trust boundary for the **ESPHome** repository — the
|
||||||
|
Python compiler/CLI and the device firmware it generates — so that real security
|
||||||
|
bugs can be told apart from defense-in-depth improvements. It gives contributors,
|
||||||
|
reviewers, and security researchers a clear answer to one question:
|
||||||
|
**does this issue let an _unauthenticated_ attacker do something they shouldn't?**
|
||||||
|
|
||||||
|
Related documents:
|
||||||
|
|
||||||
|
- Deployment guidance for operators:
|
||||||
|
https://esphome.io/guides/security_best_practices/
|
||||||
|
- The **Device Builder dashboard** (the web UI, its authentication, ingress,
|
||||||
|
Origin/Host gates, and peer-link pairing) lives in a separate repository and
|
||||||
|
has its own threat model. If your report concerns any of that, please read and
|
||||||
|
report there instead:
|
||||||
|
https://github.com/esphome/device-builder/blob/main/docs/THREAT_MODEL.md
|
||||||
|
|
||||||
|
## The trust boundary
|
||||||
|
|
||||||
|
For this repository there are two trusted inputs by design:
|
||||||
|
|
||||||
|
1. **The configuration.** Anyone who can supply or edit a YAML config is trusted
|
||||||
|
(see below).
|
||||||
|
2. **Authenticated peers of a running device** — clients holding the device's
|
||||||
|
API encryption key / password, OTA password, or web server credentials.
|
||||||
|
|
||||||
|
The security boundary is therefore **unauthenticated network traffic vs. those
|
||||||
|
trusted inputs.** A bug that lets an unauthenticated attacker cross it is a
|
||||||
|
security bug.
|
||||||
|
|
||||||
|
## Config authors are host-equivalent by design
|
||||||
|
|
||||||
|
Anyone who can supply or edit a configuration is **trusted with full code
|
||||||
|
execution on the host that runs `esphome`**, on purpose. This is what the product
|
||||||
|
does, not a flaw. A config author can already, through fully supported features:
|
||||||
|
|
||||||
|
- Run arbitrary **Python** at validation/compile time via `external_components:`
|
||||||
|
(and other component-import mechanisms) — ESPHome imports those packages as
|
||||||
|
ordinary Python.
|
||||||
|
- Run arbitrary **shell** commands through the compile/validate/flash toolchain
|
||||||
|
that ESPHome invokes as subprocesses.
|
||||||
|
- Read and write arbitrary files reachable by the process (e.g. via `!include`,
|
||||||
|
`packages:`, `dashboard_import:`, and generated build output).
|
||||||
|
|
||||||
|
Because of this, a malicious config author is equivalent to shell access on the
|
||||||
|
host running the build.
|
||||||
|
|
||||||
|
## What is *not* a security vulnerability
|
||||||
|
|
||||||
|
If exploiting an issue requires the ability to supply or edit configuration, it
|
||||||
|
is **not** a vulnerability in ESPHome, because that ability already grants host
|
||||||
|
code execution. This explicitly includes, among others:
|
||||||
|
|
||||||
|
- Template / expression injection in substitutions or any YAML string value
|
||||||
|
(e.g. Jinja `${...}` evaluation reaching Python internals). This grants no
|
||||||
|
capability a config author lacks.
|
||||||
|
- `!include` / `packages:` / `dashboard_import:` reading or fetching content
|
||||||
|
from surprising or remote locations.
|
||||||
|
- The validator or compiler crashing or behaving unexpectedly on adversarial
|
||||||
|
YAML.
|
||||||
|
- ESPHome running as root in the official container — that is the documented
|
||||||
|
deployment posture, reachable by the same caller through the features above.
|
||||||
|
|
||||||
|
These do not warrant a CVE or coordinated disclosure. Hardening in these areas
|
||||||
|
(for example, sandboxing template evaluation as least-surprise defense-in-depth)
|
||||||
|
is welcome as a normal enhancement PR, framed as cleanliness rather than a
|
||||||
|
security fix — not as a vulnerability remediation.
|
||||||
|
|
||||||
|
## What we do defend
|
||||||
|
|
||||||
|
These *are* security bugs in this repo, and we want to hear about them privately:
|
||||||
|
|
||||||
|
- Memory-safety or protocol bugs in the generated **device firmware** that are
|
||||||
|
remotely triggerable over the network (native API, web server, OTA, BLE,
|
||||||
|
captive portal, etc.) **without** valid credentials.
|
||||||
|
- Authentication or encryption bypass on the device — reaching API calls, OTA
|
||||||
|
updates, or the web server without the configured key/password.
|
||||||
|
- Flaws that weaken the device's API encryption (Noise), OTA, or web server auth
|
||||||
|
below their documented guarantees.
|
||||||
|
|
||||||
|
## Explicitly out of scope
|
||||||
|
|
||||||
|
- Local attackers who already have shell access on the host that runs `esphome`.
|
||||||
|
- Supply-chain attacks against ESPHome or its dependencies.
|
||||||
|
- Operator-supplied hostile YAML (covered above — config authoring is trusted).
|
||||||
|
- Attacks that require an already-authenticated device peer (someone who already
|
||||||
|
holds the API key / OTA / web credentials).
|
||||||
|
- Anything in the dashboard / device-builder — report that in its own repository
|
||||||
|
(linked at the top).
|
||||||
|
- The legacy bundled dashboard in this repo (`esphome/dashboard/`) — it is
|
||||||
|
deprecated and being replaced by Device Builder; report dashboard issues there.
|
||||||
|
- Deployments where the operator removed protections or exposed credentials. See
|
||||||
|
the security best practices guide:
|
||||||
|
https://esphome.io/guides/security_best_practices/
|
||||||
|
|
||||||
|
## Reporting a vulnerability
|
||||||
|
|
||||||
|
If you believe you've found an issue that crosses the unauthenticated boundary
|
||||||
|
above, please report it privately via GitHub Security Advisories rather than a
|
||||||
|
public issue. For issues that require config-write access, please review this
|
||||||
|
document first — they are very likely out of scope by design. For dashboard /
|
||||||
|
device-builder issues, report against that repository and consult its threat
|
||||||
|
model (linked at the top).
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
ARG BUILD_VERSION=dev
|
ARG BUILD_VERSION=dev
|
||||||
ARG BUILD_OS=alpine
|
ARG BUILD_BASE_VERSION=2026.06.0
|
||||||
ARG BUILD_BASE_VERSION=2025.04.0
|
|
||||||
ARG BUILD_TYPE=docker
|
ARG BUILD_TYPE=docker
|
||||||
|
|
||||||
FROM ghcr.io/esphome/docker-base:${BUILD_OS}-${BUILD_BASE_VERSION} AS base-source-docker
|
FROM ghcr.io/esphome/docker-base:debian-${BUILD_BASE_VERSION} AS base-source-docker
|
||||||
FROM ghcr.io/esphome/docker-base:${BUILD_OS}-ha-addon-${BUILD_BASE_VERSION} AS base-source-ha-addon
|
FROM ghcr.io/esphome/docker-base:debian-ha-addon-${BUILD_BASE_VERSION} AS base-source-ha-addon
|
||||||
|
|
||||||
ARG BUILD_TYPE
|
ARG BUILD_TYPE
|
||||||
FROM base-source-${BUILD_TYPE} AS base
|
FROM base-source-${BUILD_TYPE} AS base
|
||||||
@@ -18,13 +17,9 @@ RUN git config --system --add safe.directory "*" \
|
|||||||
# validate openocd-esp32 (it dynamically links libusb-1.0.so.0); without
|
# validate openocd-esp32 (it dynamically links libusb-1.0.so.0); without
|
||||||
# it idf_tools.py rejects the openocd install with exit 127 and aborts
|
# it idf_tools.py rejects the openocd install with exit 127 and aborts
|
||||||
# the whole framework setup.
|
# the whole framework setup.
|
||||||
RUN if command -v apk > /dev/null; then \
|
RUN apt-get update \
|
||||||
apk add --no-cache build-base libusb; \
|
|
||||||
else \
|
|
||||||
apt-get update \
|
|
||||||
&& apt-get install -y --no-install-recommends build-essential libusb-1.0-0 \
|
&& apt-get install -y --no-install-recommends build-essential libusb-1.0-0 \
|
||||||
&& rm -rf /var/lib/apt/lists/*; \
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
fi
|
|
||||||
|
|
||||||
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
|
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
|
||||||
|
|
||||||
@@ -36,6 +31,9 @@ RUN \
|
|||||||
uv pip install --no-cache-dir \
|
uv pip install --no-cache-dir \
|
||||||
-r /requirements.txt
|
-r /requirements.txt
|
||||||
|
|
||||||
|
# Install the ESPHome Device Builder dashboard.
|
||||||
|
RUN uv pip install --no-cache-dir esphome-device-builder==1.0.12
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
platformio settings set enable_telemetry No \
|
platformio settings set enable_telemetry No \
|
||||||
&& platformio settings set check_platformio_interval 1000000 \
|
&& platformio settings set check_platformio_interval 1000000 \
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ TYPE_HA_ADDON = "ha-addon"
|
|||||||
TYPE_LINT = "lint"
|
TYPE_LINT = "lint"
|
||||||
TYPES = [TYPE_DOCKER, TYPE_HA_ADDON, TYPE_LINT]
|
TYPES = [TYPE_DOCKER, TYPE_HA_ADDON, TYPE_LINT]
|
||||||
|
|
||||||
|
REGISTRY_GHCR = "ghcr"
|
||||||
|
REGISTRY_DOCKERHUB = "dockerhub"
|
||||||
|
REGISTRIES = [REGISTRY_GHCR, REGISTRY_DOCKERHUB]
|
||||||
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@@ -34,6 +38,12 @@ parser.add_argument(
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--build-type", choices=TYPES, required=True, help="The type of build to run"
|
"--build-type", choices=TYPES, required=True, help="The type of build to run"
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--registry",
|
||||||
|
choices=REGISTRIES,
|
||||||
|
action="append",
|
||||||
|
help="Restrict to specific registries (default: all). May be passed multiple times.",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--dry-run", action="store_true", help="Don't run any commands, just print them"
|
"--dry-run", action="store_true", help="Don't run any commands, just print them"
|
||||||
)
|
)
|
||||||
@@ -45,6 +55,11 @@ build_parser.add_argument("--push", help="Also push the images", action="store_t
|
|||||||
build_parser.add_argument(
|
build_parser.add_argument(
|
||||||
"--load", help="Load the docker image locally", action="store_true"
|
"--load", help="Load the docker image locally", action="store_true"
|
||||||
)
|
)
|
||||||
|
build_parser.add_argument(
|
||||||
|
"--no-cache-to",
|
||||||
|
help="Don't write the build cache (avoids polluting the shared cache)",
|
||||||
|
action="store_true",
|
||||||
|
)
|
||||||
manifest_parser = subparsers.add_parser(
|
manifest_parser = subparsers.add_parser(
|
||||||
"manifest", help="Create a manifest from already pushed images"
|
"manifest", help="Create a manifest from already pushed images"
|
||||||
)
|
)
|
||||||
@@ -95,11 +110,14 @@ def main():
|
|||||||
print("Command failed")
|
print("Command failed")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
registries = args.registry or REGISTRIES
|
||||||
|
|
||||||
# detect channel from tag
|
# detect channel from tag
|
||||||
match = re.match(r"^(\d+\.\d+)(?:\.\d+)?(b\d+)?$", args.tag)
|
match = re.match(r"^(\d+\.\d+)(?:\.\d+)?(b\d+)?$", args.tag)
|
||||||
major_minor_version = None
|
major_minor_version = None
|
||||||
if match is None:
|
if match is None:
|
||||||
channel = CHANNEL_DEV
|
# Custom tag (e.g. a branch name) -- push only the tag itself
|
||||||
|
channel = None
|
||||||
elif match.group(2) is None:
|
elif match.group(2) is None:
|
||||||
major_minor_version = match.group(1)
|
major_minor_version = match.group(1)
|
||||||
channel = CHANNEL_RELEASE
|
channel = CHANNEL_RELEASE
|
||||||
@@ -128,10 +146,17 @@ def main():
|
|||||||
CHANNEL_DEV: "cache-dev",
|
CHANNEL_DEV: "cache-dev",
|
||||||
CHANNEL_BETA: "cache-beta",
|
CHANNEL_BETA: "cache-beta",
|
||||||
CHANNEL_RELEASE: "cache-latest",
|
CHANNEL_RELEASE: "cache-latest",
|
||||||
}[channel]
|
}.get(channel, "cache-dev")
|
||||||
cache_img = f"ghcr.io/{params.build_to}:{cache_tag}"
|
# Cache images live alongside the pushed images; prefer GHCR when it is
|
||||||
|
# one of the selected registries, otherwise fall back to Docker Hub so a
|
||||||
|
# registry-restricted build doesn't need GHCR auth.
|
||||||
|
cache_prefix = "ghcr.io/" if REGISTRY_GHCR in registries else ""
|
||||||
|
cache_img = f"{cache_prefix}{params.build_to}:{cache_tag}"
|
||||||
|
|
||||||
imgs = [f"{params.build_to}:{tag}" for tag in tags_to_push]
|
imgs = []
|
||||||
|
if REGISTRY_DOCKERHUB in registries:
|
||||||
|
imgs += [f"{params.build_to}:{tag}" for tag in tags_to_push]
|
||||||
|
if REGISTRY_GHCR in registries:
|
||||||
imgs += [f"ghcr.io/{params.build_to}:{tag}" for tag in tags_to_push]
|
imgs += [f"ghcr.io/{params.build_to}:{tag}" for tag in tags_to_push]
|
||||||
|
|
||||||
# 3. build
|
# 3. build
|
||||||
@@ -155,7 +180,9 @@ def main():
|
|||||||
for img in imgs:
|
for img in imgs:
|
||||||
cmd += ["--tag", img]
|
cmd += ["--tag", img]
|
||||||
if args.push:
|
if args.push:
|
||||||
cmd += ["--push", "--cache-to", f"type=registry,ref={cache_img},mode=max"]
|
cmd += ["--push"]
|
||||||
|
if not args.no_cache_to:
|
||||||
|
cmd += ["--cache-to", f"type=registry,ref={cache_img},mode=max"]
|
||||||
if args.load:
|
if args.load:
|
||||||
cmd += ["--load"]
|
cmd += ["--load"]
|
||||||
|
|
||||||
@@ -163,20 +190,22 @@ def main():
|
|||||||
elif args.command == "manifest":
|
elif args.command == "manifest":
|
||||||
manifest = DockerParams.for_type_arch(args.build_type, ARCH_AMD64).manifest_to
|
manifest = DockerParams.for_type_arch(args.build_type, ARCH_AMD64).manifest_to
|
||||||
|
|
||||||
targets = [f"{manifest}:{tag}" for tag in tags_to_push]
|
targets = []
|
||||||
|
if REGISTRY_DOCKERHUB in registries:
|
||||||
|
targets += [f"{manifest}:{tag}" for tag in tags_to_push]
|
||||||
|
if REGISTRY_GHCR in registries:
|
||||||
targets += [f"ghcr.io/{manifest}:{tag}" for tag in tags_to_push]
|
targets += [f"ghcr.io/{manifest}:{tag}" for tag in tags_to_push]
|
||||||
# 1. Create manifests
|
# Use buildx imagetools (not `docker manifest`) so the per-arch sources,
|
||||||
|
# which buildx pushes as single-platform manifest lists, are combined
|
||||||
|
# and pushed correctly in one step.
|
||||||
for target in targets:
|
for target in targets:
|
||||||
cmd = ["docker", "manifest", "create", target]
|
cmd = ["docker", "buildx", "imagetools", "create", "--tag", target]
|
||||||
for arch in ARCHS:
|
for arch in ARCHS:
|
||||||
src = f"{DockerParams.for_type_arch(args.build_type, arch).build_to}:{args.tag}"
|
src = f"{DockerParams.for_type_arch(args.build_type, arch).build_to}:{args.tag}"
|
||||||
if target.startswith("ghcr.io"):
|
if target.startswith("ghcr.io"):
|
||||||
src = f"ghcr.io/{src}"
|
src = f"ghcr.io/{src}"
|
||||||
cmd.append(src)
|
cmd.append(src)
|
||||||
run_command(*cmd)
|
run_command(*cmd)
|
||||||
# 2. Push manifests
|
|
||||||
for target in targets:
|
|
||||||
run_command("docker", "manifest", "push", target)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -27,4 +27,12 @@ if [[ -d /build ]]; then
|
|||||||
export ESPHOME_BUILD_PATH=/build
|
export ESPHOME_BUILD_PATH=/build
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# The default CMD is "dashboard /config". Route the dashboard to the new
|
||||||
|
# Device Builder, but pass every other subcommand (compile, run, config,
|
||||||
|
# logs, ...) straight through to the esphome CLI so direct CLI use keeps working.
|
||||||
|
if [[ "$1" == "dashboard" ]]; then
|
||||||
|
shift
|
||||||
|
exec esphome-device-builder "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
exec esphome "$@"
|
exec esphome "$@"
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
#!/usr/bin/with-contenv bashio
|
|
||||||
# ==============================================================================
|
|
||||||
# Installs the latest prerelease of esphome-device-builder when the
|
|
||||||
# `use_new_device_builder` config option is enabled.
|
|
||||||
# This is a temporary install-on-boot step until esphome-device-builder
|
|
||||||
# becomes a direct dependency of esphome.
|
|
||||||
# ==============================================================================
|
|
||||||
|
|
||||||
if ! bashio::config.true 'use_new_device_builder'; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
bashio::log.info "Installing latest prerelease of esphome-device-builder..."
|
|
||||||
if command -v uv > /dev/null; then
|
|
||||||
uv pip install --system --no-cache-dir --prerelease=allow --upgrade \
|
|
||||||
esphome-device-builder ||
|
|
||||||
bashio::exit.nok "Failed installing esphome-device-builder."
|
|
||||||
else
|
|
||||||
pip install --no-cache-dir --pre --upgrade esphome-device-builder ||
|
|
||||||
bashio::exit.nok "Failed installing esphome-device-builder."
|
|
||||||
fi
|
|
||||||
bashio::log.info "Installed esphome-device-builder."
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
types {
|
|
||||||
text/html html htm shtml;
|
|
||||||
text/css css;
|
|
||||||
text/xml xml;
|
|
||||||
image/gif gif;
|
|
||||||
image/jpeg jpeg jpg;
|
|
||||||
application/javascript js;
|
|
||||||
application/atom+xml atom;
|
|
||||||
application/rss+xml rss;
|
|
||||||
|
|
||||||
text/mathml mml;
|
|
||||||
text/plain txt;
|
|
||||||
text/vnd.sun.j2me.app-descriptor jad;
|
|
||||||
text/vnd.wap.wml wml;
|
|
||||||
text/x-component htc;
|
|
||||||
|
|
||||||
image/png png;
|
|
||||||
image/svg+xml svg svgz;
|
|
||||||
image/tiff tif tiff;
|
|
||||||
image/vnd.wap.wbmp wbmp;
|
|
||||||
image/webp webp;
|
|
||||||
image/x-icon ico;
|
|
||||||
image/x-jng jng;
|
|
||||||
image/x-ms-bmp bmp;
|
|
||||||
|
|
||||||
font/woff woff;
|
|
||||||
font/woff2 woff2;
|
|
||||||
|
|
||||||
application/java-archive jar war ear;
|
|
||||||
application/json json;
|
|
||||||
application/mac-binhex40 hqx;
|
|
||||||
application/msword doc;
|
|
||||||
application/pdf pdf;
|
|
||||||
application/postscript ps eps ai;
|
|
||||||
application/rtf rtf;
|
|
||||||
application/vnd.apple.mpegurl m3u8;
|
|
||||||
application/vnd.google-earth.kml+xml kml;
|
|
||||||
application/vnd.google-earth.kmz kmz;
|
|
||||||
application/vnd.ms-excel xls;
|
|
||||||
application/vnd.ms-fontobject eot;
|
|
||||||
application/vnd.ms-powerpoint ppt;
|
|
||||||
application/vnd.oasis.opendocument.graphics odg;
|
|
||||||
application/vnd.oasis.opendocument.presentation odp;
|
|
||||||
application/vnd.oasis.opendocument.spreadsheet ods;
|
|
||||||
application/vnd.oasis.opendocument.text odt;
|
|
||||||
application/vnd.openxmlformats-officedocument.presentationml.presentation
|
|
||||||
pptx;
|
|
||||||
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
|
||||||
xlsx;
|
|
||||||
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
|
||||||
docx;
|
|
||||||
application/vnd.wap.wmlc wmlc;
|
|
||||||
application/x-7z-compressed 7z;
|
|
||||||
application/x-cocoa cco;
|
|
||||||
application/x-java-archive-diff jardiff;
|
|
||||||
application/x-java-jnlp-file jnlp;
|
|
||||||
application/x-makeself run;
|
|
||||||
application/x-perl pl pm;
|
|
||||||
application/x-pilot prc pdb;
|
|
||||||
application/x-rar-compressed rar;
|
|
||||||
application/x-redhat-package-manager rpm;
|
|
||||||
application/x-sea sea;
|
|
||||||
application/x-shockwave-flash swf;
|
|
||||||
application/x-stuffit sit;
|
|
||||||
application/x-tcl tcl tk;
|
|
||||||
application/x-x509-ca-cert der pem crt;
|
|
||||||
application/x-xpinstall xpi;
|
|
||||||
application/xhtml+xml xhtml;
|
|
||||||
application/xspf+xml xspf;
|
|
||||||
application/zip zip;
|
|
||||||
|
|
||||||
application/octet-stream bin exe dll;
|
|
||||||
application/octet-stream deb;
|
|
||||||
application/octet-stream dmg;
|
|
||||||
application/octet-stream iso img;
|
|
||||||
application/octet-stream msi msp msm;
|
|
||||||
|
|
||||||
audio/midi mid midi kar;
|
|
||||||
audio/mpeg mp3;
|
|
||||||
audio/ogg ogg;
|
|
||||||
audio/x-m4a m4a;
|
|
||||||
audio/x-realaudio ra;
|
|
||||||
|
|
||||||
video/3gpp 3gpp 3gp;
|
|
||||||
video/mp2t ts;
|
|
||||||
video/mp4 mp4;
|
|
||||||
video/mpeg mpeg mpg;
|
|
||||||
video/quicktime mov;
|
|
||||||
video/webm webm;
|
|
||||||
video/x-flv flv;
|
|
||||||
video/x-m4v m4v;
|
|
||||||
video/x-mng mng;
|
|
||||||
video/x-ms-asf asx asf;
|
|
||||||
video/x-ms-wmv wmv;
|
|
||||||
video/x-msvideo avi;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
proxy_http_version 1.1;
|
|
||||||
proxy_ignore_client_abort off;
|
|
||||||
proxy_read_timeout 86400s;
|
|
||||||
proxy_redirect off;
|
|
||||||
proxy_send_timeout 86400s;
|
|
||||||
proxy_max_temp_file_size 0;
|
|
||||||
|
|
||||||
proxy_set_header Accept-Encoding "";
|
|
||||||
proxy_set_header Connection $connection_upgrade;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
proxy_set_header X-NginX-Proxy true;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header Authorization "";
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
root /dev/null;
|
|
||||||
server_name $hostname;
|
|
||||||
|
|
||||||
client_max_body_size 512m;
|
|
||||||
|
|
||||||
add_header X-Content-Type-Options nosniff;
|
|
||||||
add_header X-XSS-Protection "1; mode=block";
|
|
||||||
add_header X-Robots-Tag none;
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
ssl_protocols TLSv1.2 TLSv1.3;
|
|
||||||
ssl_prefer_server_ciphers off;
|
|
||||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
|
||||||
ssl_session_timeout 10m;
|
|
||||||
ssl_session_cache shared:SSL:10m;
|
|
||||||
ssl_session_tickets off;
|
|
||||||
ssl_stapling on;
|
|
||||||
ssl_stapling_verify on;
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
upstream esphome {
|
|
||||||
server unix:/var/run/esphome.sock;
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
daemon off;
|
|
||||||
user root;
|
|
||||||
pid /var/run/nginx.pid;
|
|
||||||
worker_processes 1;
|
|
||||||
error_log /proc/1/fd/1 error;
|
|
||||||
events {
|
|
||||||
worker_connections 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
http {
|
|
||||||
include /etc/nginx/includes/mime.types;
|
|
||||||
|
|
||||||
access_log off;
|
|
||||||
default_type application/octet-stream;
|
|
||||||
gzip on;
|
|
||||||
keepalive_timeout 65;
|
|
||||||
sendfile on;
|
|
||||||
server_tokens off;
|
|
||||||
|
|
||||||
tcp_nodelay on;
|
|
||||||
tcp_nopush on;
|
|
||||||
|
|
||||||
map $http_upgrade $connection_upgrade {
|
|
||||||
default upgrade;
|
|
||||||
'' close;
|
|
||||||
}
|
|
||||||
|
|
||||||
include /etc/nginx/includes/upstream.conf;
|
|
||||||
include /etc/nginx/servers/*.conf;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Without requirements or design, programming is the art of adding bugs to an empty text file. (Louis Srygley)
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
server {
|
|
||||||
{{ if not .ssl }}
|
|
||||||
listen 6052 default_server;
|
|
||||||
{{ else }}
|
|
||||||
listen 6052 default_server ssl http2;
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
include /etc/nginx/includes/server_params.conf;
|
|
||||||
include /etc/nginx/includes/proxy_params.conf;
|
|
||||||
|
|
||||||
{{ if .ssl }}
|
|
||||||
include /etc/nginx/includes/ssl_params.conf;
|
|
||||||
|
|
||||||
ssl_certificate /ssl/{{ .certfile }};
|
|
||||||
ssl_certificate_key /ssl/{{ .keyfile }};
|
|
||||||
|
|
||||||
# Redirect http requests to https on the same port.
|
|
||||||
# https://rageagainstshell.com/2016/11/redirect-http-to-https-on-the-same-port-in-nginx/
|
|
||||||
error_page 497 https://$http_host$request_uri;
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
# Clear Home Assistant Ingress header
|
|
||||||
proxy_set_header X-HA-Ingress "";
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://esphome;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
server {
|
|
||||||
listen 127.0.0.1:{{ .port }} default_server;
|
|
||||||
listen {{ .interface }}:{{ .port }} default_server;
|
|
||||||
|
|
||||||
include /etc/nginx/includes/server_params.conf;
|
|
||||||
include /etc/nginx/includes/proxy_params.conf;
|
|
||||||
|
|
||||||
# Set Home Assistant Ingress header
|
|
||||||
proxy_set_header X-HA-Ingress "YES";
|
|
||||||
|
|
||||||
location / {
|
|
||||||
allow 172.30.32.2;
|
|
||||||
allow 127.0.0.1;
|
|
||||||
deny all;
|
|
||||||
|
|
||||||
proxy_pass http://esphome;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,7 +16,7 @@ fi
|
|||||||
|
|
||||||
port=$(bashio::addon.ingress_port)
|
port=$(bashio::addon.ingress_port)
|
||||||
|
|
||||||
# Wait for NGINX to become available
|
# Wait for the ESPHome Device Builder to become available
|
||||||
bashio::net.wait_for "${port}" "127.0.0.1" 300
|
bashio::net.wait_for "${port}" "127.0.0.1" 300
|
||||||
|
|
||||||
config=$(\
|
config=$(\
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# shellcheck shell=bash
|
# shellcheck shell=bash
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# Home Assistant Community Add-on: ESPHome
|
# Home Assistant Community Add-on: ESPHome
|
||||||
# Take down the S6 supervision tree when ESPHome dashboard fails
|
# Take down the S6 supervision tree when ESPHome Device Builder fails
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
declare exit_code
|
declare exit_code
|
||||||
readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
|
readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
|
||||||
@@ -10,7 +10,7 @@ readonly exit_code_service="${1}"
|
|||||||
readonly exit_code_signal="${2}"
|
readonly exit_code_signal="${2}"
|
||||||
|
|
||||||
bashio::log.info \
|
bashio::log.info \
|
||||||
"Service ESPHome dashboard exited with code ${exit_code_service}" \
|
"Service ESPHome Device Builder exited with code ${exit_code_service}" \
|
||||||
"(by signal ${exit_code_signal})"
|
"(by signal ${exit_code_signal})"
|
||||||
|
|
||||||
if [[ "${exit_code_service}" -eq 256 ]]; then
|
if [[ "${exit_code_service}" -eq 256 ]]; then
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# shellcheck shell=bash
|
# shellcheck shell=bash
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# Community Hass.io Add-ons: ESPHome
|
# Community Hass.io Add-ons: ESPHome
|
||||||
# Runs the ESPHome dashboard
|
# Runs the ESPHome Device Builder
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
readonly pio_cache_base=/data/cache/platformio
|
readonly pio_cache_base=/data/cache/platformio
|
||||||
|
|
||||||
@@ -49,12 +49,21 @@ if bashio::fs.directory_exists '/config/esphome/.esphome'; then
|
|||||||
rm -rf /config/esphome/.esphome
|
rm -rf /config/esphome/.esphome
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if bashio::config.true 'use_new_device_builder'; then
|
# Only signal device-builder to expose the public LAN port when the operator
|
||||||
|
# mapped port 6052, matching the legacy dashboard where nginx listened on the
|
||||||
|
# fixed port 6052 only when it was configured. We use the mapping purely as a
|
||||||
|
# presence check and don't forward the published value; device-builder binds
|
||||||
|
# its default port 6052 (the fixed container port, as the legacy
|
||||||
|
# "listen 6052" did). --ha-addon-allow-public is inert on its own: the no-auth
|
||||||
|
# gate is the DISABLE_HA_AUTHENTICATION env var set above, so both opt-ins are
|
||||||
|
# required to bind 6052 unauthenticated; either alone stays ingress-only.
|
||||||
|
set --
|
||||||
|
if bashio::var.has_value "$(bashio::addon.port 6052)"; then
|
||||||
|
set -- --ha-addon-allow-public
|
||||||
|
fi
|
||||||
|
|
||||||
bashio::log.info "Starting ESPHome Device Builder..."
|
bashio::log.info "Starting ESPHome Device Builder..."
|
||||||
exec esphome-device-builder /config/esphome \
|
exec esphome-device-builder /config/esphome \
|
||||||
--ha-addon \
|
--ha-addon \
|
||||||
--ingress-port "$(bashio::addon.ingress_port)"
|
--ingress-port "$(bashio::addon.ingress_port)" \
|
||||||
fi
|
"$@"
|
||||||
|
|
||||||
bashio::log.info "Starting ESPHome dashboard..."
|
|
||||||
exec esphome dashboard /config/esphome --socket /var/run/esphome.sock --ha-addon
|
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
#!/command/with-contenv bashio
|
|
||||||
# shellcheck shell=bash
|
|
||||||
# ==============================================================================
|
|
||||||
# Community Hass.io Add-ons: ESPHome
|
|
||||||
# Configures NGINX for use with ESPHome
|
|
||||||
# ==============================================================================
|
|
||||||
|
|
||||||
# When the new device builder is enabled it serves HA ingress directly,
|
|
||||||
# so nginx is not used at all -- skip configuration.
|
|
||||||
if bashio::config.true 'use_new_device_builder'; then
|
|
||||||
bashio::log.info "Skipping NGINX setup: new device builder serves ingress directly."
|
|
||||||
bashio::exit.ok
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p /var/log/nginx
|
|
||||||
|
|
||||||
# Generate Ingress configuration
|
|
||||||
bashio::var.json \
|
|
||||||
interface "$(bashio::addon.ip_address)" \
|
|
||||||
port "^$(bashio::addon.ingress_port)" \
|
|
||||||
| tempio \
|
|
||||||
-template /etc/nginx/templates/ingress.gtpl \
|
|
||||||
-out /etc/nginx/servers/ingress.conf
|
|
||||||
|
|
||||||
# Generate direct access configuration, if enabled.
|
|
||||||
if bashio::var.has_value "$(bashio::addon.port 6052)"; then
|
|
||||||
bashio::config.require.ssl
|
|
||||||
bashio::var.json \
|
|
||||||
certfile "$(bashio::config 'certfile')" \
|
|
||||||
keyfile "$(bashio::config 'keyfile')" \
|
|
||||||
ssl "^$(bashio::config 'ssl')" \
|
|
||||||
| tempio \
|
|
||||||
-template /etc/nginx/templates/direct.gtpl \
|
|
||||||
-out /etc/nginx/servers/direct.conf
|
|
||||||
fi
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
oneshot
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
/etc/s6-overlay/s6-rc.d/init-nginx/run
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#!/command/with-contenv bashio
|
|
||||||
# ==============================================================================
|
|
||||||
# Community Hass.io Add-ons: ESPHome
|
|
||||||
# Take down the S6 supervision tree when NGINX fails
|
|
||||||
# ==============================================================================
|
|
||||||
declare exit_code
|
|
||||||
readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
|
|
||||||
readonly exit_code_service="${1}"
|
|
||||||
readonly exit_code_signal="${2}"
|
|
||||||
|
|
||||||
bashio::log.info \
|
|
||||||
"Service NGINX exited with code ${exit_code_service}" \
|
|
||||||
"(by signal ${exit_code_signal})"
|
|
||||||
|
|
||||||
if [[ "${exit_code_service}" -eq 256 ]]; then
|
|
||||||
if [[ "${exit_code_container}" -eq 0 ]]; then
|
|
||||||
echo $((128 + $exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
|
|
||||||
fi
|
|
||||||
[[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
|
|
||||||
elif [[ "${exit_code_service}" -ne 0 ]]; then
|
|
||||||
if [[ "${exit_code_container}" -eq 0 ]]; then
|
|
||||||
echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
|
|
||||||
fi
|
|
||||||
exec /run/s6/basedir/bin/halt
|
|
||||||
fi
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#!/command/with-contenv bashio
|
|
||||||
# shellcheck shell=bash
|
|
||||||
# ==============================================================================
|
|
||||||
# Community Hass.io Add-ons: ESPHome
|
|
||||||
# Runs the NGINX proxy
|
|
||||||
# ==============================================================================
|
|
||||||
|
|
||||||
# The new device builder handles HA ingress itself, so nginx is bypassed.
|
|
||||||
# Block the longrun so s6 keeps the dependency satisfied, but exit 0 on
|
|
||||||
# SIGTERM instead of being signal-killed; a 256/15 exit makes nginx/finish
|
|
||||||
# stamp the container exit 143, which trips the Supervisor's SIGTERM check.
|
|
||||||
if bashio::config.true 'use_new_device_builder'; then
|
|
||||||
bashio::log.info "NGINX bypassed: new device builder serves ingress directly."
|
|
||||||
trap 'exit 0' TERM
|
|
||||||
sleep infinity &
|
|
||||||
wait
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
bashio::log.info "Waiting for ESPHome dashboard to come up..."
|
|
||||||
|
|
||||||
while [[ ! -S /var/run/esphome.sock ]]; do
|
|
||||||
sleep 0.5
|
|
||||||
done
|
|
||||||
|
|
||||||
bashio::log.info "Starting NGINX..."
|
|
||||||
exec nginx
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
longrun
|
|
||||||
7
docker/test_configs/bk72xx-arduino.yaml
Normal file
7
docker/test_configs/bk72xx-arduino.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
esphome:
|
||||||
|
name: docker-test-bk72xx-arduino
|
||||||
|
|
||||||
|
bk72xx:
|
||||||
|
board: generic-bk7231n-qfn32-tuya
|
||||||
|
|
||||||
|
logger:
|
||||||
10
docker/test_configs/esp32-arduino-esp-idf.yaml
Normal file
10
docker/test_configs/esp32-arduino-esp-idf.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
esphome:
|
||||||
|
name: docker-test-esp32-ard-idf
|
||||||
|
|
||||||
|
esp32:
|
||||||
|
variant: esp32
|
||||||
|
framework:
|
||||||
|
type: arduino
|
||||||
|
toolchain: esp-idf
|
||||||
|
|
||||||
|
logger:
|
||||||
10
docker/test_configs/esp32-arduino-platformio.yaml
Normal file
10
docker/test_configs/esp32-arduino-platformio.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
esphome:
|
||||||
|
name: docker-test-esp32-ard-pio
|
||||||
|
|
||||||
|
esp32:
|
||||||
|
variant: esp32
|
||||||
|
framework:
|
||||||
|
type: arduino
|
||||||
|
toolchain: platformio
|
||||||
|
|
||||||
|
logger:
|
||||||
10
docker/test_configs/esp32-idf-esp-idf.yaml
Normal file
10
docker/test_configs/esp32-idf-esp-idf.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
esphome:
|
||||||
|
name: docker-test-esp32-idf-idf
|
||||||
|
|
||||||
|
esp32:
|
||||||
|
variant: esp32
|
||||||
|
framework:
|
||||||
|
type: esp-idf
|
||||||
|
toolchain: esp-idf
|
||||||
|
|
||||||
|
logger:
|
||||||
10
docker/test_configs/esp32-idf-platformio.yaml
Normal file
10
docker/test_configs/esp32-idf-platformio.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
esphome:
|
||||||
|
name: docker-test-esp32-idf-pio
|
||||||
|
|
||||||
|
esp32:
|
||||||
|
variant: esp32
|
||||||
|
framework:
|
||||||
|
type: esp-idf
|
||||||
|
toolchain: platformio
|
||||||
|
|
||||||
|
logger:
|
||||||
7
docker/test_configs/esp8266-arduino.yaml
Normal file
7
docker/test_configs/esp8266-arduino.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
esphome:
|
||||||
|
name: docker-test-esp8266-arduino
|
||||||
|
|
||||||
|
esp8266:
|
||||||
|
board: d1_mini
|
||||||
|
|
||||||
|
logger:
|
||||||
6
docker/test_configs/host.yaml
Normal file
6
docker/test_configs/host.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
esphome:
|
||||||
|
name: docker-test-host
|
||||||
|
|
||||||
|
host:
|
||||||
|
|
||||||
|
logger:
|
||||||
7
docker/test_configs/ln882x-arduino.yaml
Normal file
7
docker/test_configs/ln882x-arduino.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
esphome:
|
||||||
|
name: docker-test-ln882x-arduino
|
||||||
|
|
||||||
|
ln882x:
|
||||||
|
board: generic-ln882hki
|
||||||
|
|
||||||
|
logger:
|
||||||
8
docker/test_configs/nrf52.yaml
Normal file
8
docker/test_configs/nrf52.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
esphome:
|
||||||
|
name: docker-test-nrf52
|
||||||
|
|
||||||
|
nrf52:
|
||||||
|
board: adafruit_itsybitsy_nrf52840
|
||||||
|
bootloader: adafruit_nrf52_sd140_v6
|
||||||
|
|
||||||
|
logger:
|
||||||
7
docker/test_configs/rp2040-arduino.yaml
Normal file
7
docker/test_configs/rp2040-arduino.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
esphome:
|
||||||
|
name: docker-test-rp2040-arduino
|
||||||
|
|
||||||
|
rp2040:
|
||||||
|
variant: rp2040
|
||||||
|
|
||||||
|
logger:
|
||||||
7
docker/test_configs/rtl87xx-arduino.yaml
Normal file
7
docker/test_configs/rtl87xx-arduino.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
esphome:
|
||||||
|
name: docker-test-rtl87xx-arduino
|
||||||
|
|
||||||
|
rtl87xx:
|
||||||
|
board: generic-rtl8710bn-2mb-788k
|
||||||
|
|
||||||
|
logger:
|
||||||
@@ -504,6 +504,12 @@ def has_resolvable_address() -> bool:
|
|||||||
if has_ip_address():
|
if has_ip_address():
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# The dashboard pre-resolves the device and passes the IPs via
|
||||||
|
# --mdns-address-cache/--dns-address-cache; honor a cached address even when the
|
||||||
|
# device has mDNS disabled (e.g. a .local host found via ping).
|
||||||
|
if CORE.address_cache and CORE.address_cache.get_addresses(CORE.address):
|
||||||
|
return True
|
||||||
|
|
||||||
if has_mdns():
|
if has_mdns():
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -1765,6 +1771,21 @@ def command_update_all(args: ArgsProtocol) -> int | None:
|
|||||||
def command_idedata(args: ArgsProtocol, config: ConfigType) -> int:
|
def command_idedata(args: ArgsProtocol, config: ConfigType) -> int:
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
if CORE.using_toolchain_esp_idf:
|
||||||
|
# Native ESP-IDF derives idedata from the build's compile_commands.json,
|
||||||
|
# so the configuration must already be compiled.
|
||||||
|
from esphome.espidf import toolchain as espidf_toolchain
|
||||||
|
|
||||||
|
idedata = espidf_toolchain.get_idedata()
|
||||||
|
if idedata is None:
|
||||||
|
_LOGGER.error(
|
||||||
|
"No idedata available; compile the configuration first",
|
||||||
|
)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
print(json.dumps(idedata, indent=2) + "\n")
|
||||||
|
return 0
|
||||||
|
|
||||||
if not CORE.using_toolchain_platformio:
|
if not CORE.using_toolchain_platformio:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"The idedata command is not compatible with %s toolchain",
|
"The idedata command is not compatible with %s toolchain",
|
||||||
|
|||||||
@@ -6,8 +6,20 @@ from pathlib import Path
|
|||||||
from esphome.components.esp32 import get_esp32_variant, idf_version
|
from esphome.components.esp32 import get_esp32_variant, idf_version
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.core import CORE
|
from esphome.core import CORE
|
||||||
|
from esphome.framework_helpers import get_project_compile_flags, get_project_link_flags
|
||||||
from esphome.helpers import mkdir_p, write_file_if_changed
|
from esphome.helpers import mkdir_p, write_file_if_changed
|
||||||
|
|
||||||
|
# Replaces the IDF default C++ standard (-std=gnu++2b appended to
|
||||||
|
# CXX_COMPILE_OPTIONS by project.cmake's __build_init) with the one set via
|
||||||
|
# cg.set_cpp_standard(). Emitted between include(project.cmake) and project(),
|
||||||
|
# i.e. after IDF appends its default and before the options are consumed, and
|
||||||
|
# applies project-wide like PlatformIO build_unflags.
|
||||||
|
CPP_STANDARD_TEMPLATE = """\
|
||||||
|
idf_build_get_property(esphome_cxx_compile_options CXX_COMPILE_OPTIONS)
|
||||||
|
list(FILTER esphome_cxx_compile_options EXCLUDE REGEX "^-std=")
|
||||||
|
list(APPEND esphome_cxx_compile_options "-std={standard}")
|
||||||
|
idf_build_set_property(CXX_COMPILE_OPTIONS "${{esphome_cxx_compile_options}}")"""
|
||||||
|
|
||||||
|
|
||||||
def get_available_components() -> list[str] | None:
|
def get_available_components() -> list[str] | None:
|
||||||
"""Get list of built-in ESP-IDF components from project_description.json.
|
"""Get list of built-in ESP-IDF components from project_description.json.
|
||||||
@@ -73,17 +85,18 @@ def get_project_cmakelists(minimal: bool = False) -> str:
|
|||||||
# esphome__micro-mp3) rather than just src/. Required so suppressions
|
# esphome__micro-mp3) rather than just src/. Required so suppressions
|
||||||
# like ``-Wno-error=maybe-uninitialized`` actually silence warnings in
|
# like ``-Wno-error=maybe-uninitialized`` actually silence warnings in
|
||||||
# third-party components we don't author.
|
# third-party components we don't author.
|
||||||
project_compile_opts = [
|
project_compile_opts = get_project_compile_flags()
|
||||||
flag
|
|
||||||
for flag in sorted(CORE.build_flags)
|
|
||||||
if flag.startswith("-D")
|
|
||||||
or (flag.startswith("-W") and not flag.startswith("-Wl,"))
|
|
||||||
]
|
|
||||||
extra_compile_options = "\n".join(
|
extra_compile_options = "\n".join(
|
||||||
f'idf_build_set_property(COMPILE_OPTIONS "{flag}" APPEND)'
|
f'idf_build_set_property(COMPILE_OPTIONS "{flag}" APPEND)'
|
||||||
for flag in project_compile_opts
|
for flag in project_compile_opts
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cpp_standard_options = (
|
||||||
|
CPP_STANDARD_TEMPLATE.format(standard=CORE.cpp_standard)
|
||||||
|
if CORE.cpp_standard
|
||||||
|
else ""
|
||||||
|
)
|
||||||
|
|
||||||
# Per-project list exposed as a CMake variable so converted PIO libs
|
# Per-project list exposed as a CMake variable so converted PIO libs
|
||||||
# can reference ${ESPHOME_PROJECT_MANAGED_COMPONENTS} without baking
|
# can reference ${ESPHOME_PROJECT_MANAGED_COMPONENTS} without baking
|
||||||
# project-specific names into their cached CMakeLists.
|
# project-specific names into their cached CMakeLists.
|
||||||
@@ -140,6 +153,8 @@ set(EXTRA_COMPONENT_DIRS ${{CMAKE_SOURCE_DIR}}/src)
|
|||||||
|
|
||||||
include($ENV{{IDF_PATH}}/tools/cmake/project.cmake)
|
include($ENV{{IDF_PATH}}/tools/cmake/project.cmake)
|
||||||
|
|
||||||
|
{cpp_standard_options}
|
||||||
|
|
||||||
{extra_compile_options}
|
{extra_compile_options}
|
||||||
|
|
||||||
{managed_components_property}
|
{managed_components_property}
|
||||||
@@ -169,8 +184,8 @@ def get_component_cmakelists() -> str:
|
|||||||
# Extract linker options (-Wl, flags). Compile flags (-D, -W) are
|
# Extract linker options (-Wl, flags). Compile flags (-D, -W) are
|
||||||
# emitted project-wide via idf_build_set_property in
|
# emitted project-wide via idf_build_set_property in
|
||||||
# get_project_cmakelists so they reach every component, not just src/.
|
# get_project_cmakelists so they reach every component, not just src/.
|
||||||
link_opts = [flag for flag in CORE.build_flags if flag.startswith("-Wl,")]
|
link_opts = get_project_link_flags()
|
||||||
link_opts_str = "\n ".join(sorted(link_opts)) if link_opts else ""
|
link_opts_str = "\n ".join(link_opts) if link_opts else ""
|
||||||
|
|
||||||
return f"""\
|
return f"""\
|
||||||
# Auto-generated by ESPHome
|
# Auto-generated by ESPHome
|
||||||
@@ -200,9 +215,6 @@ idf_component_register(
|
|||||||
REQUIRES ${{ESPHOME_PROJECT_BUILTIN_COMPONENTS}}
|
REQUIRES ${{ESPHOME_PROJECT_BUILTIN_COMPONENTS}}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Apply C++ standard
|
|
||||||
target_compile_features(${{COMPONENT_LIB}} PUBLIC cxx_std_20)
|
|
||||||
|
|
||||||
# ESPHome linker options
|
# ESPHome linker options
|
||||||
target_link_options(${{COMPONENT_LIB}} PUBLIC
|
target_link_options(${{COMPONENT_LIB}} PUBLIC
|
||||||
{link_opts_str}
|
{link_opts_str}
|
||||||
|
|||||||
@@ -33,12 +33,27 @@ def format_ini(data: dict[str, str | list[str]]) -> str:
|
|||||||
return content
|
return content
|
||||||
|
|
||||||
|
|
||||||
|
# All -std= variants a platform/framework may set by default, in both the GNU
|
||||||
|
# and strict dialects; unflagged so the cg.set_cpp_standard() value is the
|
||||||
|
# only standard left in the build.
|
||||||
|
CPP_STD_VARIANTS = [
|
||||||
|
f"{prefix}{year}"
|
||||||
|
for year in ("11", "14", "17", "20", "23", "26", "2a", "2b", "2c")
|
||||||
|
for prefix in ("gnu++", "c++")
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def get_ini_content():
|
def get_ini_content():
|
||||||
CORE.add_platformio_option(
|
CORE.add_platformio_option(
|
||||||
"lib_deps",
|
"lib_deps",
|
||||||
[x.as_lib_dep for x in CORE.platformio_libraries.values()]
|
[x.as_lib_dep for x in CORE.platformio_libraries.values()]
|
||||||
+ ["${common.lib_deps}"],
|
+ ["${common.lib_deps}"],
|
||||||
)
|
)
|
||||||
|
if CORE.cpp_standard:
|
||||||
|
for variant in CPP_STD_VARIANTS:
|
||||||
|
if variant != CORE.cpp_standard:
|
||||||
|
CORE.add_build_unflag(f"-std={variant}")
|
||||||
|
CORE.add_build_flag(f"-std={CORE.cpp_standard}")
|
||||||
# Sort to avoid changing build flags order
|
# Sort to avoid changing build flags order
|
||||||
CORE.add_platformio_option("build_flags", sorted(CORE.build_flags))
|
CORE.add_platformio_option("build_flags", sorted(CORE.build_flags))
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
namespace esphome::a01nyub {
|
namespace esphome::a01nyub {
|
||||||
|
|
||||||
class A01nyubComponent : public sensor::Sensor, public Component, public uart::UARTDevice {
|
class A01nyubComponent final : public sensor::Sensor, public Component, public uart::UARTDevice {
|
||||||
public:
|
public:
|
||||||
// Nothing really public.
|
// Nothing really public.
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
namespace esphome::a02yyuw {
|
namespace esphome::a02yyuw {
|
||||||
|
|
||||||
class A02yyuwComponent : public sensor::Sensor, public Component, public uart::UARTDevice {
|
class A02yyuwComponent final : public sensor::Sensor, public Component, public uart::UARTDevice {
|
||||||
public:
|
public:
|
||||||
// Nothing really public.
|
// Nothing really public.
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace esphome::a4988 {
|
namespace esphome::a4988 {
|
||||||
|
|
||||||
class A4988 : public stepper::Stepper, public Component {
|
class A4988 final : public stepper::Stepper, public Component {
|
||||||
public:
|
public:
|
||||||
void set_step_pin(GPIOPin *step_pin) { step_pin_ = step_pin; }
|
void set_step_pin(GPIOPin *step_pin) { step_pin_ = step_pin; }
|
||||||
void set_dir_pin(GPIOPin *dir_pin) { dir_pin_ = dir_pin; }
|
void set_dir_pin(GPIOPin *dir_pin) { dir_pin_ = dir_pin; }
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ enum SaturationVaporPressureEquation {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// This class implements calculation of absolute humidity from temperature and relative humidity.
|
/// This class implements calculation of absolute humidity from temperature and relative humidity.
|
||||||
class AbsoluteHumidityComponent : public sensor::Sensor, public Component {
|
class AbsoluteHumidityComponent final : public sensor::Sensor, public Component {
|
||||||
public:
|
public:
|
||||||
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; }
|
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; }
|
||||||
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { this->humidity_sensor_ = humidity_sensor; }
|
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { this->humidity_sensor_ = humidity_sensor; }
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ struct AcDimmerDataStore {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class AcDimmer : public output::FloatOutput, public Component {
|
class AcDimmer final : public output::FloatOutput, public Component {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ template<typename T> class Aggregator {
|
|||||||
SamplingMode mode_{SamplingMode::AVG};
|
SamplingMode mode_{SamplingMode::AVG};
|
||||||
};
|
};
|
||||||
|
|
||||||
class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler {
|
class ADCSensor final : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler {
|
||||||
public:
|
public:
|
||||||
/// Update the sensor's state by reading the current ADC value.
|
/// Update the sensor's state by reading the current ADC value.
|
||||||
/// This method is called periodically based on the update interval.
|
/// This method is called periodically based on the update interval.
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
|
|
||||||
namespace esphome::adc128s102 {
|
namespace esphome::adc128s102 {
|
||||||
|
|
||||||
class ADC128S102 : public Component,
|
class ADC128S102 final : public Component,
|
||||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
|
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
|
||||||
spi::DATA_RATE_10MHZ> {
|
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_10MHZ> {
|
||||||
public:
|
public:
|
||||||
ADC128S102() = default;
|
ADC128S102() = default;
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
namespace esphome::adc128s102 {
|
namespace esphome::adc128s102 {
|
||||||
|
|
||||||
class ADC128S102Sensor : public PollingComponent,
|
class ADC128S102Sensor final : public PollingComponent,
|
||||||
public Parented<ADC128S102>,
|
public Parented<ADC128S102>,
|
||||||
public sensor::Sensor,
|
public sensor::Sensor,
|
||||||
public voltage_sampler::VoltageSampler {
|
public voltage_sampler::VoltageSampler {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
namespace esphome::addressable_light {
|
namespace esphome::addressable_light {
|
||||||
|
|
||||||
class AddressableLightDisplay : public display::DisplayBuffer {
|
class AddressableLightDisplay final : public display::DisplayBuffer {
|
||||||
public:
|
public:
|
||||||
light::AddressableLight *get_light() const { return this->light_; }
|
light::AddressableLight *get_light() const { return this->light_; }
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ struct ADE7880Store {
|
|||||||
static void gpio_intr(ADE7880Store *arg);
|
static void gpio_intr(ADE7880Store *arg);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ADE7880 : public i2c::I2CDevice, public PollingComponent {
|
class ADE7880 final : public i2c::I2CDevice, public PollingComponent {
|
||||||
public:
|
public:
|
||||||
void set_irq0_pin(InternalGPIOPin *pin) { this->irq0_pin_ = pin; }
|
void set_irq0_pin(InternalGPIOPin *pin) { this->irq0_pin_ = pin; }
|
||||||
void set_irq1_pin(InternalGPIOPin *pin) { this->irq1_pin_ = pin; }
|
void set_irq1_pin(InternalGPIOPin *pin) { this->irq1_pin_ = pin; }
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
namespace esphome::ade7953_i2c {
|
namespace esphome::ade7953_i2c {
|
||||||
|
|
||||||
class AdE7953I2c : public ade7953_base::ADE7953, public i2c::I2CDevice {
|
class AdE7953I2c final : public ade7953_base::ADE7953, public i2c::I2CDevice {
|
||||||
public:
|
public:
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ enum ADS1115Samplerate {
|
|||||||
ADS1115_860SPS = 0b111
|
ADS1115_860SPS = 0b111
|
||||||
};
|
};
|
||||||
|
|
||||||
class ADS1115Component : public Component, public i2c::I2CDevice {
|
class ADS1115Component final : public Component, public i2c::I2CDevice {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
namespace esphome::ads1115 {
|
namespace esphome::ads1115 {
|
||||||
|
|
||||||
/// Internal holder class that is in instance of Sensor so that the hub can create individual sensors.
|
/// Internal holder class that is in instance of Sensor so that the hub can create individual sensors.
|
||||||
class ADS1115Sensor : public sensor::Sensor,
|
class ADS1115Sensor final : public sensor::Sensor,
|
||||||
public PollingComponent,
|
public PollingComponent,
|
||||||
public voltage_sampler::VoltageSampler,
|
public voltage_sampler::VoltageSampler,
|
||||||
public Parented<ADS1115Component> {
|
public Parented<ADS1115Component> {
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ enum ADS1118Gain {
|
|||||||
ADS1118_GAIN_0P256 = 0b101,
|
ADS1118_GAIN_0P256 = 0b101,
|
||||||
};
|
};
|
||||||
|
|
||||||
class ADS1118 : public Component,
|
class ADS1118 final : public Component,
|
||||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_TRAILING,
|
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
|
||||||
spi::DATA_RATE_1MHZ> {
|
spi::CLOCK_PHASE_TRAILING, spi::DATA_RATE_1MHZ> {
|
||||||
public:
|
public:
|
||||||
ADS1118() = default;
|
ADS1118() = default;
|
||||||
void setup() override;
|
void setup() override;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
namespace esphome::ads1118 {
|
namespace esphome::ads1118 {
|
||||||
|
|
||||||
class ADS1118Sensor : public PollingComponent,
|
class ADS1118Sensor final : public PollingComponent,
|
||||||
public sensor::Sensor,
|
public sensor::Sensor,
|
||||||
public voltage_sampler::VoltageSampler,
|
public voltage_sampler::VoltageSampler,
|
||||||
public Parented<ADS1118> {
|
public Parented<ADS1118> {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace esphome::ags10 {
|
namespace esphome::ags10 {
|
||||||
|
|
||||||
class AGS10Component : public PollingComponent, public i2c::I2CDevice {
|
class AGS10Component final : public PollingComponent, public i2c::I2CDevice {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Sets TVOC sensor.
|
* Sets TVOC sensor.
|
||||||
@@ -100,7 +100,7 @@ class AGS10Component : public PollingComponent, public i2c::I2CDevice {
|
|||||||
template<size_t N> optional<std::array<uint8_t, N>> read_and_check_(uint8_t a_register);
|
template<size_t N> optional<std::array<uint8_t, N>> read_and_check_(uint8_t a_register);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class AGS10NewI2cAddressAction : public Action<Ts...>, public Parented<AGS10Component> {
|
template<typename... Ts> class AGS10NewI2cAddressAction final : public Action<Ts...>, public Parented<AGS10Component> {
|
||||||
public:
|
public:
|
||||||
TEMPLATABLE_VALUE(uint8_t, new_address)
|
TEMPLATABLE_VALUE(uint8_t, new_address)
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ enum AGS10SetZeroPointActionMode {
|
|||||||
CUSTOM_VALUE,
|
CUSTOM_VALUE,
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class AGS10SetZeroPointAction : public Action<Ts...>, public Parented<AGS10Component> {
|
template<typename... Ts> class AGS10SetZeroPointAction final : public Action<Ts...>, public Parented<AGS10Component> {
|
||||||
public:
|
public:
|
||||||
TEMPLATABLE_VALUE(uint16_t, value)
|
TEMPLATABLE_VALUE(uint16_t, value)
|
||||||
TEMPLATABLE_VALUE(AGS10SetZeroPointActionMode, mode)
|
TEMPLATABLE_VALUE(AGS10SetZeroPointActionMode, mode)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace esphome::aht10 {
|
|||||||
|
|
||||||
enum AHT10Variant { AHT10, AHT20 };
|
enum AHT10Variant { AHT10, AHT20 };
|
||||||
|
|
||||||
class AHT10Component : public PollingComponent, public i2c::I2CDevice {
|
class AHT10Component final : public PollingComponent, public i2c::I2CDevice {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void update() override;
|
void update() override;
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ static const uint8_t AIC3204_ADC_PTM = 0x3D; // Register 61 - ADC Power Tu
|
|||||||
static const uint8_t AIC3204_AN_IN_CHRG = 0x47; // Register 71 - Analog Input Quick Charging Config
|
static const uint8_t AIC3204_AN_IN_CHRG = 0x47; // Register 71 - Analog Input Quick Charging Config
|
||||||
static const uint8_t AIC3204_REF_STARTUP = 0x7B; // Register 123 - Reference Power Up Config
|
static const uint8_t AIC3204_REF_STARTUP = 0x7B; // Register 123 - Reference Power Up Config
|
||||||
|
|
||||||
class AIC3204 : public audio_dac::AudioDac, public Component, public i2c::I2CDevice {
|
class AIC3204 final : public audio_dac::AudioDac, public Component, public i2c::I2CDevice {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace esphome::aic3204 {
|
namespace esphome::aic3204 {
|
||||||
|
|
||||||
template<typename... Ts> class SetAutoMuteAction : public Action<Ts...> {
|
template<typename... Ts> class SetAutoMuteAction final : public Action<Ts...> {
|
||||||
public:
|
public:
|
||||||
explicit SetAutoMuteAction(AIC3204 *aic3204) : aic3204_(aic3204) {}
|
explicit SetAutoMuteAction(AIC3204 *aic3204) : aic3204_(aic3204) {}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace esphome::airthings_ble {
|
namespace esphome::airthings_ble {
|
||||||
|
|
||||||
class AirthingsListener : public esp32_ble_tracker::ESPBTDeviceListener {
|
class AirthingsListener final : public esp32_ble_tracker::ESPBTDeviceListener {
|
||||||
public:
|
public:
|
||||||
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
|
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ static const char *const SERVICE_UUID = "b42e3882-ade7-11e4-89d3-123b93f75cba";
|
|||||||
static const char *const CHARACTERISTIC_UUID = "b42e3b98-ade7-11e4-89d3-123b93f75cba";
|
static const char *const CHARACTERISTIC_UUID = "b42e3b98-ade7-11e4-89d3-123b93f75cba";
|
||||||
static const char *const ACCESS_CONTROL_POINT_CHARACTERISTIC_UUID = "b42e3ef4-ade7-11e4-89d3-123b93f75cba";
|
static const char *const ACCESS_CONTROL_POINT_CHARACTERISTIC_UUID = "b42e3ef4-ade7-11e4-89d3-123b93f75cba";
|
||||||
|
|
||||||
class AirthingsWaveMini : public airthings_wave_base::AirthingsWaveBase {
|
class AirthingsWaveMini final : public airthings_wave_base::AirthingsWaveBase {
|
||||||
public:
|
public:
|
||||||
AirthingsWaveMini();
|
AirthingsWaveMini();
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ static const char *const CHARACTERISTIC_UUID_WAVE_RADON_GEN2 = "b42e4dcc-ade7-11
|
|||||||
static const char *const ACCESS_CONTROL_POINT_CHARACTERISTIC_UUID_WAVE_RADON_GEN2 =
|
static const char *const ACCESS_CONTROL_POINT_CHARACTERISTIC_UUID_WAVE_RADON_GEN2 =
|
||||||
"b42e50d8-ade7-11e4-89d3-123b93f75cba";
|
"b42e50d8-ade7-11e4-89d3-123b93f75cba";
|
||||||
|
|
||||||
class AirthingsWavePlus : public airthings_wave_base::AirthingsWaveBase {
|
class AirthingsWavePlus final : public airthings_wave_base::AirthingsWaveBase {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ static_assert(std::is_trivially_copyable_v<StateAnyForwarder>);
|
|||||||
static_assert(sizeof(StateEnterForwarder<ACP_STATE_TRIGGERED>) <= sizeof(void *));
|
static_assert(sizeof(StateEnterForwarder<ACP_STATE_TRIGGERED>) <= sizeof(void *));
|
||||||
static_assert(std::is_trivially_copyable_v<StateEnterForwarder<ACP_STATE_TRIGGERED>>);
|
static_assert(std::is_trivially_copyable_v<StateEnterForwarder<ACP_STATE_TRIGGERED>>);
|
||||||
|
|
||||||
template<typename... Ts> class ArmAwayAction : public Action<Ts...> {
|
template<typename... Ts> class ArmAwayAction final : public Action<Ts...> {
|
||||||
public:
|
public:
|
||||||
explicit ArmAwayAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {}
|
explicit ArmAwayAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ template<typename... Ts> class ArmAwayAction : public Action<Ts...> {
|
|||||||
AlarmControlPanel *alarm_control_panel_;
|
AlarmControlPanel *alarm_control_panel_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class ArmHomeAction : public Action<Ts...> {
|
template<typename... Ts> class ArmHomeAction final : public Action<Ts...> {
|
||||||
public:
|
public:
|
||||||
explicit ArmHomeAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {}
|
explicit ArmHomeAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {}
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ template<typename... Ts> class ArmHomeAction : public Action<Ts...> {
|
|||||||
AlarmControlPanel *alarm_control_panel_;
|
AlarmControlPanel *alarm_control_panel_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class ArmNightAction : public Action<Ts...> {
|
template<typename... Ts> class ArmNightAction final : public Action<Ts...> {
|
||||||
public:
|
public:
|
||||||
explicit ArmNightAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {}
|
explicit ArmNightAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {}
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ template<typename... Ts> class ArmNightAction : public Action<Ts...> {
|
|||||||
AlarmControlPanel *alarm_control_panel_;
|
AlarmControlPanel *alarm_control_panel_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class DisarmAction : public Action<Ts...> {
|
template<typename... Ts> class DisarmAction final : public Action<Ts...> {
|
||||||
public:
|
public:
|
||||||
explicit DisarmAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {}
|
explicit DisarmAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {}
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ template<typename... Ts> class DisarmAction : public Action<Ts...> {
|
|||||||
AlarmControlPanel *alarm_control_panel_;
|
AlarmControlPanel *alarm_control_panel_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class PendingAction : public Action<Ts...> {
|
template<typename... Ts> class PendingAction final : public Action<Ts...> {
|
||||||
public:
|
public:
|
||||||
explicit PendingAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {}
|
explicit PendingAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {}
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ template<typename... Ts> class PendingAction : public Action<Ts...> {
|
|||||||
AlarmControlPanel *alarm_control_panel_;
|
AlarmControlPanel *alarm_control_panel_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class TriggeredAction : public Action<Ts...> {
|
template<typename... Ts> class TriggeredAction final : public Action<Ts...> {
|
||||||
public:
|
public:
|
||||||
explicit TriggeredAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {}
|
explicit TriggeredAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {}
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ template<typename... Ts> class TriggeredAction : public Action<Ts...> {
|
|||||||
AlarmControlPanel *alarm_control_panel_;
|
AlarmControlPanel *alarm_control_panel_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class AlarmControlPanelCondition : public Condition<Ts...> {
|
template<typename... Ts> class AlarmControlPanelCondition final : public Condition<Ts...> {
|
||||||
public:
|
public:
|
||||||
AlarmControlPanelCondition(AlarmControlPanel *parent) : parent_(parent) {}
|
AlarmControlPanelCondition(AlarmControlPanel *parent) : parent_(parent) {}
|
||||||
bool check(const Ts &...x) override {
|
bool check(const Ts &...x) override {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ static const int16_t GENI_RESPONSE_POWER_OFFSET = 12;
|
|||||||
static const int16_t GENI_RESPONSE_MOTOR_POWER_OFFSET = 16; // not sure
|
static const int16_t GENI_RESPONSE_MOTOR_POWER_OFFSET = 16; // not sure
|
||||||
static const int16_t GENI_RESPONSE_MOTOR_SPEED_OFFSET = 20;
|
static const int16_t GENI_RESPONSE_MOTOR_SPEED_OFFSET = 20;
|
||||||
|
|
||||||
class Alpha3 : public esphome::ble_client::BLEClientNode, public PollingComponent {
|
class Alpha3 final : public esphome::ble_client::BLEClientNode, public PollingComponent {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void update() override;
|
void update() override;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
namespace esphome::am2315c {
|
namespace esphome::am2315c {
|
||||||
|
|
||||||
class AM2315C : public PollingComponent, public i2c::I2CDevice {
|
class AM2315C final : public PollingComponent, public i2c::I2CDevice {
|
||||||
public:
|
public:
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
void update() override;
|
void update() override;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace esphome::am2320 {
|
namespace esphome::am2320 {
|
||||||
|
|
||||||
class AM2320Component : public PollingComponent, public i2c::I2CDevice {
|
class AM2320Component final : public PollingComponent, public i2c::I2CDevice {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace esphome::am43 {
|
|||||||
|
|
||||||
namespace espbt = esphome::esp32_ble_tracker;
|
namespace espbt = esphome::esp32_ble_tracker;
|
||||||
|
|
||||||
class Am43Component : public cover::Cover, public esphome::ble_client::BLEClientNode, public Component {
|
class Am43Component final : public cover::Cover, public esphome::ble_client::BLEClientNode, public Component {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace esphome::am43 {
|
|||||||
|
|
||||||
namespace espbt = esphome::esp32_ble_tracker;
|
namespace espbt = esphome::esp32_ble_tracker;
|
||||||
|
|
||||||
class Am43 : public esphome::ble_client::BLEClientNode, public PollingComponent {
|
class Am43 final : public esphome::ble_client::BLEClientNode, public PollingComponent {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void update() override;
|
void update() override;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace esphome::analog_threshold {
|
namespace esphome::analog_threshold {
|
||||||
|
|
||||||
class AnalogThresholdBinarySensor : public Component, public binary_sensor::BinarySensor {
|
class AnalogThresholdBinarySensor final : public Component, public binary_sensor::BinarySensor {
|
||||||
public:
|
public:
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
void setup() override;
|
void setup() override;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
namespace esphome::animation {
|
namespace esphome::animation {
|
||||||
|
|
||||||
class Animation : public image::Image {
|
class Animation final : public image::Image {
|
||||||
public:
|
public:
|
||||||
Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, image::ImageType type,
|
Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, image::ImageType type,
|
||||||
image::Transparency transparent);
|
image::Transparency transparent);
|
||||||
@@ -35,7 +35,7 @@ class Animation : public image::Image {
|
|||||||
int loop_current_iteration_;
|
int loop_current_iteration_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class AnimationNextFrameAction : public Action<Ts...> {
|
template<typename... Ts> class AnimationNextFrameAction final : public Action<Ts...> {
|
||||||
public:
|
public:
|
||||||
AnimationNextFrameAction(Animation *parent) : parent_(parent) {}
|
AnimationNextFrameAction(Animation *parent) : parent_(parent) {}
|
||||||
void play(const Ts &...x) override { this->parent_->next_frame(); }
|
void play(const Ts &...x) override { this->parent_->next_frame(); }
|
||||||
@@ -44,7 +44,7 @@ template<typename... Ts> class AnimationNextFrameAction : public Action<Ts...> {
|
|||||||
Animation *parent_;
|
Animation *parent_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class AnimationPrevFrameAction : public Action<Ts...> {
|
template<typename... Ts> class AnimationPrevFrameAction final : public Action<Ts...> {
|
||||||
public:
|
public:
|
||||||
AnimationPrevFrameAction(Animation *parent) : parent_(parent) {}
|
AnimationPrevFrameAction(Animation *parent) : parent_(parent) {}
|
||||||
void play(const Ts &...x) override { this->parent_->prev_frame(); }
|
void play(const Ts &...x) override { this->parent_->prev_frame(); }
|
||||||
@@ -53,7 +53,7 @@ template<typename... Ts> class AnimationPrevFrameAction : public Action<Ts...> {
|
|||||||
Animation *parent_;
|
Animation *parent_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class AnimationSetFrameAction : public Action<Ts...> {
|
template<typename... Ts> class AnimationSetFrameAction final : public Action<Ts...> {
|
||||||
public:
|
public:
|
||||||
AnimationSetFrameAction(Animation *parent) : parent_(parent) {}
|
AnimationSetFrameAction(Animation *parent) : parent_(parent) {}
|
||||||
TEMPLATABLE_VALUE(uint16_t, frame)
|
TEMPLATABLE_VALUE(uint16_t, frame)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace espbt = esphome::esp32_ble_tracker;
|
|||||||
static const uint16_t ANOVA_SERVICE_UUID = 0xFFE0;
|
static const uint16_t ANOVA_SERVICE_UUID = 0xFFE0;
|
||||||
static const uint16_t ANOVA_CHARACTERISTIC_UUID = 0xFFE1;
|
static const uint16_t ANOVA_CHARACTERISTIC_UUID = 0xFFE1;
|
||||||
|
|
||||||
class Anova : public climate::Climate, public esphome::ble_client::BLEClientNode, public PollingComponent {
|
class Anova final : public climate::Climate, public esphome::ble_client::BLEClientNode, public PollingComponent {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ enum AmbientLightGain : uint8_t {
|
|||||||
};
|
};
|
||||||
static const uint8_t AMBIENT_LIGHT_GAIN_VALUES[] = {1, 3, 6, 9, 18};
|
static const uint8_t AMBIENT_LIGHT_GAIN_VALUES[] = {1, 3, 6, 9, 18};
|
||||||
|
|
||||||
class APDS9306 : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice {
|
class APDS9306 final : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
float get_setup_priority() const override { return setup_priority::BUS; }
|
float get_setup_priority() const override { return setup_priority::BUS; }
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
namespace esphome::apds9960 {
|
namespace esphome::apds9960 {
|
||||||
|
|
||||||
class APDS9960 : public PollingComponent, public i2c::I2CDevice {
|
class APDS9960 final : public PollingComponent, public i2c::I2CDevice {
|
||||||
#ifdef USE_SENSOR
|
#ifdef USE_SENSOR
|
||||||
SUB_SENSOR(red)
|
SUB_SENSOR(red)
|
||||||
SUB_SENSOR(green)
|
SUB_SENSOR(green)
|
||||||
|
|||||||
@@ -375,7 +375,7 @@ void APIConnection::finalize_iterator_sync_() {
|
|||||||
|
|
||||||
void APIConnection::process_iterator_batch_(ComponentIterator &iterator) {
|
void APIConnection::process_iterator_batch_(ComponentIterator &iterator) {
|
||||||
size_t initial_size = this->deferred_batch_.size();
|
size_t initial_size = this->deferred_batch_.size();
|
||||||
size_t max_batch = this->get_max_batch_size_();
|
size_t max_batch = MAX_INITIAL_PER_BATCH;
|
||||||
while (!iterator.completed() && (this->deferred_batch_.size() - initial_size) < max_batch) {
|
while (!iterator.completed() && (this->deferred_batch_.size() - initial_size) < max_batch) {
|
||||||
iterator.advance();
|
iterator.advance();
|
||||||
}
|
}
|
||||||
@@ -418,16 +418,6 @@ uint16_t APIConnection::fill_and_encode_entity_info(EntityBase *entity, InfoResp
|
|||||||
// Set common fields that are shared by all entity types
|
// Set common fields that are shared by all entity types
|
||||||
msg.key = entity->get_object_id_hash();
|
msg.key = entity->get_object_id_hash();
|
||||||
|
|
||||||
// API 1.14+ clients compute object_id client-side from the entity name
|
|
||||||
// For older clients, we must send object_id for backward compatibility
|
|
||||||
// See: https://github.com/esphome/backlog/issues/76
|
|
||||||
// TODO: Remove this backward compat code before 2026.7.0 - all clients should support API 1.14 by then
|
|
||||||
// Buffer must remain in scope until encode_to_buffer is called
|
|
||||||
char object_id_buf[OBJECT_ID_MAX_LEN];
|
|
||||||
if (!conn->client_supports_api_version(1, 14)) {
|
|
||||||
msg.object_id = entity->get_object_id_to(object_id_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entity->has_own_name()) {
|
if (entity->has_own_name()) {
|
||||||
msg.name = entity->get_name();
|
msg.name = entity->get_name();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,10 +43,7 @@ class APIServer;
|
|||||||
// Keepalive timeout in milliseconds
|
// Keepalive timeout in milliseconds
|
||||||
static constexpr uint32_t KEEPALIVE_TIMEOUT_MS = 60000;
|
static constexpr uint32_t KEEPALIVE_TIMEOUT_MS = 60000;
|
||||||
// Maximum number of entities to process in a single batch during initial state/info sending
|
// Maximum number of entities to process in a single batch during initial state/info sending
|
||||||
// API 1.14+ clients compute object_id client-side, so messages are smaller and we can fit more per batch
|
static constexpr size_t MAX_INITIAL_PER_BATCH = 34;
|
||||||
// TODO: Remove MAX_INITIAL_PER_BATCH_LEGACY before 2026.7.0 - all clients should support API 1.14 by then
|
|
||||||
static constexpr size_t MAX_INITIAL_PER_BATCH_LEGACY = 24; // For clients < API 1.14 (includes object_id)
|
|
||||||
static constexpr size_t MAX_INITIAL_PER_BATCH = 34; // For clients >= API 1.14 (no object_id)
|
|
||||||
// Verify MAX_MESSAGES_PER_BATCH (defined in api_frame_helper.h) can hold the initial batch
|
// Verify MAX_MESSAGES_PER_BATCH (defined in api_frame_helper.h) can hold the initial batch
|
||||||
static_assert(MAX_MESSAGES_PER_BATCH >= MAX_INITIAL_PER_BATCH,
|
static_assert(MAX_MESSAGES_PER_BATCH >= MAX_INITIAL_PER_BATCH,
|
||||||
"MAX_MESSAGES_PER_BATCH must be >= MAX_INITIAL_PER_BATCH");
|
"MAX_MESSAGES_PER_BATCH must be >= MAX_INITIAL_PER_BATCH");
|
||||||
@@ -481,13 +478,6 @@ class APIConnection final : public APIServerConnectionBase {
|
|||||||
inline bool check_voice_assistant_api_connection_() const;
|
inline bool check_voice_assistant_api_connection_() const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Get the max batch size based on client API version
|
|
||||||
// API 1.14+ clients don't receive object_id, so messages are smaller and more fit per batch
|
|
||||||
// TODO: Remove this method before 2026.7.0 and use MAX_INITIAL_PER_BATCH directly
|
|
||||||
size_t get_max_batch_size_() const {
|
|
||||||
return this->client_supports_api_version(1, 14) ? MAX_INITIAL_PER_BATCH : MAX_INITIAL_PER_BATCH_LEGACY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send keepalive ping or disconnect unresponsive client.
|
// Send keepalive ping or disconnect unresponsive client.
|
||||||
// Cold path — extracted from loop() to reduce instruction cache pressure.
|
// Cold path — extracted from loop() to reduce instruction cache pressure.
|
||||||
void __attribute__((noinline)) check_keepalive_(uint32_t now);
|
void __attribute__((noinline)) check_keepalive_(uint32_t now);
|
||||||
|
|||||||
@@ -342,7 +342,7 @@ class APIServer final : public Component,
|
|||||||
|
|
||||||
extern APIServer *global_api_server; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
extern APIServer *global_api_server; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
template<typename... Ts> class APIConnectedCondition : public Condition<Ts...> {
|
template<typename... Ts> class APIConnectedCondition final : public Condition<Ts...> {
|
||||||
TEMPLATABLE_VALUE(bool, state_subscription_only)
|
TEMPLATABLE_VALUE(bool, state_subscription_only)
|
||||||
public:
|
public:
|
||||||
bool check(const Ts &...x) override {
|
bool check(const Ts &...x) override {
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ class ActionResponse {
|
|||||||
template<typename... Ts> using ActionResponseCallback = std::function<void(const ActionResponse &, Ts...)>;
|
template<typename... Ts> using ActionResponseCallback = std::function<void(const ActionResponse &, Ts...)>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<typename... Ts> class HomeAssistantServiceCallAction : public Action<Ts...> {
|
template<typename... Ts> class HomeAssistantServiceCallAction final : public Action<Ts...> {
|
||||||
public:
|
public:
|
||||||
explicit HomeAssistantServiceCallAction(APIServer *parent, bool is_event) : parent_(parent) {
|
explicit HomeAssistantServiceCallAction(APIServer *parent, bool is_event) : parent_(parent) {
|
||||||
this->flags_.is_event = is_event;
|
this->flags_.is_event = is_event;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user