Compare commits

..

6 Commits

Author SHA1 Message Date
J. Nick Koston
cd22a9751b DNM: probe integration-test bucketing for api
Touches api/api_connection.h with a comment so determine-jobs.py routes
the api component's integration tests into the bucketed split job
alongside the cover probe. Used to validate the matrix expansion in
#16152.

Do not merge.
2026-04-29 18:41:44 -05:00
J. Nick Koston
4173f4526e DNM: probe integration-test bucketing for cover
Touches cover/cover.h with a comment so determine-jobs.py routes the
cover component's integration tests into the bucketed split job. Used
to validate the matrix expansion in #16152.

Do not merge.
2026-04-29 18:41:22 -05:00
J. Nick Koston
f3b75c0369 [ci] Extract integration test bucketing into a pure function
Pull the run_all glob expansion + bucket computation out of main() into
_compute_integration_test_buckets() returning (run_integration, buckets).
The boundary tests now call this helper directly instead of driving
main() through ~14 patched dependencies, which both shrinks the test
helper and removes duplication with the existing test_main_* fixtures.
2026-04-29 18:41:17 -05:00
J. Nick Koston
37bcd7c59f [ci] Move test helper imports to module level
Hoist `import contextlib` and `import io` from inside
_run_main_for_integration_buckets() up to the top of the file.
2026-04-29 18:38:46 -05:00
J. Nick Koston
8122ae4888 [ci] Address Copilot review on integration-test bucketing
- Emit each bucket's `tests` as a JSON list of file paths instead of a
  space-joined string. The workflow now uses jq to build a bash array,
  removing word-splitting / glob hazards on test paths.
- Guard against an empty integration test list after `run_all` expansion:
  if the glob returns nothing, suppress the run rather than invoking
  pytest with no path argument (which would collect tests outside
  tests/integration/).
- Add boundary-case unit tests for the bucketing decision: empty
  selection, explicit small lists, exactly threshold (single bucket),
  one over threshold (3 buckets), and run_all-with-empty-glob (no run).
2026-04-29 18:38:20 -05:00
J. Nick Koston
c3ebc39262 [ci] Split integration tests into 3 buckets when count > 10
When more than 10 integration tests are scheduled (or any change that
triggers run_all, e.g. core/infra changes that would run all 117 files),
fan out the pytest job into 3 parallel matrix entries. Below the
threshold, a single bucket runs as before, so small targeted PRs see no
extra job overhead.

determine-jobs.py now owns the bucketing end-to-end: it expands run_all
into the explicit glob of tests/integration/test_*.py and pre-splits the
sorted list using the same balanced contiguous-partition formula as
script/clang-tidy. The CI workflow consumes the precomputed buckets via
fromJson() in the matrix, mirroring how component-test-batches works,
so no shell-side splitting is needed.

The previous integration-tests-run-all and integration-test-files
workflow outputs are replaced by a single integration-test-buckets
list-of-objects ({name, tests}); the integration-tests gate boolean is
unchanged.
2026-04-29 18:16:43 -05:00
1963 changed files with 10361 additions and 22183 deletions

View File

@@ -96,6 +96,7 @@ Checks: >-
-modernize-avoid-variadic-functions,
-modernize-avoid-c-arrays,
-modernize-avoid-c-style-cast,
-modernize-concat-nested-namespaces,
-modernize-macro-to-enum,
-modernize-return-braced-init-list,
-modernize-type-traits,
@@ -132,6 +133,7 @@ Checks: >-
-readability-redundant-inline-specifier,
-readability-redundant-member-init,
-readability-redundant-parentheses,
-readability-redundant-string-init,
-readability-redundant-typename,
-readability-uppercase-literal-suffix,
-readability-use-anyofallof,

View File

@@ -1 +1 @@
96c95feaa60831da5f43e3c6a7c7a3a237e17c5d12995a730dbc3884c8dcd11c
0c7f309d70eca8e3efd510092ddb23c530f3934c49371717efa124b788d761f8

View File

@@ -115,4 +115,4 @@ examples/
Dockerfile
.git/
tests/
.?*
.*

View File

@@ -1,3 +1,4 @@
const fs = require('fs');
const { DOCS_PR_PATTERNS } = require('./constants');
const {
COMPONENT_REGEX,
@@ -8,31 +9,6 @@ const {
} = require('../detect-tags');
const { loadCodeowners, getEffectiveOwners } = require('../codeowners');
// Top-level `CONFIG_SCHEMA = ...` (assignment) or `CONFIG_SCHEMA: ConfigType = ...` (annotation).
// Ruff/Black enforce exactly one space around `=` and no space before `:`,
// so we can match strictly: `CONFIG_SCHEMA ` or `CONFIG_SCHEMA:`.
const CONFIG_SCHEMA_REGEX = /^CONFIG_SCHEMA[ :]/m;
// Fetch a file's contents from the PR head SHA via the GitHub API.
// The auto-label workflow runs on `pull_request_target`, which checks out the
// base branch — files added by the PR don't exist in the workspace, so we have
// to fetch them from the head SHA. Returns null if the file can't be fetched.
async function fetchPrFileContent(github, context, path) {
try {
const { owner, repo } = context.repo;
const { data } = await github.rest.repos.getContent({
owner,
repo,
path,
ref: context.payload.pull_request.head.sha,
});
return Buffer.from(data.content, 'base64').toString('utf8');
} catch (error) {
console.log(`Failed to fetch ${path} from PR head:`, error.message);
return null;
}
}
// Strategy: Merge branch detection
async function detectMergeBranch(context) {
const labels = new Set();
@@ -69,64 +45,52 @@ async function detectComponentPlatforms(changedFiles, apiData) {
}
// Strategy: New component detection
async function detectNewComponents(github, context, prFiles) {
async function detectNewComponents(prFiles) {
const labels = new Set();
let hasYamlLoadable = false;
const addedFiles = prFiles.filter(file => file.status === 'added').map(file => file.filename);
for (const file of addedFiles) {
const componentMatch = file.match(/^esphome\/components\/([^\/]+)\/__init__\.py$/);
if (!componentMatch) continue;
labels.add('new-component');
const content = await fetchPrFileContent(github, context, file);
if (content === null) {
// Safe default: assume YAML-loadable so needs-docs behaviour is unchanged on fetch failure
hasYamlLoadable = true;
continue;
}
if (content.includes('IS_TARGET_PLATFORM = True')) {
labels.add('new-target-platform');
}
if (CONFIG_SCHEMA_REGEX.test(content)) {
hasYamlLoadable = true;
if (componentMatch) {
try {
const content = fs.readFileSync(file, 'utf8');
if (content.includes('IS_TARGET_PLATFORM = True')) {
labels.add('new-target-platform');
}
} catch (error) {
console.log(`Failed to read content of ${file}:`, error.message);
}
labels.add('new-component');
}
}
return { labels, hasYamlLoadable };
return labels;
}
// Strategy: New platform detection
async function detectNewPlatforms(github, context, prFiles, apiData) {
async function detectNewPlatforms(prFiles, apiData) {
const labels = new Set();
let hasYamlLoadable = false;
const addedFiles = prFiles.filter(file => file.status === 'added').map(file => file.filename);
const platformPathPatterns = [
/^esphome\/components\/([^\/]+)\/([^\/]+)\.py$/,
/^esphome\/components\/([^\/]+)\/([^\/]+)\/__init__\.py$/,
];
for (const file of addedFiles) {
for (const re of platformPathPatterns) {
const match = file.match(re);
if (!match) continue;
const platform = match[2];
if (!apiData.platformComponents.includes(platform)) break;
labels.add('new-platform');
const content = await fetchPrFileContent(github, context, file);
if (content === null) {
// Safe default: assume YAML-loadable so needs-docs behaviour is unchanged on fetch failure
hasYamlLoadable = true;
} else if (CONFIG_SCHEMA_REGEX.test(content)) {
hasYamlLoadable = true;
const platformFileMatch = file.match(/^esphome\/components\/([^\/]+)\/([^\/]+)\.py$/);
if (platformFileMatch) {
const [, component, platform] = platformFileMatch;
if (apiData.platformComponents.includes(platform)) {
labels.add('new-platform');
}
}
const platformDirMatch = file.match(/^esphome\/components\/([^\/]+)\/([^\/]+)\/__init__\.py$/);
if (platformDirMatch) {
const [, component, platform] = platformDirMatch;
if (apiData.platformComponents.includes(platform)) {
labels.add('new-platform');
}
break;
}
}
return { labels, hasYamlLoadable };
return labels;
}
// Strategy: Core files detection
@@ -336,7 +300,7 @@ function detectMaintainerAccess(context) {
}
// Strategy: Requirements detection
async function detectRequirements(allLabels, prFiles, context, hasYamlLoadable) {
async function detectRequirements(allLabels, prFiles, context) {
const labels = new Set();
// Check for missing tests
@@ -344,15 +308,8 @@ async function detectRequirements(allLabels, prFiles, context, hasYamlLoadable)
labels.add('needs-tests');
}
// Check for missing docs.
// `new-feature` (PR-body checkbox) always counts. `new-component` / `new-platform`
// only count when at least one newly added file defines a top-level CONFIG_SCHEMA,
// i.e. the new component/platform is actually loadable from YAML.
const docsEligible =
allLabels.has('new-feature') ||
((allLabels.has('new-component') || allLabels.has('new-platform')) && hasYamlLoadable);
if (docsEligible) {
// Check for missing docs
if (allLabels.has('new-component') || allLabels.has('new-platform') || allLabels.has('new-feature')) {
const prBody = context.payload.pull_request.body || '';
const hasDocsLink = DOCS_PR_PATTERNS.some(pattern => pattern.test(prBody));

View File

@@ -106,8 +106,8 @@ module.exports = async ({ github, context }) => {
const [
branchLabels,
componentLabels,
newComponentResult,
newPlatformResult,
newComponentLabels,
newPlatformLabels,
coreLabels,
sizeLabels,
dashboardLabels,
@@ -120,8 +120,8 @@ module.exports = async ({ github, context }) => {
] = await Promise.all([
detectMergeBranch(context),
detectComponentPlatforms(changedFiles, apiData),
detectNewComponents(github, context, prFiles),
detectNewPlatforms(github, context, prFiles, apiData),
detectNewComponents(prFiles),
detectNewPlatforms(prFiles, apiData),
detectCoreChanges(changedFiles),
detectPRSize(prFiles, totalAdditions, totalDeletions, totalChanges, isMegaPR, SMALL_PR_THRESHOLD, MEDIUM_PR_THRESHOLD, TOO_BIG_THRESHOLD),
detectDashboardChanges(changedFiles),
@@ -133,13 +133,6 @@ module.exports = async ({ github, context }) => {
detectMaintainerAccess(context)
]);
// Extract new-component / new-platform results
const newComponentLabels = newComponentResult.labels;
const newPlatformLabels = newPlatformResult.labels;
// Eligible for needs-docs only if any newly added component or platform file
// defines a top-level CONFIG_SCHEMA (i.e. is actually loadable from YAML).
const hasYamlLoadable = newComponentResult.hasYamlLoadable || newPlatformResult.hasYamlLoadable;
// Extract deprecated component info
const deprecatedLabels = deprecatedResult.labels;
const deprecatedInfo = deprecatedResult.deprecatedInfo;
@@ -161,7 +154,7 @@ module.exports = async ({ github, context }) => {
]);
// Detect requirements based on all other labels
const requirementLabels = await detectRequirements(allLabels, prFiles, context, hasYamlLoadable);
const requirementLabels = await detectRequirements(allLabels, prFiles, context);
for (const label of requirementLabels) {
allLabels.add(label);
}

View File

@@ -6,10 +6,9 @@ on:
pull_request_target:
types: [labeled, opened, reopened, synchronize, edited]
# All PR/label/review writes are performed with the App token minted below,
# so the workflow's GITHUB_TOKEN only needs read access for checkout.
permissions:
contents: read # actions/checkout reads the workflow source
pull-requests: write
contents: read
env:
SMALL_PR_THRESHOLD: 30
@@ -28,14 +27,10 @@ jobs:
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v2
with:
client-id: ${{ vars.ESPHOME_GITHUB_APP_CLIENT_ID }}
app-id: ${{ secrets.ESPHOME_GITHUB_APP_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
# Scope the minted App token to the minimum needed by auto-label-pr/*.js.
permission-contents: read # repos.getContent for CODEOWNERS and file lookups in detectors.js
permission-issues: write # listLabelsOnIssue, addLabels, removeLabel, list/createComment
permission-pull-requests: write # pulls.listFiles, list/create/update/dismissReview
- name: Auto Label PR
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0

View File

@@ -12,8 +12,8 @@ on:
- ".github/workflows/ci-api-proto.yml"
permissions:
contents: read # actions/checkout for the PR head
pull-requests: write # pulls.createReview / listReviews / dismissReview when generated proto files are stale
contents: read
pull-requests: write
jobs:
check:

View File

@@ -12,8 +12,8 @@ on:
- ".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
contents: read
pull-requests: write
jobs:
verify-hash:

View File

@@ -22,7 +22,8 @@ on:
- "script/platformio_install_deps.py"
permissions:
contents: read # actions/checkout only; the build does not push images
contents: read
packages: read
concurrency:
# yamllint disable-line rule:line-length

View File

@@ -7,9 +7,9 @@ on:
types: [completed]
permissions:
contents: read # actions/checkout of the base repo at the PR's target branch
pull-requests: write # gh api to look up the PR by head SHA and post/update the memory-impact comment
actions: read # gh run download for the memory-analysis artifacts produced by the CI workflow run
contents: read
pull-requests: write
actions: read
jobs:
memory-impact-comment:

View File

@@ -17,7 +17,7 @@ on:
merge_group:
permissions:
contents: read # actions/checkout for all jobs; individual jobs add their own scopes when they need to write
contents: read
env:
DEFAULT_PYTHON: "3.11"
@@ -136,53 +136,6 @@ jobs:
if-no-files-found: ignore
retention-days: 14
device-builder:
name: Test downstream esphome/device-builder
runs-on: ubuntu-24.04
needs:
- common
- determine-jobs
if: needs.determine-jobs.outputs.device-builder == 'true'
steps:
- name: Check out esphome (this PR)
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
path: esphome
- name: Check out esphome/device-builder
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: esphome/device-builder
ref: main
path: device-builder
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.13"
- name: Set up uv
# Mirrors the install shape device-builder's own CI uses
# (esphome/device-builder#192): uv replaces pip for the
# install step (order-of-magnitude faster on cold boots,
# with its own wheel cache). actions/setup-python still
# provides the interpreter.
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
enable-cache: true
- name: Install device-builder + esphome from PR
# Install device-builder with its esphome + test extras
# first so its pinned versions of pytest/etc. land, then
# overlay the PR's esphome so the downstream tests run
# against this PR's Python code. ``--system`` installs into
# the runner's Python instead of a venv.
run: |
uv pip install --system -e './device-builder[esphome,test]'
uv pip install --system -e ./esphome
- name: Run device-builder pytest
# ``-n auto`` runs under pytest-xdist (matches device-builder's
# own CI). No ``--cov`` here -- this is purely a downstream
# smoke check against this PR's esphome code.
working-directory: device-builder
run: pytest -q -n auto --maxfail=5 --durations=10 --no-cov --ignore=tests/benchmarks
pytest:
name: Run pytest
strategy:
@@ -251,7 +204,6 @@ jobs:
clang-tidy-mode: ${{ steps.determine.outputs.clang-tidy-mode }}
python-linters: ${{ steps.determine.outputs.python-linters }}
import-time: ${{ steps.determine.outputs.import-time }}
device-builder: ${{ steps.determine.outputs.device-builder }}
changed-components: ${{ steps.determine.outputs.changed-components }}
changed-components-with-tests: ${{ steps.determine.outputs.changed-components-with-tests }}
directly-changed-components-with-tests: ${{ steps.determine.outputs.directly-changed-components-with-tests }}
@@ -295,7 +247,6 @@ jobs:
echo "clang-tidy-mode=$(echo "$output" | jq -r '.clang_tidy_mode')" >> $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 "device-builder=$(echo "$output" | jq -r '.device_builder')" >> $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 "directly-changed-components-with-tests=$(echo "$output" | jq -c '.directly_changed_components_with_tests')" >> $GITHUB_OUTPUT
@@ -415,7 +366,7 @@ jobs:
echo "binary=$BINARY" >> $GITHUB_OUTPUT
- name: Run CodSpeed benchmarks
uses: CodSpeedHQ/action@3194d9a39c4d46684cb44bf7207fc56626aad8fd # v4.15.1
uses: CodSpeedHQ/action@c381be0bfd20e844fb45594f6aa182ffcd94545c # v4.15.0
with:
run: ${{ steps.build.outputs.binary }}
mode: simulation
@@ -783,91 +734,6 @@ jobs:
# Run compilation with grouping and isolation
python3 script/test_build_components.py -e compile -c "$components_csv" -f --isolate "$directly_changed_csv"
test-native-idf:
name: Test components with native ESP-IDF
runs-on: ubuntu-24.04
needs:
- common
- determine-jobs
if: github.event_name == 'pull_request'
env:
ESPHOME_ESP_IDF_PREFIX: ~/.esphome-idf
TEST_COMPONENTS: esp32,api,heatpumpir,bme280_i2c,bh1750,aht10,esp32_ble,esp32_ble_beacon,esp32_ble_client,esp32_ble_server,esp32_ble_tracker,ble_client,ble_presence,ble_rssi,ble_scanner
steps:
- name: Check out code from GitHub
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Restore Python
uses: ./.github/actions/restore-python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Cache ESPHome
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
path: ~/.esphome-idf
key: ${{ runner.os }}-esphome-${{ needs.common.outputs.cache-key }}
- name: Run native ESP-IDF compile test
run: |
. venv/bin/activate
# Check if /mnt has more free space than / before bind mounting
# Extract available space in KB for comparison
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"
# Only use /mnt if it has more space than /
if [ -n "$mnt_avail" ] && [ "$mnt_avail" -gt "$root_avail" ]; then
echo "Using /mnt for build files (more space available)"
# Bind mount PlatformIO directory to /mnt (tools, packages, build cache all go there)
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
# Bind mount test build directory to /mnt
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
echo "Testing components: $TEST_COMPONENTS"
echo ""
# Show disk space before validation (after bind mounts setup)
echo "Disk space before config validation:"
df -h
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 "Config validation passed! Starting compilation..."
echo ""
# Show disk space before compilation
echo "Disk space before compilation:"
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@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
path: ~/.esphome-idf
key: ${{ runner.os }}-esphome-${{ needs.common.outputs.cache-key }}
pre-commit-ci-lite:
name: pre-commit.ci lite
runs-on: ubuntu-latest
@@ -1147,8 +1013,8 @@ jobs:
- memory-impact-pr-branch
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && fromJSON(needs.determine-jobs.outputs.memory_impact).should_run == 'true' && needs.memory-impact-target-branch.outputs.skip != 'true'
permissions:
contents: read # actions/checkout to load the comment-posting script
pull-requests: write # ci_memory_impact_comment.py posts/updates the memory-impact comment on the PR
contents: read
pull-requests: write
env:
GH_TOKEN: ${{ github.token }}
steps:
@@ -1197,9 +1063,7 @@ jobs:
- clang-tidy-nosplit
- clang-tidy-split
- determine-jobs
- device-builder
- test-build-components-split
- test-native-idf
- pre-commit-ci-lite
- memory-impact-target-branch
- memory-impact-pr-branch

View File

@@ -6,8 +6,8 @@ on:
types: [opened, reopened]
permissions:
pull-requests: write # pulls.update to close the PR opened from a fork's default branch
issues: write # issues.createComment to explain to the contributor why the PR was closed
pull-requests: write
issues: write
jobs:
close:

View File

@@ -15,9 +15,9 @@ on:
- beta
permissions:
issues: write # issues.addLabels / removeLabel to manage the 'code-owner-approved' label on the PR
pull-requests: read # listReviews to determine whether a codeowner has approved
contents: read # actions/checkout to read CODEOWNERS and the shared codeowners.js helper
issues: write
pull-requests: read
contents: read
jobs:
codeowner-approved:

View File

@@ -17,10 +17,9 @@ on:
- release
- beta
# PR/review writes (requestReviewers, issues.createComment) are performed with the App token minted below,
# so the workflow's GITHUB_TOKEN only needs read access for checkout.
permissions:
contents: read # actions/checkout to read CODEOWNERS and the shared codeowners.js helper
pull-requests: write
contents: read
jobs:
request-codeowner-reviews:
@@ -33,20 +32,9 @@ jobs:
with:
ref: ${{ github.event.pull_request.base.sha }}
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
client-id: ${{ vars.ESPHOME_GITHUB_APP_CLIENT_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
# Scope the minted App token to the minimum needed by the github-script step below.
permission-pull-requests: write # pulls.listFiles, pulls.get, pulls.listReviews, pulls.requestReviewers
permission-issues: write # issues.listComments and issues.createComment (PR comments use the issues API)
- name: Request reviews from component codeowners
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ steps.generate-token.outputs.token }}
script: |
const { loadCodeowners, getEffectiveOwners } = require('./.github/scripts/codeowners.js');

View File

@@ -16,9 +16,6 @@ on:
schedule:
- cron: "30 18 * * 4"
# Deny by default; the analyze job opts in to exactly what it needs.
permissions: {}
jobs:
analyze:
name: Analyze (${{ matrix.language }})
@@ -29,10 +26,15 @@ jobs:
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
permissions:
security-events: write # upload CodeQL SARIF results to the Code Scanning API
packages: read # fetch internal or private CodeQL query packs
actions: read # required by codeql-action when run from a private repo
contents: read # actions/checkout to scan the repository
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
@@ -56,7 +58,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
@@ -84,6 +86,6 @@ jobs:
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
with:
category: "/language:${{matrix.language}}"

View File

@@ -4,29 +4,20 @@ on:
pull_request_target:
types: [opened, synchronize]
# All API calls (pulls.listFiles + issues.{list,create,update}Comment) are performed with
# the App token minted below, so the workflow's GITHUB_TOKEN does not need any scopes.
permissions: {}
permissions:
contents: read # Needed to fetch PR details
issues: write # Needed to create and update comments (PR comments are managed via the issues REST API)
pull-requests: write # also needed?
jobs:
external-comment:
name: External component comment
runs-on: ubuntu-latest
steps:
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
client-id: ${{ vars.ESPHOME_GITHUB_APP_CLIENT_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
# pulls.listFiles + issues.{list,create,update}Comment on PRs. For PR resources
# the issues.*Comment APIs require the pull-requests scope, not issues.
permission-pull-requests: write
- name: Add external component comment
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ steps.generate-token.outputs.token }}
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
// Generate external component usage instructions
function generateExternalComponentInstructions(prNumber, componentNames, owner, repo) {

View File

@@ -9,8 +9,8 @@ on:
types: [labeled]
permissions:
issues: write # issues.createComment to mention component codeowners on the newly labelled issue
contents: read # repos.getContent to fetch CODEOWNERS from the default branch
issues: write
contents: read
jobs:
notify-codeowners:

View File

@@ -6,12 +6,6 @@ on:
- cron: "30 0 * * *" # Run daily at 00:30 UTC
workflow_dispatch:
# Deny by default; the lock job opts in to exactly what the reusable workflow needs.
permissions: {}
jobs:
lock:
permissions:
issues: write # issues.lock on closed issues
pull-requests: write # issues.lock on closed pull requests
uses: esphome/workflows/.github/workflows/lock.yml@025a1e6255610c498ed590403b7e510b69e474df # 2026.4.1
uses: esphome/workflows/.github/workflows/lock.yml@3c4e8446aa1029f1c346a482034b3ee1489077ca # 2026.4.0

View File

@@ -8,8 +8,8 @@ on:
- beta
permissions:
contents: read # actions/checkout to load detect-tags.js
pull-requests: read # pulls.listFiles to map changed files to component/core/dashboard/ci tags
contents: read
pull-requests: read
jobs:
check:

View File

@@ -9,7 +9,7 @@ on:
- cron: "0 2 * * *"
permissions:
contents: read # actions/checkout for all jobs; deploy jobs add their own scopes when they need to write
contents: read
jobs:
init:
@@ -57,8 +57,8 @@ jobs:
if: github.repository == 'esphome/esphome' && github.event_name == 'release'
runs-on: ubuntu-latest
permissions:
contents: read # actions/checkout to build the sdist/wheel
id-token: write # OIDC token for PyPI Trusted Publishing (pypa/gh-action-pypi-publish)
contents: read
id-token: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Python
@@ -78,8 +78,8 @@ jobs:
name: Build ESPHome ${{ matrix.platform.arch }}
if: github.repository == 'esphome/esphome'
permissions:
contents: read # actions/checkout to load Dockerfile and build context
packages: write # docker/login-action + build-push-action push image digests to ghcr.io
contents: read
packages: write
runs-on: ${{ matrix.platform.os }}
needs: [init]
strategy:
@@ -152,8 +152,8 @@ jobs:
- deploy-docker
if: github.repository == 'esphome/esphome'
permissions:
contents: read # actions/checkout to load Dockerfile and build context
packages: write # docker/login-action + build-push-action push image digests to ghcr.io
contents: read
packages: write
strategy:
fail-fast: false
matrix:
@@ -223,11 +223,10 @@ jobs:
id: generate-token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
client-id: ${{ vars.ESPHOME_GITHUB_APP_CLIENT_ID }}
app-id: ${{ secrets.ESPHOME_GITHUB_APP_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
owner: esphome
repositories: home-assistant-addon
permission-actions: write # actions.createWorkflowDispatch on the target repo (only API call made with this token)
- name: Trigger Workflow
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
@@ -259,11 +258,10 @@ jobs:
id: generate-token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
client-id: ${{ vars.ESPHOME_GITHUB_APP_CLIENT_ID }}
app-id: ${{ secrets.ESPHOME_GITHUB_APP_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
owner: esphome
repositories: esphome-schema
permission-actions: write # actions.createWorkflowDispatch on the target repo (only API call made with this token)
- name: Trigger Workflow
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
@@ -291,11 +289,10 @@ jobs:
id: generate-token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
client-id: ${{ vars.ESPHOME_GITHUB_APP_CLIENT_ID }}
app-id: ${{ secrets.ESPHOME_GITHUB_APP_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
owner: esphome
repositories: version-notifier
permission-actions: write # actions.createWorkflowDispatch on the target repo (only API call made with this token)
- name: Trigger Workflow
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0

View File

@@ -7,8 +7,8 @@ on:
workflow_dispatch:
permissions:
issues: write # actions/stale labels, comments on, and closes stale issues
pull-requests: write # actions/stale labels, comments on, and closes stale pull requests
issues: write
pull-requests: write
concurrency:
group: lock

View File

@@ -4,9 +4,6 @@ on:
pull_request:
types: [opened, reopened, labeled, unlabeled, synchronize]
permissions:
pull-requests: read # issues.listLabelsOnIssue to detect blocking labels (needs-docs, merge-after-release, chained-pr)
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true

View File

@@ -6,27 +6,12 @@ on:
schedule:
- cron: "45 6 * * *"
# Repo writes (branch push, PR open) happen via the App token minted below,
# so the workflow's GITHUB_TOKEN does not need any write scopes.
permissions:
contents: read # actions/checkout for this repo and home-assistant/core
jobs:
sync:
name: Sync Device Classes
runs-on: ubuntu-latest
if: github.repository == 'esphome/esphome'
steps:
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
with:
client-id: ${{ vars.ESPHOME_GITHUB_APP_CLIENT_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
# Scope the minted App token to the minimum needed by peter-evans/create-pull-request.
permission-contents: write # git.createCommit + refs.create/update to push the sync/device-classes branch
permission-pull-requests: write # pulls.create / pulls.update to open or refresh the sync PR
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -65,4 +50,4 @@ jobs:
delete-branch: true
title: "Synchronise Device Classes from Home Assistant"
body-path: .github/PULL_REQUEST_TEMPLATE.md
token: ${{ steps.generate-token.outputs.token }}
token: ${{ secrets.DEVICE_CLASS_SYNC_TOKEN }}

View File

@@ -55,7 +55,7 @@ repos:
hooks:
- id: pylint
name: pylint
entry: python script/run-in-env.py pylint
entry: python3 script/run-in-env.py pylint
language: system
types: [python]
files: ^esphome/.+\.py$
@@ -68,5 +68,5 @@ repos:
additional_dependencies: []
- id: ci-custom
name: ci-custom
entry: python script/run-in-env.py script/ci-custom.py
entry: python3 script/run-in-env.py script/ci-custom.py
language: system

View File

@@ -416,7 +416,6 @@ esphome/components/resampler/speaker/* @kahrendt
esphome/components/restart/* @esphome/core
esphome/components/rf_bridge/* @jesserockz
esphome/components/rgbct/* @jesserockz
esphome/components/ring_buffer/* @kahrendt
esphome/components/rp2040/* @jesserockz
esphome/components/rp2040_ble/* @bdraco
esphome/components/rp2040_pio_led_strip/* @Papa-DMan

View File

@@ -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."

View File

@@ -49,12 +49,5 @@ if bashio::fs.directory_exists '/config/esphome/.esphome'; then
rm -rf /config/esphome/.esphome
fi
if bashio::config.true 'use_new_device_builder'; then
bashio::log.info "Starting ESPHome Device Builder..."
exec esphome-device-builder /config/esphome \
--ha-addon \
--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

View File

@@ -4,14 +4,6 @@
# 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

View File

@@ -5,14 +5,6 @@
# Runs the NGINX proxy
# ==============================================================================
# The new device builder handles HA ingress itself, so nginx is bypassed.
# Block the longrun forever so s6 keeps the dependency satisfied and does
# not respawn it.
if bashio::config.true 'use_new_device_builder'; then
bashio::log.info "NGINX bypassed: new device builder serves ingress directly."
exec sleep infinity
fi
bashio::log.info "Waiting for ESPHome dashboard to come up..."
while [[ ! -S /var/run/esphome.sock ]]; do

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,7 @@ from .helpers import (
from .toolchain import find_tool, resolve_tool_path, run_tool
if TYPE_CHECKING:
from esphome.platformio.toolchain import IDEData
from esphome.platformio_api import IDEData
_LOGGER = logging.getLogger(__name__)

View File

@@ -739,7 +739,7 @@ def main():
import json
from pathlib import Path
from esphome.platformio.toolchain import IDEData
from esphome.platformio_api import IDEData
build_path = Path(build_dir)

View File

@@ -6,7 +6,6 @@ from pathlib import Path
from esphome.components.esp32 import get_esp32_variant
from esphome.core import CORE
from esphome.helpers import mkdir_p, write_file_if_changed
from esphome.writer import update_storage_json
def get_available_components() -> list[str] | None:
@@ -55,7 +54,7 @@ def get_project_cmakelists() -> str:
idf_target = variant.lower().replace("-", "")
# Extract compile definitions from build flags (-DXXX -> XXX)
compile_defs = [flag for flag in sorted(CORE.build_flags) if flag.startswith("-D")]
compile_defs = [flag for flag in CORE.build_flags if flag.startswith("-D")]
extra_compile_options = "\n".join(
f'idf_build_set_property(COMPILE_OPTIONS "{compile_def}" APPEND)'
for compile_def in compile_defs
@@ -65,22 +64,6 @@ def get_project_cmakelists() -> str:
# Auto-generated by ESPHome
cmake_minimum_required(VERSION 3.16)
# On Windows, Ninja can fail with:
# "CreateProcess: The parameter is incorrect (is the command line too long?)"
# when compiler/linker command lines exceed the OS length limit.
#
# The following settings force CMake/Ninja to use *response files* (@file.rsp)
# to pass long lists of includes, objects, and other arguments indirectly,
# avoiding command-line length limits and fixing the build failure.
#
# This is especially useful for large ESP-IDF / ESPHome projects with many
# source files or include directories.
set(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1)
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1)
set(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1)
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1)
set(CMAKE_NINJA_FORCE_RESPONSE_FILE 1)
set(IDF_TARGET {idf_target})
set(EXTRA_COMPONENT_DIRS ${{CMAKE_SOURCE_DIR}}/src)
@@ -141,11 +124,6 @@ target_link_options(${{COMPONENT_LIB}} PUBLIC
def write_project(minimal: bool = False) -> None:
"""Write ESP-IDF project files."""
# Refresh <data_dir>/storage/<name>.yaml.json so the dashboard's
# /info and /downloads endpoints can locate the build (they 404
# otherwise). This mirrors the PlatformIO build-gen path's call
# in build_gen/platformio.py:write_ini().
update_storage_json()
mkdir_p(CORE.build_path)
mkdir_p(CORE.relative_src_path())

View File

@@ -98,13 +98,11 @@ _KNOWN_FILE_EXTENSIONS = frozenset(
)
# Matches !secret references in YAML text. An optional surrounding
# quote pair around the key is allowed and ignored: YAML treats
# ``!secret 'foo'`` and ``!secret foo`` as the same key. This is
# intentionally a simple regex scan rather than a YAML parse — it may
# match inside comments or multi-line strings, which is the conservative
# direction (include more secrets rather than fewer).
_SECRET_RE = re.compile(r"""!secret\s+['"]?([^\s'"]+)""")
# Matches !secret references in YAML text. This is intentionally a simple
# regex scan rather than a YAML parse — it may match inside comments or
# multi-line strings, which is the conservative direction (include more
# secrets rather than fewer).
_SECRET_RE = re.compile(r"!secret\s+(\S+)")
def _find_used_secret_keys(yaml_files: list[Path]) -> set[str]:

View File

@@ -4,7 +4,8 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome::a01nyub {
namespace esphome {
namespace a01nyub {
static const char *const TAG = "a01nyub.sensor";
@@ -41,4 +42,5 @@ void A01nyubComponent::check_buffer_() {
void A01nyubComponent::dump_config() { LOG_SENSOR("", "A01nyub Sensor", this); }
} // namespace esphome::a01nyub
} // namespace a01nyub
} // namespace esphome

View File

@@ -6,7 +6,8 @@
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/uart/uart.h"
namespace esphome::a01nyub {
namespace esphome {
namespace a01nyub {
class A01nyubComponent : public sensor::Sensor, public Component, public uart::UARTDevice {
public:
@@ -22,4 +23,5 @@ class A01nyubComponent : public sensor::Sensor, public Component, public uart::U
std::vector<uint8_t> buffer_;
};
} // namespace esphome::a01nyub
} // namespace a01nyub
} // namespace esphome

View File

@@ -4,7 +4,8 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome::a02yyuw {
namespace esphome {
namespace a02yyuw {
static const char *const TAG = "a02yyuw.sensor";
@@ -40,4 +41,5 @@ void A02yyuwComponent::check_buffer_() {
void A02yyuwComponent::dump_config() { LOG_SENSOR("", "A02yyuw Sensor", this); }
} // namespace esphome::a02yyuw
} // namespace a02yyuw
} // namespace esphome

View File

@@ -6,7 +6,8 @@
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/uart/uart.h"
namespace esphome::a02yyuw {
namespace esphome {
namespace a02yyuw {
class A02yyuwComponent : public sensor::Sensor, public Component, public uart::UARTDevice {
public:
@@ -22,4 +23,5 @@ class A02yyuwComponent : public sensor::Sensor, public Component, public uart::U
std::vector<uint8_t> buffer_;
};
} // namespace esphome::a02yyuw
} // namespace a02yyuw
} // namespace esphome

View File

@@ -1,7 +1,8 @@
#include "a4988.h"
#include "esphome/core/log.h"
namespace esphome::a4988 {
namespace esphome {
namespace a4988 {
static const char *const TAG = "a4988.stepper";
@@ -50,4 +51,5 @@ void A4988::loop() {
this->step_pin_->digital_write(false);
}
} // namespace esphome::a4988
} // namespace a4988
} // namespace esphome

View File

@@ -4,7 +4,8 @@
#include "esphome/core/hal.h"
#include "esphome/components/stepper/stepper.h"
namespace esphome::a4988 {
namespace esphome {
namespace a4988 {
class A4988 : public stepper::Stepper, public Component {
public:
@@ -24,4 +25,5 @@ class A4988 : public stepper::Stepper, public Component {
HighFrequencyLoopRequester high_freq_;
};
} // namespace esphome::a4988
} // namespace a4988
} // namespace esphome

View File

@@ -1,7 +1,8 @@
#include "adalight_light_effect.h"
#include "esphome/core/log.h"
namespace esphome::adalight {
namespace esphome {
namespace adalight {
static const char *const TAG = "adalight_light_effect";
@@ -137,4 +138,5 @@ AdalightLightEffect::Frame AdalightLightEffect::parse_frame_(light::AddressableL
return CONSUMED;
}
} // namespace esphome::adalight
} // namespace adalight
} // namespace esphome

View File

@@ -6,7 +6,8 @@
#include <vector>
namespace esphome::adalight {
namespace esphome {
namespace adalight {
class AdalightLightEffect : public light::AddressableLightEffect, public uart::UARTDevice {
public:
@@ -34,4 +35,5 @@ class AdalightLightEffect : public light::AddressableLightEffect, public uart::U
std::vector<uint8_t> frame_;
};
} // namespace esphome::adalight
} // namespace adalight
} // namespace esphome

View File

@@ -17,7 +17,8 @@
#include <zephyr/drivers/adc.h>
#endif
namespace esphome::adc {
namespace esphome {
namespace adc {
#ifdef USE_ESP32
// clang-format off
@@ -161,4 +162,5 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
#endif
};
} // namespace esphome::adc
} // namespace adc
} // namespace esphome

View File

@@ -1,7 +1,8 @@
#include "adc_sensor.h"
#include "esphome/core/log.h"
namespace esphome::adc {
namespace esphome {
namespace adc {
static const char *const TAG = "adc.common";
@@ -78,4 +79,5 @@ void ADCSensor::set_sample_count(uint8_t sample_count) {
void ADCSensor::set_sampling_mode(SamplingMode sampling_mode) { this->sampling_mode_ = sampling_mode; }
} // namespace esphome::adc
} // namespace adc
} // namespace esphome

View File

@@ -4,7 +4,8 @@
#include "esphome/core/log.h"
#include <cinttypes>
namespace esphome::adc {
namespace esphome {
namespace adc {
static const char *const TAG = "adc.esp32";
@@ -363,6 +364,7 @@ float ADCSensor::sample_autorange_() {
return final_result;
}
} // namespace esphome::adc
} // namespace adc
} // namespace esphome
#endif // USE_ESP32

View File

@@ -11,7 +11,8 @@ ADC_MODE(ADC_VCC)
#include <Arduino.h>
#endif // USE_ADC_SENSOR_VCC
namespace esphome::adc {
namespace esphome {
namespace adc {
static const char *const TAG = "adc.esp8266";
@@ -54,6 +55,7 @@ float ADCSensor::sample() {
return aggr.aggregate() / 1024.0f;
}
} // namespace esphome::adc
} // namespace adc
} // namespace esphome
#endif // USE_ESP8266

View File

@@ -3,7 +3,8 @@
#include "adc_sensor.h"
#include "esphome/core/log.h"
namespace esphome::adc {
namespace esphome {
namespace adc {
static const char *const TAG = "adc.libretiny";
@@ -47,6 +48,7 @@ float ADCSensor::sample() {
return aggr.aggregate() / 1000.0f;
}
} // namespace esphome::adc
} // namespace adc
} // namespace esphome
#endif // USE_LIBRETINY

View File

@@ -15,7 +15,8 @@
#define PICO_VSYS_PIN 29 // NOLINT(cppcoreguidelines-macro-usage)
#endif
namespace esphome::adc {
namespace esphome {
namespace adc {
static const char *const TAG = "adc.rp2040";
@@ -97,6 +98,7 @@ float ADCSensor::sample() {
return aggr.aggregate() * 3.3f / 4096.0f * coeff;
}
} // namespace esphome::adc
} // namespace adc
} // namespace esphome
#endif // USE_RP2040

View File

@@ -5,7 +5,8 @@
#include "hal/nrf_saadc.h"
namespace esphome::adc {
namespace esphome {
namespace adc {
static const char *const TAG = "adc.zephyr";
@@ -201,5 +202,6 @@ float ADCSensor::sample() {
return val_mv / 1000.0f;
}
} // namespace esphome::adc
} // namespace adc
} // namespace esphome
#endif

View File

@@ -1,7 +1,8 @@
#include "adc128s102.h"
#include "esphome/core/log.h"
namespace esphome::adc128s102 {
namespace esphome {
namespace adc128s102 {
static const char *const TAG = "adc128s102";
@@ -27,4 +28,5 @@ uint16_t ADC128S102::read_data(uint8_t channel) {
return digital_value;
}
} // namespace esphome::adc128s102
} // namespace adc128s102
} // namespace esphome

View File

@@ -4,7 +4,8 @@
#include "esphome/core/hal.h"
#include "esphome/components/spi/spi.h"
namespace esphome::adc128s102 {
namespace esphome {
namespace adc128s102 {
class ADC128S102 : public Component,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
@@ -18,4 +19,5 @@ class ADC128S102 : public Component,
uint16_t read_data(uint8_t channel);
};
} // namespace esphome::adc128s102
} // namespace adc128s102
} // namespace esphome

View File

@@ -2,7 +2,8 @@
#include "esphome/core/log.h"
namespace esphome::adc128s102 {
namespace esphome {
namespace adc128s102 {
static const char *const TAG = "adc128s102.sensor";
@@ -17,4 +18,5 @@ void ADC128S102Sensor::dump_config() {
float ADC128S102Sensor::sample() { return this->parent_->read_data(this->channel_); }
void ADC128S102Sensor::update() { this->publish_state(this->sample()); }
} // namespace esphome::adc128s102
} // namespace adc128s102
} // namespace esphome

View File

@@ -7,7 +7,8 @@
#include "../adc128s102.h"
namespace esphome::adc128s102 {
namespace esphome {
namespace adc128s102 {
class ADC128S102Sensor : public PollingComponent,
public Parented<ADC128S102>,
@@ -23,4 +24,5 @@ class ADC128S102Sensor : public PollingComponent,
protected:
uint8_t channel_;
};
} // namespace esphome::adc128s102
} // namespace adc128s102
} // namespace esphome

View File

@@ -1,7 +1,8 @@
#include "addressable_light_display.h"
#include "esphome/core/log.h"
namespace esphome::addressable_light {
namespace esphome {
namespace addressable_light {
static const char *const TAG = "addressable_light.display";
@@ -65,4 +66,5 @@ void HOT AddressableLightDisplay::draw_absolute_pixel_internal(int x, int y, Col
this->addressable_light_buffer_[y * this->get_width_internal() + x] = color;
}
}
} // namespace esphome::addressable_light
} // namespace addressable_light
} // namespace esphome

View File

@@ -7,7 +7,8 @@
#include <vector>
namespace esphome::addressable_light {
namespace esphome {
namespace addressable_light {
class AddressableLightDisplay : public display::DisplayBuffer {
public:
@@ -60,4 +61,5 @@ class AddressableLightDisplay : public display::DisplayBuffer {
optional<uint32_t> last_effect_index_;
optional<std::function<int(int, int)>> pixel_mapper_f_;
};
} // namespace esphome::addressable_light
} // namespace addressable_light
} // namespace esphome

View File

@@ -13,7 +13,8 @@
#include <cinttypes>
namespace esphome::ade7880 {
namespace esphome {
namespace ade7880 {
static const char *const TAG = "ade7880";
@@ -312,4 +313,5 @@ void ADE7880::reset_device_() {
this->store_.reset_pending = true;
}
} // namespace esphome::ade7880
} // namespace ade7880
} // namespace esphome

View File

@@ -16,7 +16,8 @@
#include "ade7880_registers.h"
namespace esphome::ade7880 {
namespace esphome {
namespace ade7880 {
struct NeutralChannel {
void set_current(sensor::Sensor *sens) { this->current = sens; }
@@ -124,4 +125,5 @@ class ADE7880 : public i2c::I2CDevice, public PollingComponent {
void write_u32_register16_(uint16_t a_register, uint32_t value);
};
} // namespace esphome::ade7880
} // namespace ade7880
} // namespace esphome

View File

@@ -9,7 +9,8 @@
#include "ade7880.h"
namespace esphome::ade7880 {
namespace esphome {
namespace ade7880 {
// adapted from https://stackoverflow.com/a/55912127/1886371
template<size_t Bits, typename T> inline T sign_extend(const T &v) noexcept {
@@ -96,4 +97,5 @@ void ADE7880::write_u32_register16_(uint16_t a_register, uint32_t value) {
this->write_register16(a_register, reinterpret_cast<uint8_t *>(&out), sizeof(out));
}
} // namespace esphome::ade7880
} // namespace ade7880
} // namespace esphome

View File

@@ -4,7 +4,8 @@
// Source: https://www.analog.com/media/en/technical-documentation/application-notes/AN-1127.pdf
namespace esphome::ade7880 {
namespace esphome {
namespace ade7880 {
// DSP Data Memory RAM registers
constexpr uint16_t AIGAIN = 0x4380;
@@ -241,4 +242,5 @@ constexpr uint8_t DSPWP_SET_RO = (1 << 7);
// DSPWP_SEL Register Bits
constexpr uint8_t DSPWP_SEL_SET = 0xAD;
} // namespace esphome::ade7880
} // namespace ade7880
} // namespace esphome

View File

@@ -3,7 +3,8 @@
#include <cinttypes>
namespace esphome::ade7953_base {
namespace esphome {
namespace ade7953_base {
static const char *const TAG = "ade7953";
@@ -159,4 +160,5 @@ void ADE7953::update() {
ADE_PUBLISH(frequency, 223750.0f, 1 + val_16);
}
} // namespace esphome::ade7953_base
} // namespace ade7953_base
} // namespace esphome

View File

@@ -6,7 +6,8 @@
#include <vector>
namespace esphome::ade7953_base {
namespace esphome {
namespace ade7953_base {
static constexpr uint8_t PGA_V_8 =
0x007; // PGA_V, (R/W) Default: 0x00, Unsigned, Voltage channel gain configuration (Bits[2:0])
@@ -130,4 +131,5 @@ class ADE7953 : public PollingComponent, public sensor::Sensor {
virtual bool ade_read_32(uint16_t reg, uint32_t *value) = 0;
};
} // namespace esphome::ade7953_base
} // namespace ade7953_base
} // namespace esphome

View File

@@ -2,7 +2,8 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome::ade7953_i2c {
namespace esphome {
namespace ade7953_i2c {
static const char *const TAG = "ade7953";
@@ -75,4 +76,5 @@ bool AdE7953I2c::ade_read_32(uint16_t reg, uint32_t *value) {
return false;
}
} // namespace esphome::ade7953_i2c
} // namespace ade7953_i2c
} // namespace esphome

View File

@@ -8,7 +8,8 @@
#include <vector>
namespace esphome::ade7953_i2c {
namespace esphome {
namespace ade7953_i2c {
class AdE7953I2c : public ade7953_base::ADE7953, public i2c::I2CDevice {
public:
@@ -23,4 +24,5 @@ class AdE7953I2c : public ade7953_base::ADE7953, public i2c::I2CDevice {
bool ade_read_32(uint16_t reg, uint32_t *value) override;
};
} // namespace esphome::ade7953_i2c
} // namespace ade7953_i2c
} // namespace esphome

View File

@@ -2,7 +2,8 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome::ade7953_spi {
namespace esphome {
namespace ade7953_spi {
static const char *const TAG = "ade7953";
@@ -82,4 +83,5 @@ bool AdE7953Spi::ade_read_32(uint16_t reg, uint32_t *value) {
return false;
}
} // namespace esphome::ade7953_spi
} // namespace ade7953_spi
} // namespace esphome

View File

@@ -8,7 +8,8 @@
#include <vector>
namespace esphome::ade7953_spi {
namespace esphome {
namespace ade7953_spi {
class AdE7953Spi : public ade7953_base::ADE7953,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_HIGH, spi::CLOCK_PHASE_TRAILING,
@@ -27,4 +28,5 @@ class AdE7953Spi : public ade7953_base::ADE7953,
bool ade_read_32(uint16_t reg, uint32_t *value) override;
};
} // namespace esphome::ade7953_spi
} // namespace ade7953_spi
} // namespace esphome

View File

@@ -2,7 +2,8 @@
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
namespace esphome::ads1115 {
namespace esphome {
namespace ads1115 {
static const char *const TAG = "ads1115";
static const uint8_t ADS1115_REGISTER_CONVERSION = 0x00;
@@ -207,4 +208,5 @@ float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1
return millivolts / 1e3f;
}
} // namespace esphome::ads1115
} // namespace ads1115
} // namespace esphome

View File

@@ -5,7 +5,8 @@
#include <vector>
namespace esphome::ads1115 {
namespace esphome {
namespace ads1115 {
enum ADS1115Multiplexer {
ADS1115_MULTIPLEXER_P0_N1 = 0b000,
@@ -59,4 +60,5 @@ class ADS1115Component : public Component, public i2c::I2CDevice {
bool continuous_mode_;
};
} // namespace esphome::ads1115
} // namespace ads1115
} // namespace esphome

View File

@@ -2,7 +2,8 @@
#include "esphome/core/log.h"
namespace esphome::ads1115 {
namespace esphome {
namespace ads1115 {
static const char *const TAG = "ads1115.sensor";
@@ -28,4 +29,5 @@ void ADS1115Sensor::dump_config() {
this->multiplexer_, this->gain_, this->resolution_, this->samplerate_);
}
} // namespace esphome::ads1115
} // namespace ads1115
} // namespace esphome

View File

@@ -8,7 +8,8 @@
#include "../ads1115.h"
namespace esphome::ads1115 {
namespace esphome {
namespace ads1115 {
/// Internal holder class that is in instance of Sensor so that the hub can create individual sensors.
class ADS1115Sensor : public sensor::Sensor,
@@ -32,4 +33,5 @@ class ADS1115Sensor : public sensor::Sensor,
ADS1115Samplerate samplerate_;
};
} // namespace esphome::ads1115
} // namespace ads1115
} // namespace esphome

View File

@@ -2,7 +2,8 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome::ads1118 {
namespace esphome {
namespace ads1118 {
static const char *const TAG = "ads1118";
static const uint8_t ADS1118_DATA_RATE_860_SPS = 0b111;
@@ -121,4 +122,5 @@ float ADS1118::request_measurement(ADS1118Multiplexer multiplexer, ADS1118Gain g
}
}
} // namespace esphome::ads1118
} // namespace ads1118
} // namespace esphome

View File

@@ -4,7 +4,8 @@
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
namespace esphome::ads1118 {
namespace esphome {
namespace ads1118 {
enum ADS1118Multiplexer {
ADS1118_MULTIPLEXER_P0_N1 = 0b000,
@@ -40,4 +41,5 @@ class ADS1118 : public Component,
uint16_t config_{0};
};
} // namespace esphome::ads1118
} // namespace ads1118
} // namespace esphome

View File

@@ -2,7 +2,8 @@
#include "esphome/core/log.h"
namespace esphome::ads1118 {
namespace esphome {
namespace ads1118 {
static const char *const TAG = "ads1118.sensor";
@@ -26,4 +27,5 @@ void ADS1118Sensor::update() {
}
}
} // namespace esphome::ads1118
} // namespace ads1118
} // namespace esphome

View File

@@ -8,7 +8,8 @@
#include "../ads1118.h"
namespace esphome::ads1118 {
namespace esphome {
namespace ads1118 {
class ADS1118Sensor : public PollingComponent,
public sensor::Sensor,
@@ -31,4 +32,5 @@ class ADS1118Sensor : public PollingComponent,
bool temperature_mode_;
};
} // namespace esphome::ads1118
} // namespace ads1118
} // namespace esphome

View File

@@ -3,7 +3,8 @@
#include <cinttypes>
namespace esphome::ags10 {
namespace esphome {
namespace ags10 {
static const char *const TAG = "ags10";
// Data acquisition.
@@ -191,4 +192,5 @@ template<size_t N> optional<std::array<uint8_t, N>> AGS10Component::read_and_che
return data;
}
} // namespace esphome::ags10
} // namespace ags10
} // namespace esphome

View File

@@ -5,7 +5,8 @@
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
namespace esphome::ags10 {
namespace esphome {
namespace ags10 {
class AGS10Component : public PollingComponent, public i2c::I2CDevice {
public:
@@ -135,4 +136,5 @@ template<typename... Ts> class AGS10SetZeroPointAction : public Action<Ts...>, p
}
}
};
} // namespace esphome::ags10
} // namespace ags10
} // namespace esphome

View File

@@ -17,7 +17,8 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome::aht10 {
namespace esphome {
namespace aht10 {
static const char *const TAG = "aht10";
static const uint8_t AHT10_INITIALIZE_CMD[] = {0xE1, 0x08, 0x00};
@@ -159,4 +160,5 @@ void AHT10Component::dump_config() {
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
}
} // namespace esphome::aht10
} // namespace aht10
} // namespace esphome

View File

@@ -6,7 +6,8 @@
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome::aht10 {
namespace esphome {
namespace aht10 {
enum AHT10Variant { AHT10, AHT20 };
@@ -30,4 +31,5 @@ class AHT10Component : public PollingComponent, public i2c::I2CDevice {
uint32_t start_time_{};
};
} // namespace esphome::aht10
} // namespace aht10
} // namespace esphome

View File

@@ -4,7 +4,8 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome::aic3204 {
namespace esphome {
namespace aic3204 {
static const char *const TAG = "aic3204";
@@ -166,4 +167,5 @@ bool AIC3204::write_volume_() {
return true;
}
} // namespace esphome::aic3204
} // namespace aic3204
} // namespace esphome

View File

@@ -6,7 +6,8 @@
#include "esphome/core/defines.h"
#include "esphome/core/hal.h"
namespace esphome::aic3204 {
namespace esphome {
namespace aic3204 {
// TLV320AIC3204 Register Addresses
// Page 0
@@ -82,4 +83,5 @@ class AIC3204 : public audio_dac::AudioDac, public Component, public i2c::I2CDev
float volume_{0};
};
} // namespace esphome::aic3204
} // namespace aic3204
} // namespace esphome

View File

@@ -4,7 +4,8 @@
#include "esphome/core/component.h"
#include "aic3204.h"
namespace esphome::aic3204 {
namespace esphome {
namespace aic3204 {
template<typename... Ts> class SetAutoMuteAction : public Action<Ts...> {
public:
@@ -18,4 +19,5 @@ template<typename... Ts> class SetAutoMuteAction : public Action<Ts...> {
AIC3204 *aic3204_;
};
} // namespace esphome::aic3204
} // namespace aic3204
} // namespace esphome

View File

@@ -4,7 +4,8 @@
#ifdef USE_ESP32
namespace esphome::airthings_ble {
namespace esphome {
namespace airthings_ble {
static const char *const TAG = "airthings_ble";
@@ -28,6 +29,7 @@ bool AirthingsListener::parse_device(const esp32_ble_tracker::ESPBTDevice &devic
return false;
}
} // namespace esphome::airthings_ble
} // namespace airthings_ble
} // namespace esphome
#endif

View File

@@ -5,13 +5,15 @@
#include "esphome/core/component.h"
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
namespace esphome::airthings_ble {
namespace esphome {
namespace airthings_ble {
class AirthingsListener : public esp32_ble_tracker::ESPBTDeviceListener {
public:
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
};
} // namespace esphome::airthings_ble
} // namespace airthings_ble
} // namespace esphome
#endif

View File

@@ -6,7 +6,8 @@
#ifdef USE_ESP32
namespace esphome::airthings_wave_base {
namespace esphome {
namespace airthings_wave_base {
static const char *const TAG = "airthings_wave_base";
@@ -210,6 +211,7 @@ void AirthingsWaveBase::set_response_timeout_() {
});
}
} // namespace esphome::airthings_wave_base
} // namespace airthings_wave_base
} // namespace esphome
#endif // USE_ESP32

View File

@@ -14,7 +14,8 @@
#include "esphome/core/component.h"
#include "esphome/core/log.h"
namespace esphome::airthings_wave_base {
namespace esphome {
namespace airthings_wave_base {
namespace espbt = esphome::esp32_ble_tracker;
@@ -83,6 +84,7 @@ class AirthingsWaveBase : public PollingComponent, public ble_client::BLEClientN
};
};
} // namespace esphome::airthings_wave_base
} // namespace airthings_wave_base
} // namespace esphome
#endif // USE_ESP32

View File

@@ -2,7 +2,8 @@
#ifdef USE_ESP32
namespace esphome::airthings_wave_mini {
namespace esphome {
namespace airthings_wave_mini {
static const char *const TAG = "airthings_wave_mini";
@@ -48,6 +49,7 @@ AirthingsWaveMini::AirthingsWaveMini() {
espbt::ESPBTUUID::from_raw(ACCESS_CONTROL_POINT_CHARACTERISTIC_UUID);
}
} // namespace esphome::airthings_wave_mini
} // namespace airthings_wave_mini
} // namespace esphome
#endif // USE_ESP32

View File

@@ -4,7 +4,8 @@
#include "esphome/components/airthings_wave_base/airthings_wave_base.h"
namespace esphome::airthings_wave_mini {
namespace esphome {
namespace airthings_wave_mini {
namespace espbt = esphome::esp32_ble_tracker;
@@ -33,6 +34,7 @@ class AirthingsWaveMini : public airthings_wave_base::AirthingsWaveBase {
};
};
} // namespace esphome::airthings_wave_mini
} // namespace airthings_wave_mini
} // namespace esphome
#endif // USE_ESP32

View File

@@ -2,7 +2,8 @@
#ifdef USE_ESP32
namespace esphome::airthings_wave_plus {
namespace esphome {
namespace airthings_wave_plus {
static const char *const TAG = "airthings_wave_plus";
@@ -97,6 +98,7 @@ void AirthingsWavePlus::setup() {
espbt::ESPBTUUID::from_raw(access_control_point_characteristic_uuid);
}
} // namespace esphome::airthings_wave_plus
} // namespace airthings_wave_plus
} // namespace esphome
#endif // USE_ESP32

View File

@@ -4,7 +4,8 @@
#include "esphome/components/airthings_wave_base/airthings_wave_base.h"
namespace esphome::airthings_wave_plus {
namespace esphome {
namespace airthings_wave_plus {
namespace espbt = esphome::esp32_ble_tracker;
@@ -57,6 +58,7 @@ class AirthingsWavePlus : public airthings_wave_base::AirthingsWaveBase {
};
};
} // namespace esphome::airthings_wave_plus
} // namespace airthings_wave_plus
} // namespace esphome
#endif // USE_ESP32

View File

@@ -5,7 +5,8 @@
#ifdef USE_ESP32
namespace esphome::alpha3 {
namespace esphome {
namespace alpha3 {
static const char *const TAG = "alpha3";
@@ -184,6 +185,7 @@ void Alpha3::update() {
delay(25); // need to wait between requests
}
}
} // namespace esphome::alpha3
} // namespace alpha3
} // namespace esphome
#endif

View File

@@ -9,7 +9,8 @@
#include <esp_gattc_api.h>
namespace esphome::alpha3 {
namespace esphome {
namespace alpha3 {
namespace espbt = esphome::esp32_ble_tracker;
@@ -63,6 +64,7 @@ class Alpha3 : public esphome::ble_client::BLEClientNode, public PollingComponen
void send_request_(uint8_t *request, size_t len);
bool is_current_response_type_(const uint8_t *response_type);
};
} // namespace esphome::alpha3
} // namespace alpha3
} // namespace esphome
#endif

View File

@@ -24,7 +24,8 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome::am2315c {
namespace esphome {
namespace am2315c {
static const char *const TAG = "am2315c";
@@ -175,4 +176,5 @@ void AM2315C::dump_config() {
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
}
} // namespace esphome::am2315c
} // namespace am2315c
} // namespace esphome

View File

@@ -25,7 +25,8 @@
#include "esphome/components/sensor/sensor.h"
#include "esphome/core/component.h"
namespace esphome::am2315c {
namespace esphome {
namespace am2315c {
class AM2315C : public PollingComponent, public i2c::I2CDevice {
public:
@@ -44,4 +45,5 @@ class AM2315C : public PollingComponent, public i2c::I2CDevice {
sensor::Sensor *humidity_sensor_{nullptr};
};
} // namespace esphome::am2315c
} // namespace am2315c
} // namespace esphome

View File

@@ -8,7 +8,8 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome::am2320 {
namespace esphome {
namespace am2320 {
static const char *const TAG = "am2320";
@@ -85,4 +86,5 @@ bool AM2320Component::read_data_(uint8_t *data) {
return true;
}
} // namespace esphome::am2320
} // namespace am2320
} // namespace esphome

View File

@@ -4,7 +4,8 @@
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome::am2320 {
namespace esphome {
namespace am2320 {
class AM2320Component : public PollingComponent, public i2c::I2CDevice {
public:
@@ -23,4 +24,5 @@ class AM2320Component : public PollingComponent, public i2c::I2CDevice {
sensor::Sensor *humidity_sensor_{nullptr};
};
} // namespace esphome::am2320
} // namespace am2320
} // namespace esphome

View File

@@ -2,7 +2,8 @@
#include "esphome/core/helpers.h"
#include <cstring>
namespace esphome::am43 {
namespace esphome {
namespace am43 {
const uint8_t START_PACKET[5] = {0x00, 0xff, 0x00, 0x00, 0x9a};
@@ -133,4 +134,5 @@ void Am43Decoder::decode(const uint8_t *data, uint16_t length) {
}
};
} // namespace esphome::am43
} // namespace am43
} // namespace esphome

View File

@@ -3,7 +3,8 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome::am43 {
namespace esphome {
namespace am43 {
static const uint16_t AM43_SERVICE_UUID = 0xFE50;
static const uint16_t AM43_CHARACTERISTIC_UUID = 0xFE51;
@@ -73,4 +74,5 @@ class Am43Decoder {
bool has_pin_response_;
};
} // namespace esphome::am43
} // namespace am43
} // namespace esphome

View File

@@ -3,7 +3,8 @@
#ifdef USE_ESP32
namespace esphome::am43 {
namespace esphome {
namespace am43 {
static const char *const TAG = "am43_cover";
@@ -153,6 +154,7 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
}
}
} // namespace esphome::am43
} // namespace am43
} // namespace esphome
#endif

View File

@@ -10,7 +10,8 @@
#include <esp_gattc_api.h>
namespace esphome::am43 {
namespace esphome {
namespace am43 {
namespace espbt = esphome::esp32_ble_tracker;
@@ -37,6 +38,7 @@ class Am43Component : public cover::Cover, public esphome::ble_client::BLEClient
float position_;
};
} // namespace esphome::am43
} // namespace am43
} // namespace esphome
#endif

View File

@@ -4,7 +4,8 @@
#ifdef USE_ESP32
namespace esphome::am43 {
namespace esphome {
namespace am43 {
static const char *const TAG = "am43";
@@ -110,6 +111,7 @@ void Am43::update() {
}
}
} // namespace esphome::am43
} // namespace am43
} // namespace esphome
#endif

View File

@@ -10,7 +10,8 @@
#include <esp_gattc_api.h>
namespace esphome::am43 {
namespace esphome {
namespace am43 {
namespace espbt = esphome::esp32_ble_tracker;
@@ -37,6 +38,7 @@ class Am43 : public esphome::ble_client::BLEClientNode, public PollingComponent
uint32_t last_battery_update_;
};
} // namespace esphome::am43
} // namespace am43
} // namespace esphome
#endif

Some files were not shown because too many files have changed in this diff Show More