mirror of
https://github.com/esphome/esphome.git
synced 2026-09-17 18:18:43 +00:00
Merge remote-tracking branch 'upstream/dev' into integration
This commit is contained in:
@@ -96,7 +96,6 @@ 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,
|
||||
@@ -133,7 +132,6 @@ 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,
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
0c7f309d70eca8e3efd510092ddb23c530f3934c49371717efa124b788d761f8
|
||||
96c95feaa60831da5f43e3c6a7c7a3a237e17c5d12995a730dbc3884c8dcd11c
|
||||
|
||||
+1
-1
@@ -115,4 +115,4 @@ examples/
|
||||
Dockerfile
|
||||
.git/
|
||||
tests/
|
||||
.*
|
||||
.?*
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
const fs = require('fs');
|
||||
const { DOCS_PR_PATTERNS } = require('./constants');
|
||||
const {
|
||||
COMPONENT_REGEX,
|
||||
@@ -9,6 +8,31 @@ 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();
|
||||
@@ -45,52 +69,64 @@ async function detectComponentPlatforms(changedFiles, apiData) {
|
||||
}
|
||||
|
||||
// Strategy: New component detection
|
||||
async function detectNewComponents(prFiles) {
|
||||
async function detectNewComponents(github, context, 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) {
|
||||
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');
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return labels;
|
||||
return { labels, hasYamlLoadable };
|
||||
}
|
||||
|
||||
// Strategy: New platform detection
|
||||
async function detectNewPlatforms(prFiles, apiData) {
|
||||
async function detectNewPlatforms(github, context, prFiles, apiData) {
|
||||
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 platformFileMatch = file.match(/^esphome\/components\/([^\/]+)\/([^\/]+)\.py$/);
|
||||
if (platformFileMatch) {
|
||||
const [, component, platform] = platformFileMatch;
|
||||
if (apiData.platformComponents.includes(platform)) {
|
||||
labels.add('new-platform');
|
||||
}
|
||||
}
|
||||
const platformPathPatterns = [
|
||||
/^esphome\/components\/([^\/]+)\/([^\/]+)\.py$/,
|
||||
/^esphome\/components\/([^\/]+)\/([^\/]+)\/__init__\.py$/,
|
||||
];
|
||||
|
||||
const platformDirMatch = file.match(/^esphome\/components\/([^\/]+)\/([^\/]+)\/__init__\.py$/);
|
||||
if (platformDirMatch) {
|
||||
const [, component, platform] = platformDirMatch;
|
||||
if (apiData.platformComponents.includes(platform)) {
|
||||
labels.add('new-platform');
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return labels;
|
||||
return { labels, hasYamlLoadable };
|
||||
}
|
||||
|
||||
// Strategy: Core files detection
|
||||
@@ -300,7 +336,7 @@ function detectMaintainerAccess(context) {
|
||||
}
|
||||
|
||||
// Strategy: Requirements detection
|
||||
async function detectRequirements(allLabels, prFiles, context) {
|
||||
async function detectRequirements(allLabels, prFiles, context, hasYamlLoadable) {
|
||||
const labels = new Set();
|
||||
|
||||
// Check for missing tests
|
||||
@@ -308,8 +344,15 @@ async function detectRequirements(allLabels, prFiles, context) {
|
||||
labels.add('needs-tests');
|
||||
}
|
||||
|
||||
// Check for missing docs
|
||||
if (allLabels.has('new-component') || allLabels.has('new-platform') || allLabels.has('new-feature')) {
|
||||
// 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) {
|
||||
const prBody = context.payload.pull_request.body || '';
|
||||
const hasDocsLink = DOCS_PR_PATTERNS.some(pattern => pattern.test(prBody));
|
||||
|
||||
|
||||
@@ -106,8 +106,8 @@ module.exports = async ({ github, context }) => {
|
||||
const [
|
||||
branchLabels,
|
||||
componentLabels,
|
||||
newComponentLabels,
|
||||
newPlatformLabels,
|
||||
newComponentResult,
|
||||
newPlatformResult,
|
||||
coreLabels,
|
||||
sizeLabels,
|
||||
dashboardLabels,
|
||||
@@ -120,8 +120,8 @@ module.exports = async ({ github, context }) => {
|
||||
] = await Promise.all([
|
||||
detectMergeBranch(context),
|
||||
detectComponentPlatforms(changedFiles, apiData),
|
||||
detectNewComponents(prFiles),
|
||||
detectNewPlatforms(prFiles, apiData),
|
||||
detectNewComponents(github, context, prFiles),
|
||||
detectNewPlatforms(github, context, prFiles, apiData),
|
||||
detectCoreChanges(changedFiles),
|
||||
detectPRSize(prFiles, totalAdditions, totalDeletions, totalChanges, isMegaPR, SMALL_PR_THRESHOLD, MEDIUM_PR_THRESHOLD, TOO_BIG_THRESHOLD),
|
||||
detectDashboardChanges(changedFiles),
|
||||
@@ -133,6 +133,13 @@ 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;
|
||||
@@ -154,7 +161,7 @@ module.exports = async ({ github, context }) => {
|
||||
]);
|
||||
|
||||
// Detect requirements based on all other labels
|
||||
const requirementLabels = await detectRequirements(allLabels, prFiles, context);
|
||||
const requirementLabels = await detectRequirements(allLabels, prFiles, context, hasYamlLoadable);
|
||||
for (const label of requirementLabels) {
|
||||
allLabels.add(label);
|
||||
}
|
||||
|
||||
@@ -6,9 +6,10 @@ 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:
|
||||
pull-requests: write
|
||||
contents: read
|
||||
contents: read # actions/checkout reads the workflow source
|
||||
|
||||
env:
|
||||
SMALL_PR_THRESHOLD: 30
|
||||
@@ -31,6 +32,10 @@ jobs:
|
||||
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 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
|
||||
|
||||
@@ -12,8 +12,8 @@ on:
|
||||
- ".github/workflows/ci-api-proto.yml"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
contents: read # actions/checkout for the PR head
|
||||
pull-requests: write # pulls.createReview / listReviews / dismissReview when generated proto files are stale
|
||||
|
||||
jobs:
|
||||
check:
|
||||
|
||||
@@ -12,8 +12,8 @@ on:
|
||||
- ".github/workflows/ci-clang-tidy-hash.yml"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
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:
|
||||
|
||||
@@ -22,8 +22,7 @@ on:
|
||||
- "script/platformio_install_deps.py"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: read
|
||||
contents: read # actions/checkout only; the build does not push images
|
||||
|
||||
concurrency:
|
||||
# yamllint disable-line rule:line-length
|
||||
|
||||
@@ -7,9 +7,9 @@ on:
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
actions: read
|
||||
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
|
||||
|
||||
jobs:
|
||||
memory-impact-comment:
|
||||
|
||||
@@ -17,7 +17,7 @@ on:
|
||||
merge_group:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
contents: read # actions/checkout for all jobs; individual jobs add their own scopes when they need to write
|
||||
|
||||
env:
|
||||
DEFAULT_PYTHON: "3.11"
|
||||
@@ -783,6 +783,91 @@ 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@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
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@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
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
|
||||
@@ -1062,8 +1147,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
|
||||
pull-requests: write
|
||||
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
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
steps:
|
||||
@@ -1114,6 +1199,7 @@ jobs:
|
||||
- determine-jobs
|
||||
- device-builder
|
||||
- test-build-components-split
|
||||
- test-native-idf
|
||||
- pre-commit-ci-lite
|
||||
- memory-impact-target-branch
|
||||
- memory-impact-pr-branch
|
||||
|
||||
@@ -6,8 +6,8 @@ on:
|
||||
types: [opened, reopened]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
issues: write
|
||||
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
|
||||
|
||||
jobs:
|
||||
close:
|
||||
|
||||
@@ -15,9 +15,9 @@ on:
|
||||
- beta
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: read
|
||||
contents: read
|
||||
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
|
||||
|
||||
jobs:
|
||||
codeowner-approved:
|
||||
|
||||
@@ -17,9 +17,10 @@ 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:
|
||||
pull-requests: write
|
||||
contents: read
|
||||
contents: read # actions/checkout to read CODEOWNERS and the shared codeowners.js helper
|
||||
|
||||
jobs:
|
||||
request-codeowner-reviews:
|
||||
@@ -32,9 +33,20 @@ 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');
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ 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 }})
|
||||
@@ -26,15 +29,10 @@ 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:
|
||||
# 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
|
||||
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
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -58,7 +56,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
|
||||
uses: github/codeql-action/init@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
@@ -86,6 +84,6 @@ jobs:
|
||||
exit 1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
|
||||
uses: github/codeql-action/analyze@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
@@ -4,20 +4,29 @@ on:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize]
|
||||
|
||||
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?
|
||||
# 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: {}
|
||||
|
||||
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: ${{ secrets.GITHUB_TOKEN }}
|
||||
github-token: ${{ steps.generate-token.outputs.token }}
|
||||
script: |
|
||||
// Generate external component usage instructions
|
||||
function generateExternalComponentInstructions(prNumber, componentNames, owner, repo) {
|
||||
|
||||
@@ -9,8 +9,8 @@ on:
|
||||
types: [labeled]
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
contents: read
|
||||
issues: write # issues.createComment to mention component codeowners on the newly labelled issue
|
||||
contents: read # repos.getContent to fetch CODEOWNERS from the default branch
|
||||
|
||||
jobs:
|
||||
notify-codeowners:
|
||||
|
||||
@@ -6,6 +6,12 @@ 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
|
||||
|
||||
@@ -8,8 +8,8 @@ on:
|
||||
- beta
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
contents: read # actions/checkout to load detect-tags.js
|
||||
pull-requests: read # pulls.listFiles to map changed files to component/core/dashboard/ci tags
|
||||
|
||||
jobs:
|
||||
check:
|
||||
|
||||
@@ -9,7 +9,7 @@ on:
|
||||
- cron: "0 2 * * *"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
contents: read # actions/checkout for all jobs; deploy jobs add their own scopes when they need to write
|
||||
|
||||
jobs:
|
||||
init:
|
||||
@@ -57,8 +57,8 @@ jobs:
|
||||
if: github.repository == 'esphome/esphome' && github.event_name == 'release'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
contents: read # actions/checkout to build the sdist/wheel
|
||||
id-token: write # OIDC token for PyPI Trusted Publishing (pypa/gh-action-pypi-publish)
|
||||
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
|
||||
packages: write
|
||||
contents: read # actions/checkout to load Dockerfile and build context
|
||||
packages: write # docker/login-action + build-push-action push image digests to ghcr.io
|
||||
runs-on: ${{ matrix.platform.os }}
|
||||
needs: [init]
|
||||
strategy:
|
||||
@@ -152,8 +152,8 @@ jobs:
|
||||
- deploy-docker
|
||||
if: github.repository == 'esphome/esphome'
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
contents: read # actions/checkout to load Dockerfile and build context
|
||||
packages: write # docker/login-action + build-push-action push image digests to ghcr.io
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -227,6 +227,7 @@ jobs:
|
||||
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
|
||||
@@ -262,6 +263,7 @@ jobs:
|
||||
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
|
||||
@@ -293,6 +295,7 @@ jobs:
|
||||
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
|
||||
|
||||
@@ -7,8 +7,8 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
issues: write # actions/stale labels, comments on, and closes stale issues
|
||||
pull-requests: write # actions/stale labels, comments on, and closes stale pull requests
|
||||
|
||||
concurrency:
|
||||
group: lock
|
||||
|
||||
@@ -4,6 +4,9 @@ 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
|
||||
|
||||
@@ -6,12 +6,27 @@ 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
|
||||
|
||||
@@ -50,4 +65,4 @@ jobs:
|
||||
delete-branch: true
|
||||
title: "Synchronise Device Classes from Home Assistant"
|
||||
body-path: .github/PULL_REQUEST_TEMPLATE.md
|
||||
token: ${{ secrets.DEVICE_CLASS_SYNC_TOKEN }}
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
|
||||
@@ -416,6 +416,7 @@ 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
|
||||
|
||||
+218
-103
@@ -52,18 +52,19 @@ from esphome.const import (
|
||||
CONF_WEB_SERVER,
|
||||
ENV_NOGITIGNORE,
|
||||
KEY_CORE,
|
||||
KEY_NATIVE_IDF,
|
||||
KEY_TARGET_PLATFORM,
|
||||
PLATFORM_ESP32,
|
||||
PLATFORM_ESP8266,
|
||||
PLATFORM_RP2040,
|
||||
SECRETS_FILES,
|
||||
Toolchain,
|
||||
)
|
||||
from esphome.core import CORE, EsphomeError, coroutine
|
||||
from esphome.enum import StrEnum
|
||||
from esphome.helpers import get_bool_env, indent, is_ip_address
|
||||
from esphome.log import AnsiFore, color, setup_log
|
||||
from esphome.types import ConfigType
|
||||
from esphome.upload_targets import PortType, get_port_type
|
||||
from esphome.util import (
|
||||
PICOTOOL_PACKAGE,
|
||||
FlashImage,
|
||||
@@ -155,7 +156,6 @@ class ArgsProtocol(Protocol):
|
||||
configuration: str
|
||||
name: str
|
||||
upload_speed: str | None
|
||||
native_idf: bool
|
||||
|
||||
|
||||
def choose_prompt(options, purpose: str = None):
|
||||
@@ -195,14 +195,6 @@ class Purpose(StrEnum):
|
||||
LOGGING = "logging"
|
||||
|
||||
|
||||
class PortType(StrEnum):
|
||||
SERIAL = "SERIAL"
|
||||
NETWORK = "NETWORK"
|
||||
MQTT = "MQTT"
|
||||
MQTTIP = "MQTTIP"
|
||||
BOOTSEL = "BOOTSEL"
|
||||
|
||||
|
||||
# Magic MQTT port types that require special handling
|
||||
_MQTT_PORT_TYPES = frozenset({PortType.MQTT, PortType.MQTTIP})
|
||||
|
||||
@@ -598,27 +590,6 @@ def _resolve_network_devices(
|
||||
return network_devices
|
||||
|
||||
|
||||
def get_port_type(port: str) -> PortType:
|
||||
"""Determine the type of port/device identifier.
|
||||
|
||||
Returns:
|
||||
PortType.SERIAL for serial ports (/dev/ttyUSB0, COM1, etc.)
|
||||
PortType.BOOTSEL for RP2040 BOOTSEL upload via picotool
|
||||
PortType.MQTT for MQTT logging
|
||||
PortType.MQTTIP for MQTT IP lookup
|
||||
PortType.NETWORK for IP addresses, hostnames, or mDNS names
|
||||
"""
|
||||
if port == "BOOTSEL":
|
||||
return PortType.BOOTSEL
|
||||
if port.startswith("/") or port.startswith("COM"):
|
||||
return PortType.SERIAL
|
||||
if port == "MQTT":
|
||||
return PortType.MQTT
|
||||
if port == "MQTTIP":
|
||||
return PortType.MQTTIP
|
||||
return PortType.NETWORK
|
||||
|
||||
|
||||
def run_miniterm(config: ConfigType, port: str, args) -> int:
|
||||
from aioesphomeapi import LogParser
|
||||
import serial
|
||||
@@ -721,17 +692,14 @@ def _wrap_to_code(name, comp, yaml_util):
|
||||
return wrapped
|
||||
|
||||
|
||||
def write_cpp(config: ConfigType, native_idf: bool = False) -> int:
|
||||
def write_cpp(config: ConfigType) -> int:
|
||||
from esphome import writer
|
||||
|
||||
if not get_bool_env(ENV_NOGITIGNORE):
|
||||
writer.write_gitignore()
|
||||
|
||||
# Store native_idf flag so esp32 component can check it
|
||||
CORE.data[KEY_NATIVE_IDF] = native_idf
|
||||
|
||||
generate_cpp_contents(config)
|
||||
return write_cpp_file(native_idf=native_idf)
|
||||
return write_cpp_file()
|
||||
|
||||
|
||||
def generate_cpp_contents(config: ConfigType) -> None:
|
||||
@@ -747,13 +715,13 @@ def generate_cpp_contents(config: ConfigType) -> None:
|
||||
CORE.flush_tasks()
|
||||
|
||||
|
||||
def write_cpp_file(native_idf: bool = False) -> int:
|
||||
def write_cpp_file() -> int:
|
||||
from esphome import writer
|
||||
|
||||
code_s = indent(CORE.cpp_main_section)
|
||||
writer.write_cpp(code_s)
|
||||
|
||||
if native_idf and CORE.is_esp32 and CORE.target_framework == "esp-idf":
|
||||
if CORE.using_toolchain_esp_idf:
|
||||
from esphome.build_gen import espidf
|
||||
|
||||
espidf.write_project()
|
||||
@@ -766,30 +734,29 @@ def write_cpp_file(native_idf: bool = False) -> int:
|
||||
|
||||
|
||||
def compile_program(args: ArgsProtocol, config: ConfigType) -> int:
|
||||
native_idf = getattr(args, "native_idf", False)
|
||||
|
||||
# NOTE: "Build path:" format is parsed by script/ci_memory_impact_extract.py
|
||||
# If you change this format, update the regex in that script as well
|
||||
_LOGGER.info("Compiling app... Build path: %s", CORE.build_path)
|
||||
|
||||
if native_idf and CORE.is_esp32 and CORE.target_framework == "esp-idf":
|
||||
from esphome import espidf_api
|
||||
if CORE.using_toolchain_esp_idf:
|
||||
from esphome.espidf import toolchain
|
||||
|
||||
rc = espidf_api.run_compile(config, CORE.verbose)
|
||||
rc = toolchain.run_compile(config, CORE.verbose)
|
||||
if rc != 0:
|
||||
return rc
|
||||
|
||||
# Create factory.bin and ota.bin
|
||||
espidf_api.create_factory_bin()
|
||||
espidf_api.create_ota_bin()
|
||||
# Create factory.bin, ota.bin, and firmware.elf copy
|
||||
toolchain.create_factory_bin()
|
||||
toolchain.create_ota_bin()
|
||||
toolchain.create_elf_copy()
|
||||
else:
|
||||
from esphome import platformio_api
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
rc = platformio_api.run_compile(config, CORE.verbose)
|
||||
rc = toolchain.run_compile(config, CORE.verbose)
|
||||
if rc != 0:
|
||||
return rc
|
||||
|
||||
idedata = platformio_api.get_idedata(config)
|
||||
idedata = toolchain.get_idedata(config)
|
||||
if idedata is None:
|
||||
return 1
|
||||
|
||||
@@ -884,10 +851,16 @@ def upload_using_esptool(
|
||||
|
||||
if file is not None:
|
||||
flash_images = [FlashImage(path=file, offset="0x0")]
|
||||
else:
|
||||
from esphome import platformio_api
|
||||
elif CORE.using_toolchain_esp_idf:
|
||||
from esphome.espidf import toolchain
|
||||
|
||||
idedata = platformio_api.get_idedata(config)
|
||||
flash_images = [
|
||||
FlashImage(path=toolchain.get_factory_firmware_path(), offset="0x0")
|
||||
]
|
||||
else:
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
idedata = toolchain.get_idedata(config)
|
||||
|
||||
firmware_offset = "0x10000" if CORE.is_esp32 else "0x0"
|
||||
flash_images = [
|
||||
@@ -960,13 +933,13 @@ def upload_using_esptool(
|
||||
|
||||
|
||||
def upload_using_platformio(config: ConfigType, port: str) -> int:
|
||||
from esphome import platformio_api
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
# RP2040 platform-raspberrypi build recipe expects firmware.bin.signed for
|
||||
# the upload target, but 'nobuild' skips the build phase that creates it.
|
||||
# Create it here so the upload doesn't fail.
|
||||
if CORE.data.get(KEY_CORE, {}).get(KEY_TARGET_PLATFORM) == PLATFORM_RP2040:
|
||||
idedata = platformio_api.get_idedata(config)
|
||||
idedata = toolchain.get_idedata(config)
|
||||
build_dir = Path(idedata.firmware_elf_path).parent
|
||||
firmware_bin = build_dir / "firmware.bin"
|
||||
signed_bin = build_dir / "firmware.bin.signed"
|
||||
@@ -976,15 +949,15 @@ def upload_using_platformio(config: ConfigType, port: str) -> int:
|
||||
upload_args = ["-t", "upload", "-t", "nobuild"]
|
||||
if port is not None:
|
||||
upload_args += ["--upload-port", port]
|
||||
return platformio_api.run_platformio_cli_run(config, CORE.verbose, *upload_args)
|
||||
return toolchain.run_platformio_cli_run(config, CORE.verbose, *upload_args)
|
||||
|
||||
|
||||
def _find_picotool() -> Path | None:
|
||||
"""Find the picotool binary from PlatformIO packages."""
|
||||
from esphome import platformio_api
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
try:
|
||||
idedata = platformio_api.get_idedata(CORE.config)
|
||||
idedata = toolchain.get_idedata(CORE.config)
|
||||
except Exception: # noqa: BLE001 # pylint: disable=broad-except
|
||||
return None
|
||||
return get_picotool_path(idedata.cc_path)
|
||||
@@ -997,9 +970,9 @@ def upload_using_picotool(config: ConfigType) -> int:
|
||||
the mass storage copy approach that causes "disk not ejected properly"
|
||||
warnings on macOS.
|
||||
"""
|
||||
from esphome import platformio_api
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
idedata = platformio_api.get_idedata(config)
|
||||
idedata = toolchain.get_idedata(config)
|
||||
firmware_elf = Path(idedata.firmware_elf_path)
|
||||
|
||||
if not firmware_elf.is_file():
|
||||
@@ -1126,11 +1099,18 @@ def upload_program(
|
||||
|
||||
# MQTT and MQTTIP are also OTA paths; MQTTIP gets resolved to a real IP later by
|
||||
# _resolve_network_devices(). Only SERIAL and BOOTSEL are non-OTA upload paths.
|
||||
if port_type in (PortType.SERIAL, PortType.BOOTSEL) and getattr(
|
||||
args, "partition_table", False
|
||||
is_partition_table = getattr(args, "partition_table", False)
|
||||
is_bootloader = getattr(args, "bootloader", False)
|
||||
if is_partition_table and is_bootloader:
|
||||
raise EsphomeError(
|
||||
"The options --partition-table and --bootloader can't be used together."
|
||||
)
|
||||
option_string = "--partition-table" if is_partition_table else "--bootloader"
|
||||
if port_type in (PortType.SERIAL, PortType.BOOTSEL) and (
|
||||
is_partition_table or is_bootloader
|
||||
):
|
||||
raise EsphomeError(
|
||||
"The option --partition-table can only be used for Over The Air updates."
|
||||
f"The option {option_string} can only be used for Over The Air updates."
|
||||
)
|
||||
|
||||
if port_type == PortType.BOOTSEL:
|
||||
@@ -1159,9 +1139,9 @@ def upload_program(
|
||||
network_devices = _resolve_network_devices(devices, config, args)
|
||||
|
||||
if chosen_platform == CONF_WEB_SERVER:
|
||||
if getattr(args, "partition_table", False):
|
||||
if is_partition_table or is_bootloader:
|
||||
raise EsphomeError(
|
||||
"--partition-table is only supported with the esphome OTA platform; "
|
||||
f"{option_string} is only supported with the esphome OTA platform; "
|
||||
"the web_server OTA path can only update the firmware image."
|
||||
)
|
||||
binary = CORE.firmware_bin
|
||||
@@ -1229,25 +1209,34 @@ def _upload_via_native_api(
|
||||
remote_port = int(ota_conf[CONF_PORT])
|
||||
password = ota_conf.get(CONF_PASSWORD)
|
||||
|
||||
def check_partition_access(option_string: str) -> None:
|
||||
if not ota_conf.get("allow_partition_access"):
|
||||
raise EsphomeError(
|
||||
f"The option {option_string} requires 'allow_partition_access: true' on the "
|
||||
"esphome OTA platform in the device's YAML configuration. Add it, recompile, "
|
||||
f"flash a build with the option enabled, and then retry {option_string}."
|
||||
)
|
||||
|
||||
binary = CORE.firmware_bin
|
||||
ota_type = espota2.OTA_TYPE_UPDATE_APP
|
||||
if getattr(args, "partition_table", False):
|
||||
# Fail fast if the resolved ESPHome OTA config does not enable allow_partition_access.
|
||||
# The device-side handshake also rejects this with "Device only supports app updates",
|
||||
# but checking here surfaces the misconfiguration before opening a network connection.
|
||||
if not ota_conf.get("allow_partition_access"):
|
||||
raise EsphomeError(
|
||||
"The option --partition-table requires 'allow_partition_access: true' on the "
|
||||
"esphome OTA platform in the device's YAML configuration. Add it, recompile, "
|
||||
"flash a build with the option enabled, and then retry --partition-table."
|
||||
)
|
||||
check_partition_access("--partition-table")
|
||||
binary = CORE.partition_table_bin
|
||||
ota_type = espota2.OTA_TYPE_UPDATE_PARTITION_TABLE
|
||||
elif getattr(args, "bootloader", False):
|
||||
check_partition_access("--bootloader")
|
||||
binary = CORE.bootloader_bin
|
||||
ota_type = espota2.OTA_TYPE_UPDATE_BOOTLOADER
|
||||
if getattr(args, "file", None) is not None:
|
||||
binary = Path(args.file)
|
||||
|
||||
if ota_type == espota2.OTA_TYPE_UPDATE_PARTITION_TABLE:
|
||||
_validate_partition_table_binary(binary)
|
||||
if ota_type == espota2.OTA_TYPE_UPDATE_BOOTLOADER:
|
||||
_validate_bootloader_binary(binary)
|
||||
|
||||
return espota2.run_ota(network_devices, remote_port, password, binary, ota_type)
|
||||
|
||||
@@ -1282,6 +1271,7 @@ def _upload_via_web_server(
|
||||
_PARTITION_TABLE_MAX_LEN = 0xC00
|
||||
_ESP_PARTITION_MAGIC = 0x50AA
|
||||
_ESP_PARTITION_MAGIC_MD5 = 0xEBEB
|
||||
_ESP_IMAGE_HEADER_MAGIC = 0xE9
|
||||
|
||||
|
||||
def _validate_partition_table_binary(binary: Path) -> None:
|
||||
@@ -1327,6 +1317,28 @@ def _validate_partition_table_binary(binary: Path) -> None:
|
||||
)
|
||||
|
||||
|
||||
def _validate_bootloader_binary(binary: Path) -> None:
|
||||
"""Validate that ``binary`` looks like an ESP32 bootloader image."""
|
||||
try:
|
||||
data = binary.read_bytes()
|
||||
except OSError as err:
|
||||
raise EsphomeError(f"Cannot read bootloader file '{binary}': {err}") from err
|
||||
|
||||
if not data:
|
||||
raise EsphomeError(
|
||||
f"Bootloader file '{binary}' is empty. "
|
||||
"This file does not look like an ESP32 bootloader."
|
||||
)
|
||||
|
||||
first_magic = data[0]
|
||||
if first_magic != _ESP_IMAGE_HEADER_MAGIC:
|
||||
raise EsphomeError(
|
||||
f"Bootloader file '{binary}' does not start with the expected "
|
||||
f"image header magic 0x{_ESP_IMAGE_HEADER_MAGIC:02X} (got 0x{first_magic:02X}). "
|
||||
"This file does not look like an ESP32 bootloader."
|
||||
)
|
||||
|
||||
|
||||
def show_logs(config: ConfigType, args: ArgsProtocol, devices: list[str]) -> int | None:
|
||||
try:
|
||||
module = importlib.import_module("esphome.components." + CORE.target_platform)
|
||||
@@ -1409,8 +1421,7 @@ def command_vscode(args: ArgsProtocol) -> int | None:
|
||||
|
||||
|
||||
def command_compile(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
native_idf = getattr(args, "native_idf", False)
|
||||
exit_code = write_cpp(config, native_idf=native_idf)
|
||||
exit_code = write_cpp(config)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
if args.only_generate:
|
||||
@@ -1420,9 +1431,14 @@ def command_compile(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
if CORE.is_host:
|
||||
from esphome.platformio_api import get_idedata
|
||||
if CORE.using_toolchain_esp_idf:
|
||||
from esphome.espidf import toolchain
|
||||
|
||||
program_path = str(get_idedata(config).firmware_elf_path)
|
||||
program_path = str(toolchain.get_elf_path())
|
||||
else:
|
||||
from esphome.platformio.toolchain import get_idedata
|
||||
|
||||
program_path = str(get_idedata(config).firmware_elf_path)
|
||||
_LOGGER.info("Successfully compiled program to path '%s'", program_path)
|
||||
else:
|
||||
_LOGGER.info("Successfully compiled program.")
|
||||
@@ -1465,8 +1481,7 @@ def command_logs(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
|
||||
|
||||
def command_run(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
native_idf = getattr(args, "native_idf", False)
|
||||
exit_code = write_cpp(config, native_idf=native_idf)
|
||||
exit_code = write_cpp(config)
|
||||
if exit_code != 0:
|
||||
return exit_code
|
||||
exit_code = compile_program(args, config)
|
||||
@@ -1474,9 +1489,14 @@ def command_run(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
return exit_code
|
||||
_LOGGER.info("Successfully compiled program.")
|
||||
if CORE.is_host:
|
||||
from esphome.platformio_api import get_idedata
|
||||
if CORE.using_toolchain_esp_idf:
|
||||
from esphome.espidf import toolchain
|
||||
|
||||
program_path = str(get_idedata(config).firmware_elf_path)
|
||||
program_path = str(toolchain.get_elf_path())
|
||||
else:
|
||||
from esphome.platformio.toolchain import get_idedata
|
||||
|
||||
program_path = str(get_idedata(config).firmware_elf_path)
|
||||
_LOGGER.info("Running program from path '%s'", program_path)
|
||||
return run_external_process(program_path)
|
||||
|
||||
@@ -1667,12 +1687,19 @@ def command_update_all(args: ArgsProtocol) -> int | None:
|
||||
def command_idedata(args: ArgsProtocol, config: ConfigType) -> int:
|
||||
import json
|
||||
|
||||
from esphome import platformio_api
|
||||
if not CORE.using_toolchain_platformio:
|
||||
_LOGGER.error(
|
||||
"The idedata command is not compatible with %s toolchain",
|
||||
CORE.toolchain.value,
|
||||
)
|
||||
return 1
|
||||
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
logging.disable(logging.INFO)
|
||||
logging.disable(logging.WARNING)
|
||||
|
||||
idedata = platformio_api.get_idedata(config)
|
||||
idedata = toolchain.get_idedata(config)
|
||||
if idedata is None:
|
||||
return 1
|
||||
|
||||
@@ -1686,7 +1713,6 @@ def command_analyze_memory(args: ArgsProtocol, config: ConfigType) -> int:
|
||||
This command compiles the configuration and performs memory analysis.
|
||||
Compilation is fast if sources haven't changed (just relinking).
|
||||
"""
|
||||
from esphome import platformio_api
|
||||
from esphome.analyze_memory.cli import MemoryAnalyzerCLI
|
||||
from esphome.analyze_memory.ram_strings import RamStringsAnalyzer
|
||||
|
||||
@@ -1700,12 +1726,25 @@ def command_analyze_memory(args: ArgsProtocol, config: ConfigType) -> int:
|
||||
_LOGGER.info("Successfully compiled program.")
|
||||
|
||||
# Get idedata for analysis
|
||||
idedata = platformio_api.get_idedata(config)
|
||||
if idedata is None:
|
||||
_LOGGER.error("Failed to get IDE data for memory analysis")
|
||||
return 1
|
||||
idedata = None
|
||||
if CORE.using_toolchain_esp_idf:
|
||||
from esphome.espidf import toolchain
|
||||
|
||||
firmware_elf = Path(idedata.firmware_elf_path)
|
||||
objdump_path = str(toolchain.get_objdump_path())
|
||||
readelf_path = str(toolchain.get_readelf_path())
|
||||
|
||||
firmware_elf = toolchain.get_elf_path()
|
||||
else:
|
||||
from esphome.platformio import toolchain
|
||||
|
||||
idedata = toolchain.get_idedata(config)
|
||||
if idedata is None:
|
||||
_LOGGER.error("Failed to get IDE data for memory analysis")
|
||||
return 1
|
||||
objdump_path = idedata.objdump_path
|
||||
readelf_path = idedata.readelf_path
|
||||
|
||||
firmware_elf = Path(idedata.firmware_elf_path)
|
||||
|
||||
# Extract external components from config
|
||||
external_components = detect_external_components(config)
|
||||
@@ -1715,8 +1754,8 @@ def command_analyze_memory(args: ArgsProtocol, config: ConfigType) -> int:
|
||||
_LOGGER.info("Analyzing memory usage...")
|
||||
analyzer = MemoryAnalyzerCLI(
|
||||
str(firmware_elf),
|
||||
idedata.objdump_path,
|
||||
idedata.readelf_path,
|
||||
objdump_path,
|
||||
readelf_path,
|
||||
external_components,
|
||||
idedata=idedata,
|
||||
)
|
||||
@@ -1732,7 +1771,7 @@ def command_analyze_memory(args: ArgsProtocol, config: ConfigType) -> int:
|
||||
try:
|
||||
ram_analyzer = RamStringsAnalyzer(
|
||||
str(firmware_elf),
|
||||
objdump_path=idedata.objdump_path,
|
||||
objdump_path=objdump_path,
|
||||
platform=CORE.target_platform,
|
||||
)
|
||||
ram_analyzer.analyze()
|
||||
@@ -1775,11 +1814,32 @@ def command_rename(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
old_name = yaml[CONF_ESPHOME][CONF_NAME]
|
||||
match = re.match(r"^\$\{?([a-zA-Z0-9_]+)\}?$", old_name)
|
||||
if match is None:
|
||||
new_raw = re.sub(
|
||||
rf"name:\s+[\"']?{old_name}[\"']?",
|
||||
f'name: "{new_name}"',
|
||||
raw_contents,
|
||||
# Only swap the ``name:`` line that sits directly under the
|
||||
# top-level ``esphome:`` block. A naked ``re.sub`` would
|
||||
# also clobber any other ``name:`` line whose value happens
|
||||
# to match (e.g. a sensor / output / wifi entry sharing the
|
||||
# device's hostname), silently rewriting unrelated user
|
||||
# configuration. The pattern anchors:
|
||||
# - at the start of the line so ``friendly_name:``,
|
||||
# ``device_name:`` etc. don't match the trailing ``name:``
|
||||
# substring; and
|
||||
# - at the end of the value (lookahead for whitespace +
|
||||
# comment + EOL) so ``old_name`` doesn't match as a
|
||||
# prefix of a longer value (``kitchen`` vs ``kitchen2``).
|
||||
name_pattern = re.compile(
|
||||
rf"^(\s*)name:\s+[\"']?{re.escape(old_name)}[\"']?(?=\s*(?:#|$))"
|
||||
)
|
||||
out_lines: list[str] = []
|
||||
in_esphome_block = False
|
||||
for line in raw_contents.splitlines(keepends=True):
|
||||
if line and not line[0].isspace() and line.strip():
|
||||
in_esphome_block = line.lstrip().startswith("esphome:")
|
||||
out_lines.append(line)
|
||||
continue
|
||||
if in_esphome_block:
|
||||
line = name_pattern.sub(rf'\1name: "{new_name}"', line, count=1)
|
||||
out_lines.append(line)
|
||||
new_raw = "".join(out_lines)
|
||||
else:
|
||||
old_name = yaml[CONF_SUBSTITUTIONS][match.group(1)]
|
||||
if (
|
||||
@@ -1802,7 +1862,40 @@ def command_rename(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
flags=re.MULTILINE,
|
||||
)
|
||||
|
||||
# ``new_name == old_name`` (after substitution resolution) is
|
||||
# a no-op rewrite that would still queue a pointless re-flash.
|
||||
# Catch it before the path-equality check below — covers the
|
||||
# case where the config filename doesn't match the device name
|
||||
# (e.g. ``weird-file.yaml`` whose ``esphome.name`` is
|
||||
# ``kitchen``; running ``esphome rename weird-file.yaml kitchen``
|
||||
# would otherwise just re-flash the same hostname).
|
||||
if new_name == old_name:
|
||||
print(
|
||||
color(
|
||||
AnsiFore.BOLD_RED,
|
||||
f"'{new_name}' is already the device's name.",
|
||||
)
|
||||
)
|
||||
return 1
|
||||
|
||||
new_path: Path = CORE.config_dir / (new_name + ".yaml")
|
||||
if new_path.resolve() == CORE.config_path.resolve():
|
||||
print(
|
||||
color(
|
||||
AnsiFore.BOLD_RED,
|
||||
f"'{new_name}' is already the device's name.",
|
||||
)
|
||||
)
|
||||
return 1
|
||||
if new_path.exists():
|
||||
print(
|
||||
color(
|
||||
AnsiFore.BOLD_RED,
|
||||
f"Cannot rename: {new_path} already exists. "
|
||||
"Refusing to overwrite an existing configuration.",
|
||||
)
|
||||
)
|
||||
return 1
|
||||
print(
|
||||
f"Updating {color(AnsiFore.CYAN, str(CORE.config_path))} to {color(AnsiFore.CYAN, str(new_path))}"
|
||||
)
|
||||
@@ -1923,6 +2016,17 @@ def parse_args(argv):
|
||||
action="store_true",
|
||||
default=False,
|
||||
)
|
||||
options_parser.add_argument(
|
||||
"--toolchain",
|
||||
type=Toolchain,
|
||||
default=None,
|
||||
choices=list(Toolchain),
|
||||
metavar="{" + ",".join(t.value for t in Toolchain) + "}",
|
||||
help=(
|
||||
"Select toolchain for compiling. Overrides '<platform>.toolchain' in YAML. "
|
||||
f"Default: {Toolchain.PLATFORMIO.value}."
|
||||
),
|
||||
)
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=f"ESPHome {const.__version__}", parents=[options_parser]
|
||||
@@ -1967,11 +2071,6 @@ def parse_args(argv):
|
||||
help="Only generate source code, do not compile.",
|
||||
action="store_true",
|
||||
)
|
||||
parser_compile.add_argument(
|
||||
"--native-idf",
|
||||
help="Build with native ESP-IDF instead of PlatformIO (ESP32 esp-idf framework only).",
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
parser_upload = subparsers.add_parser(
|
||||
"upload",
|
||||
@@ -2010,6 +2109,11 @@ def parse_args(argv):
|
||||
help="Upload as partition table (OTA).",
|
||||
action="store_true",
|
||||
)
|
||||
parser_upload.add_argument(
|
||||
"--bootloader",
|
||||
help="Upload as bootloader (OTA).",
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
parser_logs = subparsers.add_parser(
|
||||
"logs",
|
||||
@@ -2067,6 +2171,13 @@ def parse_args(argv):
|
||||
parser_run.add_argument(
|
||||
"--no-logs", help="Disable starting logs.", action="store_true"
|
||||
)
|
||||
|
||||
parser_run.add_argument(
|
||||
"--no-states",
|
||||
action="store_true",
|
||||
help="Do not show entity state changes in log output.",
|
||||
)
|
||||
|
||||
parser_run.add_argument(
|
||||
"--reset",
|
||||
"-r",
|
||||
@@ -2074,11 +2185,6 @@ def parse_args(argv):
|
||||
help="Reset the device before starting serial logs.",
|
||||
default=os.getenv("ESPHOME_SERIAL_LOGGING_RESET"),
|
||||
)
|
||||
parser_run.add_argument(
|
||||
"--native-idf",
|
||||
help="Build with native ESP-IDF instead of PlatformIO (ESP32 esp-idf framework only).",
|
||||
action="store_true",
|
||||
)
|
||||
parser_run.add_argument(
|
||||
"--ota-platform",
|
||||
choices=[CONF_ESPHOME, CONF_WEB_SERVER],
|
||||
@@ -2301,6 +2407,9 @@ def run_esphome(argv):
|
||||
|
||||
CORE.config_path = conf_path
|
||||
CORE.dashboard = args.dashboard
|
||||
if args.toolchain is not None:
|
||||
# CLI toolchain wins over esp32.toolchain in YAML.
|
||||
CORE.toolchain = args.toolchain
|
||||
|
||||
# Commands that don't need fresh external components: logs just connects
|
||||
# to the device, and clean is about to delete the build directory.
|
||||
@@ -2313,6 +2422,12 @@ def run_esphome(argv):
|
||||
return 2
|
||||
CORE.config = config
|
||||
|
||||
# Fallback for platforms whose validators didn't set the toolchain
|
||||
# (only the esp32 component reads esp32.framework.toolchain). All
|
||||
# other platforms only support PlatformIO today.
|
||||
if CORE.toolchain is None:
|
||||
CORE.toolchain = Toolchain.PLATFORMIO
|
||||
|
||||
if args.command not in POST_CONFIG_ACTIONS:
|
||||
safe_print(f"Unknown command {args.command}")
|
||||
return 1
|
||||
|
||||
@@ -24,7 +24,7 @@ from .helpers import (
|
||||
from .toolchain import find_tool, resolve_tool_path, run_tool
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from esphome.platformio_api import IDEData
|
||||
from esphome.platformio.toolchain import IDEData
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -739,7 +739,7 @@ def main():
|
||||
# Load build directory
|
||||
from pathlib import Path
|
||||
|
||||
from esphome.platformio_api import IDEData
|
||||
from esphome.platformio.toolchain import IDEData
|
||||
|
||||
build_path = Path(build_dir)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ 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:
|
||||
@@ -54,7 +55,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 CORE.build_flags if flag.startswith("-D")]
|
||||
compile_defs = [flag for flag in sorted(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
|
||||
@@ -64,6 +65,22 @@ 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)
|
||||
|
||||
@@ -124,6 +141,11 @@ 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())
|
||||
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace a01nyub {
|
||||
namespace esphome::a01nyub {
|
||||
|
||||
static const char *const TAG = "a01nyub.sensor";
|
||||
|
||||
@@ -42,5 +41,4 @@ void A01nyubComponent::check_buffer_() {
|
||||
|
||||
void A01nyubComponent::dump_config() { LOG_SENSOR("", "A01nyub Sensor", this); }
|
||||
|
||||
} // namespace a01nyub
|
||||
} // namespace esphome
|
||||
} // namespace esphome::a01nyub
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace a01nyub {
|
||||
namespace esphome::a01nyub {
|
||||
|
||||
class A01nyubComponent : public sensor::Sensor, public Component, public uart::UARTDevice {
|
||||
public:
|
||||
@@ -23,5 +22,4 @@ class A01nyubComponent : public sensor::Sensor, public Component, public uart::U
|
||||
std::vector<uint8_t> buffer_;
|
||||
};
|
||||
|
||||
} // namespace a01nyub
|
||||
} // namespace esphome
|
||||
} // namespace esphome::a01nyub
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace a02yyuw {
|
||||
namespace esphome::a02yyuw {
|
||||
|
||||
static const char *const TAG = "a02yyuw.sensor";
|
||||
|
||||
@@ -41,5 +40,4 @@ void A02yyuwComponent::check_buffer_() {
|
||||
|
||||
void A02yyuwComponent::dump_config() { LOG_SENSOR("", "A02yyuw Sensor", this); }
|
||||
|
||||
} // namespace a02yyuw
|
||||
} // namespace esphome
|
||||
} // namespace esphome::a02yyuw
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace a02yyuw {
|
||||
namespace esphome::a02yyuw {
|
||||
|
||||
class A02yyuwComponent : public sensor::Sensor, public Component, public uart::UARTDevice {
|
||||
public:
|
||||
@@ -23,5 +22,4 @@ class A02yyuwComponent : public sensor::Sensor, public Component, public uart::U
|
||||
std::vector<uint8_t> buffer_;
|
||||
};
|
||||
|
||||
} // namespace a02yyuw
|
||||
} // namespace esphome
|
||||
} // namespace esphome::a02yyuw
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "a4988.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace a4988 {
|
||||
namespace esphome::a4988 {
|
||||
|
||||
static const char *const TAG = "a4988.stepper";
|
||||
|
||||
@@ -51,5 +50,4 @@ void A4988::loop() {
|
||||
this->step_pin_->digital_write(false);
|
||||
}
|
||||
|
||||
} // namespace a4988
|
||||
} // namespace esphome
|
||||
} // namespace esphome::a4988
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/components/stepper/stepper.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace a4988 {
|
||||
namespace esphome::a4988 {
|
||||
|
||||
class A4988 : public stepper::Stepper, public Component {
|
||||
public:
|
||||
@@ -25,5 +24,4 @@ class A4988 : public stepper::Stepper, public Component {
|
||||
HighFrequencyLoopRequester high_freq_;
|
||||
};
|
||||
|
||||
} // namespace a4988
|
||||
} // namespace esphome
|
||||
} // namespace esphome::a4988
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "adalight_light_effect.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace adalight {
|
||||
namespace esphome::adalight {
|
||||
|
||||
static const char *const TAG = "adalight_light_effect";
|
||||
|
||||
@@ -138,5 +137,4 @@ AdalightLightEffect::Frame AdalightLightEffect::parse_frame_(light::AddressableL
|
||||
return CONSUMED;
|
||||
}
|
||||
|
||||
} // namespace adalight
|
||||
} // namespace esphome
|
||||
} // namespace esphome::adalight
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace adalight {
|
||||
namespace esphome::adalight {
|
||||
|
||||
class AdalightLightEffect : public light::AddressableLightEffect, public uart::UARTDevice {
|
||||
public:
|
||||
@@ -35,5 +34,4 @@ class AdalightLightEffect : public light::AddressableLightEffect, public uart::U
|
||||
std::vector<uint8_t> frame_;
|
||||
};
|
||||
|
||||
} // namespace adalight
|
||||
} // namespace esphome
|
||||
} // namespace esphome::adalight
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
#include <zephyr/drivers/adc.h>
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
namespace esphome::adc {
|
||||
|
||||
#ifdef USE_ESP32
|
||||
// clang-format off
|
||||
@@ -162,5 +161,4 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace adc
|
||||
} // namespace esphome
|
||||
} // namespace esphome::adc
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "adc_sensor.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
namespace esphome::adc {
|
||||
|
||||
static const char *const TAG = "adc.common";
|
||||
|
||||
@@ -79,5 +78,4 @@ void ADCSensor::set_sample_count(uint8_t sample_count) {
|
||||
|
||||
void ADCSensor::set_sampling_mode(SamplingMode sampling_mode) { this->sampling_mode_ = sampling_mode; }
|
||||
|
||||
} // namespace adc
|
||||
} // namespace esphome
|
||||
} // namespace esphome::adc
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
#include "esphome/core/log.h"
|
||||
#include <cinttypes>
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
namespace esphome::adc {
|
||||
|
||||
static const char *const TAG = "adc.esp32";
|
||||
|
||||
@@ -364,7 +363,6 @@ float ADCSensor::sample_autorange_() {
|
||||
return final_result;
|
||||
}
|
||||
|
||||
} // namespace adc
|
||||
} // namespace esphome
|
||||
} // namespace esphome::adc
|
||||
|
||||
#endif // USE_ESP32
|
||||
|
||||
@@ -11,8 +11,7 @@ ADC_MODE(ADC_VCC)
|
||||
#include <Arduino.h>
|
||||
#endif // USE_ADC_SENSOR_VCC
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
namespace esphome::adc {
|
||||
|
||||
static const char *const TAG = "adc.esp8266";
|
||||
|
||||
@@ -55,7 +54,6 @@ float ADCSensor::sample() {
|
||||
return aggr.aggregate() / 1024.0f;
|
||||
}
|
||||
|
||||
} // namespace adc
|
||||
} // namespace esphome
|
||||
} // namespace esphome::adc
|
||||
|
||||
#endif // USE_ESP8266
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "adc_sensor.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
namespace esphome::adc {
|
||||
|
||||
static const char *const TAG = "adc.libretiny";
|
||||
|
||||
@@ -48,7 +47,6 @@ float ADCSensor::sample() {
|
||||
return aggr.aggregate() / 1000.0f;
|
||||
}
|
||||
|
||||
} // namespace adc
|
||||
} // namespace esphome
|
||||
} // namespace esphome::adc
|
||||
|
||||
#endif // USE_LIBRETINY
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
#define PICO_VSYS_PIN 29 // NOLINT(cppcoreguidelines-macro-usage)
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
namespace esphome::adc {
|
||||
|
||||
static const char *const TAG = "adc.rp2040";
|
||||
|
||||
@@ -98,7 +97,6 @@ float ADCSensor::sample() {
|
||||
return aggr.aggregate() * 3.3f / 4096.0f * coeff;
|
||||
}
|
||||
|
||||
} // namespace adc
|
||||
} // namespace esphome
|
||||
} // namespace esphome::adc
|
||||
|
||||
#endif // USE_RP2040
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
|
||||
#include "hal/nrf_saadc.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
namespace esphome::adc {
|
||||
|
||||
static const char *const TAG = "adc.zephyr";
|
||||
|
||||
@@ -202,6 +201,5 @@ float ADCSensor::sample() {
|
||||
return val_mv / 1000.0f;
|
||||
}
|
||||
|
||||
} // namespace adc
|
||||
} // namespace esphome
|
||||
} // namespace esphome::adc
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "adc128s102.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace adc128s102 {
|
||||
namespace esphome::adc128s102 {
|
||||
|
||||
static const char *const TAG = "adc128s102";
|
||||
|
||||
@@ -28,5 +27,4 @@ uint16_t ADC128S102::read_data(uint8_t channel) {
|
||||
return digital_value;
|
||||
}
|
||||
|
||||
} // namespace adc128s102
|
||||
} // namespace esphome
|
||||
} // namespace esphome::adc128s102
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/components/spi/spi.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace adc128s102 {
|
||||
namespace esphome::adc128s102 {
|
||||
|
||||
class ADC128S102 : public Component,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
|
||||
@@ -19,5 +18,4 @@ class ADC128S102 : public Component,
|
||||
uint16_t read_data(uint8_t channel);
|
||||
};
|
||||
|
||||
} // namespace adc128s102
|
||||
} // namespace esphome
|
||||
} // namespace esphome::adc128s102
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace adc128s102 {
|
||||
namespace esphome::adc128s102 {
|
||||
|
||||
static const char *const TAG = "adc128s102.sensor";
|
||||
|
||||
@@ -18,5 +17,4 @@ void ADC128S102Sensor::dump_config() {
|
||||
float ADC128S102Sensor::sample() { return this->parent_->read_data(this->channel_); }
|
||||
void ADC128S102Sensor::update() { this->publish_state(this->sample()); }
|
||||
|
||||
} // namespace adc128s102
|
||||
} // namespace esphome
|
||||
} // namespace esphome::adc128s102
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
|
||||
#include "../adc128s102.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace adc128s102 {
|
||||
namespace esphome::adc128s102 {
|
||||
|
||||
class ADC128S102Sensor : public PollingComponent,
|
||||
public Parented<ADC128S102>,
|
||||
@@ -24,5 +23,4 @@ class ADC128S102Sensor : public PollingComponent,
|
||||
protected:
|
||||
uint8_t channel_;
|
||||
};
|
||||
} // namespace adc128s102
|
||||
} // namespace esphome
|
||||
} // namespace esphome::adc128s102
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "addressable_light_display.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace addressable_light {
|
||||
namespace esphome::addressable_light {
|
||||
|
||||
static const char *const TAG = "addressable_light.display";
|
||||
|
||||
@@ -66,5 +65,4 @@ void HOT AddressableLightDisplay::draw_absolute_pixel_internal(int x, int y, Col
|
||||
this->addressable_light_buffer_[y * this->get_width_internal() + x] = color;
|
||||
}
|
||||
}
|
||||
} // namespace addressable_light
|
||||
} // namespace esphome
|
||||
} // namespace esphome::addressable_light
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace addressable_light {
|
||||
namespace esphome::addressable_light {
|
||||
|
||||
class AddressableLightDisplay : public display::DisplayBuffer {
|
||||
public:
|
||||
@@ -61,5 +60,4 @@ class AddressableLightDisplay : public display::DisplayBuffer {
|
||||
optional<uint32_t> last_effect_index_;
|
||||
optional<std::function<int(int, int)>> pixel_mapper_f_;
|
||||
};
|
||||
} // namespace addressable_light
|
||||
} // namespace esphome
|
||||
} // namespace esphome::addressable_light
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
namespace esphome {
|
||||
namespace ade7880 {
|
||||
namespace esphome::ade7880 {
|
||||
|
||||
static const char *const TAG = "ade7880";
|
||||
|
||||
@@ -313,5 +312,4 @@ void ADE7880::reset_device_() {
|
||||
this->store_.reset_pending = true;
|
||||
}
|
||||
|
||||
} // namespace ade7880
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ade7880
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
|
||||
#include "ade7880_registers.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ade7880 {
|
||||
namespace esphome::ade7880 {
|
||||
|
||||
struct NeutralChannel {
|
||||
void set_current(sensor::Sensor *sens) { this->current = sens; }
|
||||
@@ -125,5 +124,4 @@ class ADE7880 : public i2c::I2CDevice, public PollingComponent {
|
||||
void write_u32_register16_(uint16_t a_register, uint32_t value);
|
||||
};
|
||||
|
||||
} // namespace ade7880
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ade7880
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
|
||||
#include "ade7880.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ade7880 {
|
||||
namespace esphome::ade7880 {
|
||||
|
||||
// adapted from https://stackoverflow.com/a/55912127/1886371
|
||||
template<size_t Bits, typename T> inline T sign_extend(const T &v) noexcept {
|
||||
@@ -97,5 +96,4 @@ 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 ade7880
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ade7880
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
// Source: https://www.analog.com/media/en/technical-documentation/application-notes/AN-1127.pdf
|
||||
|
||||
namespace esphome {
|
||||
namespace ade7880 {
|
||||
namespace esphome::ade7880 {
|
||||
|
||||
// DSP Data Memory RAM registers
|
||||
constexpr uint16_t AIGAIN = 0x4380;
|
||||
@@ -242,5 +241,4 @@ constexpr uint8_t DSPWP_SET_RO = (1 << 7);
|
||||
// DSPWP_SEL Register Bits
|
||||
constexpr uint8_t DSPWP_SEL_SET = 0xAD;
|
||||
|
||||
} // namespace ade7880
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ade7880
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
namespace esphome {
|
||||
namespace ade7953_base {
|
||||
namespace esphome::ade7953_base {
|
||||
|
||||
static const char *const TAG = "ade7953";
|
||||
|
||||
@@ -160,5 +159,4 @@ void ADE7953::update() {
|
||||
ADE_PUBLISH(frequency, 223750.0f, 1 + val_16);
|
||||
}
|
||||
|
||||
} // namespace ade7953_base
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ade7953_base
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace ade7953_base {
|
||||
namespace esphome::ade7953_base {
|
||||
|
||||
static constexpr uint8_t PGA_V_8 =
|
||||
0x007; // PGA_V, (R/W) Default: 0x00, Unsigned, Voltage channel gain configuration (Bits[2:0])
|
||||
@@ -131,5 +130,4 @@ class ADE7953 : public PollingComponent, public sensor::Sensor {
|
||||
virtual bool ade_read_32(uint16_t reg, uint32_t *value) = 0;
|
||||
};
|
||||
|
||||
} // namespace ade7953_base
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ade7953_base
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ade7953_i2c {
|
||||
namespace esphome::ade7953_i2c {
|
||||
|
||||
static const char *const TAG = "ade7953";
|
||||
|
||||
@@ -76,5 +75,4 @@ bool AdE7953I2c::ade_read_32(uint16_t reg, uint32_t *value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ade7953_i2c
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ade7953_i2c
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace ade7953_i2c {
|
||||
namespace esphome::ade7953_i2c {
|
||||
|
||||
class AdE7953I2c : public ade7953_base::ADE7953, public i2c::I2CDevice {
|
||||
public:
|
||||
@@ -24,5 +23,4 @@ class AdE7953I2c : public ade7953_base::ADE7953, public i2c::I2CDevice {
|
||||
bool ade_read_32(uint16_t reg, uint32_t *value) override;
|
||||
};
|
||||
|
||||
} // namespace ade7953_i2c
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ade7953_i2c
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ade7953_spi {
|
||||
namespace esphome::ade7953_spi {
|
||||
|
||||
static const char *const TAG = "ade7953";
|
||||
|
||||
@@ -83,5 +82,4 @@ bool AdE7953Spi::ade_read_32(uint16_t reg, uint32_t *value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ade7953_spi
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ade7953_spi
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace ade7953_spi {
|
||||
namespace esphome::ade7953_spi {
|
||||
|
||||
class AdE7953Spi : public ade7953_base::ADE7953,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_HIGH, spi::CLOCK_PHASE_TRAILING,
|
||||
@@ -28,5 +27,4 @@ class AdE7953Spi : public ade7953_base::ADE7953,
|
||||
bool ade_read_32(uint16_t reg, uint32_t *value) override;
|
||||
};
|
||||
|
||||
} // namespace ade7953_spi
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ade7953_spi
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ads1115 {
|
||||
namespace esphome::ads1115 {
|
||||
|
||||
static const char *const TAG = "ads1115";
|
||||
static const uint8_t ADS1115_REGISTER_CONVERSION = 0x00;
|
||||
@@ -208,5 +207,4 @@ float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1
|
||||
return millivolts / 1e3f;
|
||||
}
|
||||
|
||||
} // namespace ads1115
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ads1115
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
namespace ads1115 {
|
||||
namespace esphome::ads1115 {
|
||||
|
||||
enum ADS1115Multiplexer {
|
||||
ADS1115_MULTIPLEXER_P0_N1 = 0b000,
|
||||
@@ -60,5 +59,4 @@ class ADS1115Component : public Component, public i2c::I2CDevice {
|
||||
bool continuous_mode_;
|
||||
};
|
||||
|
||||
} // namespace ads1115
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ads1115
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ads1115 {
|
||||
namespace esphome::ads1115 {
|
||||
|
||||
static const char *const TAG = "ads1115.sensor";
|
||||
|
||||
@@ -29,5 +28,4 @@ void ADS1115Sensor::dump_config() {
|
||||
this->multiplexer_, this->gain_, this->resolution_, this->samplerate_);
|
||||
}
|
||||
|
||||
} // namespace ads1115
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ads1115
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
|
||||
#include "../ads1115.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ads1115 {
|
||||
namespace esphome::ads1115 {
|
||||
|
||||
/// Internal holder class that is in instance of Sensor so that the hub can create individual sensors.
|
||||
class ADS1115Sensor : public sensor::Sensor,
|
||||
@@ -33,5 +32,4 @@ class ADS1115Sensor : public sensor::Sensor,
|
||||
ADS1115Samplerate samplerate_;
|
||||
};
|
||||
|
||||
} // namespace ads1115
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ads1115
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ads1118 {
|
||||
namespace esphome::ads1118 {
|
||||
|
||||
static const char *const TAG = "ads1118";
|
||||
static const uint8_t ADS1118_DATA_RATE_860_SPS = 0b111;
|
||||
@@ -122,5 +121,4 @@ float ADS1118::request_measurement(ADS1118Multiplexer multiplexer, ADS1118Gain g
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ads1118
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ads1118
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ads1118 {
|
||||
namespace esphome::ads1118 {
|
||||
|
||||
enum ADS1118Multiplexer {
|
||||
ADS1118_MULTIPLEXER_P0_N1 = 0b000,
|
||||
@@ -41,5 +40,4 @@ class ADS1118 : public Component,
|
||||
uint16_t config_{0};
|
||||
};
|
||||
|
||||
} // namespace ads1118
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ads1118
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ads1118 {
|
||||
namespace esphome::ads1118 {
|
||||
|
||||
static const char *const TAG = "ads1118.sensor";
|
||||
|
||||
@@ -27,5 +26,4 @@ void ADS1118Sensor::update() {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ads1118
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ads1118
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
|
||||
#include "../ads1118.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ads1118 {
|
||||
namespace esphome::ads1118 {
|
||||
|
||||
class ADS1118Sensor : public PollingComponent,
|
||||
public sensor::Sensor,
|
||||
@@ -32,5 +31,4 @@ class ADS1118Sensor : public PollingComponent,
|
||||
bool temperature_mode_;
|
||||
};
|
||||
|
||||
} // namespace ads1118
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ads1118
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
namespace esphome {
|
||||
namespace ags10 {
|
||||
namespace esphome::ags10 {
|
||||
static const char *const TAG = "ags10";
|
||||
|
||||
// Data acquisition.
|
||||
@@ -192,5 +191,4 @@ template<size_t N> optional<std::array<uint8_t, N>> AGS10Component::read_and_che
|
||||
|
||||
return data;
|
||||
}
|
||||
} // namespace ags10
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ags10
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ags10 {
|
||||
namespace esphome::ags10 {
|
||||
|
||||
class AGS10Component : public PollingComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
@@ -136,5 +135,4 @@ template<typename... Ts> class AGS10SetZeroPointAction : public Action<Ts...>, p
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace ags10
|
||||
} // namespace esphome
|
||||
} // namespace esphome::ags10
|
||||
|
||||
@@ -17,8 +17,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace aht10 {
|
||||
namespace esphome::aht10 {
|
||||
|
||||
static const char *const TAG = "aht10";
|
||||
static const uint8_t AHT10_INITIALIZE_CMD[] = {0xE1, 0x08, 0x00};
|
||||
@@ -160,5 +159,4 @@ void AHT10Component::dump_config() {
|
||||
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
|
||||
}
|
||||
|
||||
} // namespace aht10
|
||||
} // namespace esphome
|
||||
} // namespace esphome::aht10
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace aht10 {
|
||||
namespace esphome::aht10 {
|
||||
|
||||
enum AHT10Variant { AHT10, AHT20 };
|
||||
|
||||
@@ -31,5 +30,4 @@ class AHT10Component : public PollingComponent, public i2c::I2CDevice {
|
||||
uint32_t start_time_{};
|
||||
};
|
||||
|
||||
} // namespace aht10
|
||||
} // namespace esphome
|
||||
} // namespace esphome::aht10
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace aic3204 {
|
||||
namespace esphome::aic3204 {
|
||||
|
||||
static const char *const TAG = "aic3204";
|
||||
|
||||
@@ -167,5 +166,4 @@ bool AIC3204::write_volume_() {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace aic3204
|
||||
} // namespace esphome
|
||||
} // namespace esphome::aic3204
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace aic3204 {
|
||||
namespace esphome::aic3204 {
|
||||
|
||||
// TLV320AIC3204 Register Addresses
|
||||
// Page 0
|
||||
@@ -83,5 +82,4 @@ class AIC3204 : public audio_dac::AudioDac, public Component, public i2c::I2CDev
|
||||
float volume_{0};
|
||||
};
|
||||
|
||||
} // namespace aic3204
|
||||
} // namespace esphome
|
||||
} // namespace esphome::aic3204
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "aic3204.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace aic3204 {
|
||||
namespace esphome::aic3204 {
|
||||
|
||||
template<typename... Ts> class SetAutoMuteAction : public Action<Ts...> {
|
||||
public:
|
||||
@@ -19,5 +18,4 @@ template<typename... Ts> class SetAutoMuteAction : public Action<Ts...> {
|
||||
AIC3204 *aic3204_;
|
||||
};
|
||||
|
||||
} // namespace aic3204
|
||||
} // namespace esphome
|
||||
} // namespace esphome::aic3204
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
namespace esphome {
|
||||
namespace airthings_ble {
|
||||
namespace esphome::airthings_ble {
|
||||
|
||||
static const char *const TAG = "airthings_ble";
|
||||
|
||||
@@ -29,7 +28,6 @@ bool AirthingsListener::parse_device(const esp32_ble_tracker::ESPBTDevice &devic
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace airthings_ble
|
||||
} // namespace esphome
|
||||
} // namespace esphome::airthings_ble
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,15 +5,13 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace airthings_ble {
|
||||
namespace esphome::airthings_ble {
|
||||
|
||||
class AirthingsListener : public esp32_ble_tracker::ESPBTDeviceListener {
|
||||
public:
|
||||
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
|
||||
};
|
||||
|
||||
} // namespace airthings_ble
|
||||
} // namespace esphome
|
||||
} // namespace esphome::airthings_ble
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
namespace esphome {
|
||||
namespace airthings_wave_base {
|
||||
namespace esphome::airthings_wave_base {
|
||||
|
||||
static const char *const TAG = "airthings_wave_base";
|
||||
|
||||
@@ -211,7 +210,6 @@ void AirthingsWaveBase::set_response_timeout_() {
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace airthings_wave_base
|
||||
} // namespace esphome
|
||||
} // namespace esphome::airthings_wave_base
|
||||
|
||||
#endif // USE_ESP32
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace airthings_wave_base {
|
||||
namespace esphome::airthings_wave_base {
|
||||
|
||||
namespace espbt = esphome::esp32_ble_tracker;
|
||||
|
||||
@@ -84,7 +83,6 @@ class AirthingsWaveBase : public PollingComponent, public ble_client::BLEClientN
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace airthings_wave_base
|
||||
} // namespace esphome
|
||||
} // namespace esphome::airthings_wave_base
|
||||
|
||||
#endif // USE_ESP32
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
namespace esphome {
|
||||
namespace airthings_wave_mini {
|
||||
namespace esphome::airthings_wave_mini {
|
||||
|
||||
static const char *const TAG = "airthings_wave_mini";
|
||||
|
||||
@@ -49,7 +48,6 @@ AirthingsWaveMini::AirthingsWaveMini() {
|
||||
espbt::ESPBTUUID::from_raw(ACCESS_CONTROL_POINT_CHARACTERISTIC_UUID);
|
||||
}
|
||||
|
||||
} // namespace airthings_wave_mini
|
||||
} // namespace esphome
|
||||
} // namespace esphome::airthings_wave_mini
|
||||
|
||||
#endif // USE_ESP32
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
#include "esphome/components/airthings_wave_base/airthings_wave_base.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace airthings_wave_mini {
|
||||
namespace esphome::airthings_wave_mini {
|
||||
|
||||
namespace espbt = esphome::esp32_ble_tracker;
|
||||
|
||||
@@ -34,7 +33,6 @@ class AirthingsWaveMini : public airthings_wave_base::AirthingsWaveBase {
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace airthings_wave_mini
|
||||
} // namespace esphome
|
||||
} // namespace esphome::airthings_wave_mini
|
||||
|
||||
#endif // USE_ESP32
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
namespace esphome {
|
||||
namespace airthings_wave_plus {
|
||||
namespace esphome::airthings_wave_plus {
|
||||
|
||||
static const char *const TAG = "airthings_wave_plus";
|
||||
|
||||
@@ -98,7 +97,6 @@ void AirthingsWavePlus::setup() {
|
||||
espbt::ESPBTUUID::from_raw(access_control_point_characteristic_uuid);
|
||||
}
|
||||
|
||||
} // namespace airthings_wave_plus
|
||||
} // namespace esphome
|
||||
} // namespace esphome::airthings_wave_plus
|
||||
|
||||
#endif // USE_ESP32
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
#include "esphome/components/airthings_wave_base/airthings_wave_base.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace airthings_wave_plus {
|
||||
namespace esphome::airthings_wave_plus {
|
||||
|
||||
namespace espbt = esphome::esp32_ble_tracker;
|
||||
|
||||
@@ -58,7 +57,6 @@ class AirthingsWavePlus : public airthings_wave_base::AirthingsWaveBase {
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace airthings_wave_plus
|
||||
} // namespace esphome
|
||||
} // namespace esphome::airthings_wave_plus
|
||||
|
||||
#endif // USE_ESP32
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
namespace esphome {
|
||||
namespace alpha3 {
|
||||
namespace esphome::alpha3 {
|
||||
|
||||
static const char *const TAG = "alpha3";
|
||||
|
||||
@@ -185,7 +184,6 @@ void Alpha3::update() {
|
||||
delay(25); // need to wait between requests
|
||||
}
|
||||
}
|
||||
} // namespace alpha3
|
||||
} // namespace esphome
|
||||
} // namespace esphome::alpha3
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
|
||||
#include <esp_gattc_api.h>
|
||||
|
||||
namespace esphome {
|
||||
namespace alpha3 {
|
||||
namespace esphome::alpha3 {
|
||||
|
||||
namespace espbt = esphome::esp32_ble_tracker;
|
||||
|
||||
@@ -64,7 +63,6 @@ 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 alpha3
|
||||
} // namespace esphome
|
||||
} // namespace esphome::alpha3
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace am2315c {
|
||||
namespace esphome::am2315c {
|
||||
|
||||
static const char *const TAG = "am2315c";
|
||||
|
||||
@@ -176,5 +175,4 @@ void AM2315C::dump_config() {
|
||||
LOG_SENSOR(" ", "Humidity", this->humidity_sensor_);
|
||||
}
|
||||
|
||||
} // namespace am2315c
|
||||
} // namespace esphome
|
||||
} // namespace esphome::am2315c
|
||||
|
||||
@@ -25,8 +25,7 @@
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/core/component.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace am2315c {
|
||||
namespace esphome::am2315c {
|
||||
|
||||
class AM2315C : public PollingComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
@@ -45,5 +44,4 @@ class AM2315C : public PollingComponent, public i2c::I2CDevice {
|
||||
sensor::Sensor *humidity_sensor_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace am2315c
|
||||
} // namespace esphome
|
||||
} // namespace esphome::am2315c
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace am2320 {
|
||||
namespace esphome::am2320 {
|
||||
|
||||
static const char *const TAG = "am2320";
|
||||
|
||||
@@ -86,5 +85,4 @@ bool AM2320Component::read_data_(uint8_t *data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace am2320
|
||||
} // namespace esphome
|
||||
} // namespace esphome::am2320
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace am2320 {
|
||||
namespace esphome::am2320 {
|
||||
|
||||
class AM2320Component : public PollingComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
@@ -24,5 +23,4 @@ class AM2320Component : public PollingComponent, public i2c::I2CDevice {
|
||||
sensor::Sensor *humidity_sensor_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace am2320
|
||||
} // namespace esphome
|
||||
} // namespace esphome::am2320
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace esphome {
|
||||
namespace am43 {
|
||||
namespace esphome::am43 {
|
||||
|
||||
const uint8_t START_PACKET[5] = {0x00, 0xff, 0x00, 0x00, 0x9a};
|
||||
|
||||
@@ -134,5 +133,4 @@ void Am43Decoder::decode(const uint8_t *data, uint16_t length) {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace am43
|
||||
} // namespace esphome
|
||||
} // namespace esphome::am43
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace am43 {
|
||||
namespace esphome::am43 {
|
||||
|
||||
static const uint16_t AM43_SERVICE_UUID = 0xFE50;
|
||||
static const uint16_t AM43_CHARACTERISTIC_UUID = 0xFE51;
|
||||
@@ -74,5 +73,4 @@ class Am43Decoder {
|
||||
bool has_pin_response_;
|
||||
};
|
||||
|
||||
} // namespace am43
|
||||
} // namespace esphome
|
||||
} // namespace esphome::am43
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
namespace esphome {
|
||||
namespace am43 {
|
||||
namespace esphome::am43 {
|
||||
|
||||
static const char *const TAG = "am43_cover";
|
||||
|
||||
@@ -154,7 +153,6 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace am43
|
||||
} // namespace esphome
|
||||
} // namespace esphome::am43
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
|
||||
#include <esp_gattc_api.h>
|
||||
|
||||
namespace esphome {
|
||||
namespace am43 {
|
||||
namespace esphome::am43 {
|
||||
|
||||
namespace espbt = esphome::esp32_ble_tracker;
|
||||
|
||||
@@ -38,7 +37,6 @@ class Am43Component : public cover::Cover, public esphome::ble_client::BLEClient
|
||||
float position_;
|
||||
};
|
||||
|
||||
} // namespace am43
|
||||
} // namespace esphome
|
||||
} // namespace esphome::am43
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
namespace esphome {
|
||||
namespace am43 {
|
||||
namespace esphome::am43 {
|
||||
|
||||
static const char *const TAG = "am43";
|
||||
|
||||
@@ -111,7 +110,6 @@ void Am43::update() {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace am43
|
||||
} // namespace esphome
|
||||
} // namespace esphome::am43
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
|
||||
#include <esp_gattc_api.h>
|
||||
|
||||
namespace esphome {
|
||||
namespace am43 {
|
||||
namespace esphome::am43 {
|
||||
|
||||
namespace espbt = esphome::esp32_ble_tracker;
|
||||
|
||||
@@ -38,7 +37,6 @@ class Am43 : public esphome::ble_client::BLEClientNode, public PollingComponent
|
||||
uint32_t last_battery_update_;
|
||||
};
|
||||
|
||||
} // namespace am43
|
||||
} // namespace esphome
|
||||
} // namespace esphome::am43
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "analog_threshold_binary_sensor.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace analog_threshold {
|
||||
namespace esphome::analog_threshold {
|
||||
|
||||
static const char *const TAG = "analog_threshold.binary_sensor";
|
||||
|
||||
@@ -43,5 +42,4 @@ void AnalogThresholdBinarySensor::dump_config() {
|
||||
this->upper_threshold_.value(), this->lower_threshold_.value());
|
||||
}
|
||||
|
||||
} // namespace analog_threshold
|
||||
} // namespace esphome
|
||||
} // namespace esphome::analog_threshold
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace analog_threshold {
|
||||
namespace esphome::analog_threshold {
|
||||
|
||||
class AnalogThresholdBinarySensor : public Component, public binary_sensor::BinarySensor {
|
||||
public:
|
||||
@@ -24,5 +23,4 @@ class AnalogThresholdBinarySensor : public Component, public binary_sensor::Bina
|
||||
bool raw_state_{false}; // Pre-filter state for hysteresis logic
|
||||
};
|
||||
|
||||
} // namespace analog_threshold
|
||||
} // namespace esphome
|
||||
} // namespace esphome::analog_threshold
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace animation {
|
||||
namespace esphome::animation {
|
||||
|
||||
Animation::Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count,
|
||||
image::ImageType type, image::Transparency transparent)
|
||||
@@ -71,5 +70,4 @@ void Animation::update_data_start_() {
|
||||
this->data_start_ = this->animation_data_start_ + image_size * this->current_frame_;
|
||||
}
|
||||
|
||||
} // namespace animation
|
||||
} // namespace esphome
|
||||
} // namespace esphome::animation
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
#include "esphome/core/automation.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace animation {
|
||||
namespace esphome::animation {
|
||||
|
||||
class Animation : public image::Image {
|
||||
public:
|
||||
@@ -64,5 +63,4 @@ template<typename... Ts> class AnimationSetFrameAction : public Action<Ts...> {
|
||||
Animation *parent_;
|
||||
};
|
||||
|
||||
} // namespace animation
|
||||
} // namespace esphome
|
||||
} // namespace esphome::animation
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
namespace esphome {
|
||||
namespace anova {
|
||||
namespace esphome::anova {
|
||||
|
||||
static const char *const TAG = "anova";
|
||||
|
||||
@@ -160,7 +159,6 @@ void Anova::update() {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace anova
|
||||
} // namespace esphome
|
||||
} // namespace esphome::anova
|
||||
|
||||
#endif
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
|
||||
#include <esp_gattc_api.h>
|
||||
|
||||
namespace esphome {
|
||||
namespace anova {
|
||||
namespace esphome::anova {
|
||||
|
||||
namespace espbt = esphome::esp32_ble_tracker;
|
||||
|
||||
@@ -45,7 +44,6 @@ class Anova : public climate::Climate, public esphome::ble_client::BLEClientNode
|
||||
bool fahrenheit_;
|
||||
};
|
||||
|
||||
} // namespace anova
|
||||
} // namespace esphome
|
||||
} // namespace esphome::anova
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user