mirror of
https://github.com/esphome/esphome.git
synced 2026-06-29 20:16:08 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a251f4eb74 |
@@ -17,12 +17,12 @@ runs:
|
||||
steps:
|
||||
- name: Set up Python ${{ inputs.python-version }}
|
||||
id: python
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: ${{ inputs.python-version }}
|
||||
- name: Restore Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: venv
|
||||
# yamllint disable-line rule:line-length
|
||||
|
||||
@@ -147,9 +147,19 @@ async function detectCoreChanges(changedFiles) {
|
||||
}
|
||||
|
||||
// Strategy: PR size detection
|
||||
async function detectPRSize(prFiles, totalAdditions, totalDeletions, isMegaPR, SMALL_PR_THRESHOLD, MEDIUM_PR_THRESHOLD, TOO_BIG_THRESHOLD) {
|
||||
async function detectPRSize(prFiles, totalAdditions, totalDeletions, totalChanges, isMegaPR, SMALL_PR_THRESHOLD, MEDIUM_PR_THRESHOLD, TOO_BIG_THRESHOLD) {
|
||||
const labels = new Set();
|
||||
|
||||
if (totalChanges <= SMALL_PR_THRESHOLD) {
|
||||
labels.add('small-pr');
|
||||
return labels;
|
||||
}
|
||||
|
||||
if (totalChanges <= MEDIUM_PR_THRESHOLD) {
|
||||
labels.add('medium-pr');
|
||||
return labels;
|
||||
}
|
||||
|
||||
const testAdditions = prFiles
|
||||
.filter(file => file.filename.startsWith('tests/'))
|
||||
.reduce((sum, file) => sum + (file.additions || 0), 0);
|
||||
@@ -157,24 +167,7 @@ async function detectPRSize(prFiles, totalAdditions, totalDeletions, isMegaPR, S
|
||||
.filter(file => file.filename.startsWith('tests/'))
|
||||
.reduce((sum, file) => sum + (file.deletions || 0), 0);
|
||||
|
||||
const nonTestAdditions = totalAdditions - testAdditions;
|
||||
const nonTestDeletions = totalDeletions - testDeletions;
|
||||
|
||||
// small/medium count churn (additions + deletions) so a balanced refactor isn't undersized.
|
||||
const nonTestChurn = nonTestAdditions + nonTestDeletions;
|
||||
|
||||
if (nonTestChurn <= SMALL_PR_THRESHOLD) {
|
||||
labels.add('small-pr');
|
||||
return labels;
|
||||
}
|
||||
|
||||
if (nonTestChurn <= MEDIUM_PR_THRESHOLD) {
|
||||
labels.add('medium-pr');
|
||||
return labels;
|
||||
}
|
||||
|
||||
// too-big uses net line delta (additions - deletions), matching the review message in reviews.js.
|
||||
const nonTestChanges = nonTestAdditions - nonTestDeletions;
|
||||
const nonTestChanges = (totalAdditions - testAdditions) - (totalDeletions - testDeletions);
|
||||
|
||||
// Don't add too-big if mega-pr label is already present
|
||||
if (nonTestChanges > TOO_BIG_THRESHOLD && !isMegaPR) {
|
||||
|
||||
@@ -123,7 +123,7 @@ module.exports = async ({ github, context }) => {
|
||||
detectNewComponents(github, context, prFiles),
|
||||
detectNewPlatforms(github, context, prFiles, apiData),
|
||||
detectCoreChanges(changedFiles),
|
||||
detectPRSize(prFiles, totalAdditions, totalDeletions, isMegaPR, SMALL_PR_THRESHOLD, MEDIUM_PR_THRESHOLD, TOO_BIG_THRESHOLD),
|
||||
detectPRSize(prFiles, totalAdditions, totalDeletions, totalChanges, isMegaPR, SMALL_PR_THRESHOLD, MEDIUM_PR_THRESHOLD, TOO_BIG_THRESHOLD),
|
||||
detectDashboardChanges(changedFiles),
|
||||
detectGitHubActionsChanges(changedFiles),
|
||||
detectCodeOwner(github, context, changedFiles),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const { describe, it } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const { detectNewPlatforms, detectNewComponents, detectPRSize } = require('../detectors');
|
||||
const { detectNewPlatforms, detectNewComponents } = require('../detectors');
|
||||
|
||||
// Minimal GitHub API mock — only repos.getContent is called by detectNewPlatforms/detectNewComponents
|
||||
// to check for CONFIG_SCHEMA in newly added files.
|
||||
@@ -145,79 +145,3 @@ describe('detectNewComponents', () => {
|
||||
assert.equal(result.labels.size, 0);
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// detectPRSize
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('detectPRSize', () => {
|
||||
const SMALL = 30;
|
||||
const MEDIUM = 100;
|
||||
const TOO_BIG = 1000;
|
||||
|
||||
function size(prFiles, isMegaPR = false) {
|
||||
const totalAdditions = prFiles.reduce((sum, file) => sum + (file.additions || 0), 0);
|
||||
const totalDeletions = prFiles.reduce((sum, file) => sum + (file.deletions || 0), 0);
|
||||
return detectPRSize(prFiles, totalAdditions, totalDeletions, isMegaPR, SMALL, MEDIUM, TOO_BIG);
|
||||
}
|
||||
|
||||
it('counts only non-test changes toward small-pr', async () => {
|
||||
// 10 source + 5000 test lines -> non-test churn of 10 is still small.
|
||||
const labels = await size([
|
||||
{ filename: 'esphome/components/foo/foo.cpp', additions: 10, deletions: 0 },
|
||||
{ filename: 'tests/components/foo/test.esp32-idf.yaml', additions: 5000, deletions: 0 },
|
||||
]);
|
||||
assert.ok(labels.has('small-pr'));
|
||||
assert.equal(labels.size, 1);
|
||||
});
|
||||
|
||||
it('counts additions and deletions as churn (not net delta)', async () => {
|
||||
// A balanced refactor (40 added, 40 removed) is 80 lines of churn -> medium, not small.
|
||||
const labels = await size([
|
||||
{ filename: 'esphome/components/foo/foo.cpp', additions: 40, deletions: 40 },
|
||||
]);
|
||||
assert.ok(labels.has('medium-pr'));
|
||||
assert.equal(labels.size, 1);
|
||||
});
|
||||
|
||||
it('labels medium-pr when non-test changes exceed small threshold', async () => {
|
||||
const labels = await size([
|
||||
{ filename: 'esphome/components/foo/foo.cpp', additions: 60, deletions: 0 },
|
||||
{ filename: 'tests/components/foo/test.esp32-idf.yaml', additions: 5000, deletions: 0 },
|
||||
]);
|
||||
assert.ok(labels.has('medium-pr'));
|
||||
assert.equal(labels.size, 1);
|
||||
});
|
||||
|
||||
it('uses net delta (not churn) for too-big', async () => {
|
||||
// 600 added + 600 removed: 1200 churn (above too-big) but 0 net delta -> not too-big.
|
||||
const labels = await size([
|
||||
{ filename: 'esphome/components/foo/foo.cpp', additions: 600, deletions: 600 },
|
||||
]);
|
||||
assert.equal(labels.size, 0);
|
||||
});
|
||||
|
||||
it('labels too-big when non-test changes exceed the big threshold', async () => {
|
||||
const labels = await size([
|
||||
{ filename: 'esphome/components/foo/foo.cpp', additions: 2000, deletions: 0 },
|
||||
{ filename: 'tests/components/foo/test.esp32-idf.yaml', additions: 5000, deletions: 0 },
|
||||
]);
|
||||
assert.ok(labels.has('too-big'));
|
||||
assert.equal(labels.size, 1);
|
||||
});
|
||||
|
||||
it('does not label too-big when mega-pr is set', async () => {
|
||||
const labels = await size([
|
||||
{ filename: 'esphome/components/foo/foo.cpp', additions: 2000, deletions: 0 },
|
||||
], true);
|
||||
assert.equal(labels.size, 0);
|
||||
});
|
||||
|
||||
it('produces no size label for a large mega-pr in the gap above medium', async () => {
|
||||
// Non-test changes land between MEDIUM and TOO_BIG: not small/medium, and mega-pr suppresses too-big.
|
||||
const labels = await size([
|
||||
{ filename: 'esphome/components/foo/foo.cpp', additions: 500, deletions: 0 },
|
||||
], true);
|
||||
assert.equal(labels.size, 0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -23,9 +23,9 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
python-version: "3.11"
|
||||
- name: Set up uv
|
||||
# ``--system`` (below) installs into the setup-python interpreter;
|
||||
# no venv is created or restored by this workflow.
|
||||
|
||||
@@ -63,9 +63,9 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
python-version: "3.11"
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
|
||||
|
||||
@@ -147,9 +147,9 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
python-version: "3.11"
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
if: steps.pr.outputs.skip != 'true'
|
||||
uses: ./.github/actions/restore-python
|
||||
with:
|
||||
python-version: "3.12"
|
||||
python-version: "3.11"
|
||||
cache-key: ${{ hashFiles('.cache-key') }}
|
||||
|
||||
- name: Download memory analysis artifacts
|
||||
|
||||
+21
-26
@@ -12,8 +12,8 @@ permissions:
|
||||
contents: read # actions/checkout for all jobs; individual jobs add their own scopes when they need to write
|
||||
|
||||
env:
|
||||
DEFAULT_PYTHON: "3.12"
|
||||
PYUPGRADE_TARGET: "--py312-plus"
|
||||
DEFAULT_PYTHON: "3.11"
|
||||
PYUPGRADE_TARGET: "--py311-plus"
|
||||
|
||||
concurrency:
|
||||
# yamllint disable-line rule:line-length
|
||||
@@ -34,12 +34,12 @@ jobs:
|
||||
run: echo key="${{ hashFiles('requirements.txt', 'requirements_dev.txt', 'requirements_test.txt', '.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
id: python
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
- name: Restore Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: venv
|
||||
# yamllint disable-line rule:line-length
|
||||
@@ -162,7 +162,7 @@ jobs:
|
||||
ref: main
|
||||
path: device-builder
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
- name: Set up uv
|
||||
@@ -203,7 +203,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version:
|
||||
- "3.12"
|
||||
- "3.11"
|
||||
- "3.13"
|
||||
- "3.14"
|
||||
os:
|
||||
@@ -250,7 +250,7 @@ jobs:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
- name: Save Python virtual environment cache
|
||||
if: github.ref == 'refs/heads/dev'
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: venv
|
||||
key: ${{ runner.os }}-${{ steps.restore-python.outputs.python-version }}-venv-${{ needs.common.outputs.cache-key }}
|
||||
@@ -295,7 +295,7 @@ jobs:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
cache-key: ${{ needs.common.outputs.cache-key }}
|
||||
- name: Restore components graph cache
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: .temp/components_graph.json
|
||||
key: components-graph-${{ hashFiles('esphome/components/**/*.py') }}
|
||||
@@ -339,7 +339,7 @@ jobs:
|
||||
echo "benchmarks=$(echo "$output" | jq -r '.benchmarks')" >> $GITHUB_OUTPUT
|
||||
- name: Save components graph cache
|
||||
if: github.ref == 'refs/heads/dev'
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: .temp/components_graph.json
|
||||
key: components-graph-${{ hashFiles('esphome/components/**/*.py') }}
|
||||
@@ -360,12 +360,12 @@ jobs:
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- name: Set up Python 3.13
|
||||
id: python
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.13"
|
||||
- name: Restore Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: venv
|
||||
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{ needs.common.outputs.cache-key }}
|
||||
@@ -456,7 +456,7 @@ jobs:
|
||||
echo "binary=$BINARY" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Run CodSpeed benchmarks
|
||||
uses: CodSpeedHQ/action@a4a36bb07c0638b0b4ca52bf1f3dad1b4289e52f # v4.18.1
|
||||
uses: CodSpeedHQ/action@63f3e98b61959fe67f146a3ff022e4136fe9bb9c # v4.17.6
|
||||
with:
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
@@ -509,14 +509,14 @@ jobs:
|
||||
|
||||
- name: Cache platformio
|
||||
if: github.ref == 'refs/heads/dev' && matrix.pio_cache_key
|
||||
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
|
||||
|
||||
- name: Cache platformio
|
||||
if: github.ref != 'refs/heads/dev' && matrix.pio_cache_key
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
|
||||
@@ -820,10 +820,10 @@ jobs:
|
||||
run: echo ${{ matrix.components }}
|
||||
|
||||
- name: Cache apt packages
|
||||
uses: awalsh128/cache-apt-pkgs-action@5513791f75b039e2a79653b1a92238d3fb8d99b4 # v1.6.2
|
||||
uses: awalsh128/cache-apt-pkgs-action@acb598e5ddbc6f68a970c5da0688d2f3a9f04d05 # v1.5.3
|
||||
with:
|
||||
packages: libsdl2-dev ccache
|
||||
version: 1.1
|
||||
packages: libsdl2-dev
|
||||
version: 1.0
|
||||
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
@@ -941,11 +941,6 @@ jobs:
|
||||
echo "All components in this batch are validate-only -- skipping compile stage."
|
||||
fi
|
||||
|
||||
- name: Print ccache statistics
|
||||
# esphome stores the cache under the IDF tools path; expand the leading
|
||||
# ~ in ESPHOME_ESP_IDF_PREFIX so ccache reads the dir the build used.
|
||||
run: CCACHE_DIR="${ESPHOME_ESP_IDF_PREFIX/#\~/$HOME}/ccache" ccache -s
|
||||
|
||||
test-esp32-platformio:
|
||||
name: Test esp32 components with PlatformIO
|
||||
runs-on: ubuntu-24.04
|
||||
@@ -1098,7 +1093,7 @@ jobs:
|
||||
- name: Restore cached memory analysis
|
||||
id: cache-memory-analysis
|
||||
if: steps.check-script.outputs.skip != 'true' && steps.check-tests.outputs.skip != 'true'
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: memory-analysis-target.json
|
||||
key: ${{ steps.cache-key.outputs.cache-key }}
|
||||
@@ -1122,7 +1117,7 @@ jobs:
|
||||
|
||||
- name: Cache platformio
|
||||
if: steps.check-script.outputs.skip != 'true' && steps.check-tests.outputs.skip != 'true' && steps.cache-memory-analysis.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: platformio-memory-${{ fromJSON(needs.determine-jobs.outputs.memory_impact).platform }}-${{ hashFiles('platformio.ini') }}
|
||||
@@ -1164,7 +1159,7 @@ jobs:
|
||||
|
||||
- name: Save memory analysis to cache
|
||||
if: steps.check-script.outputs.skip != 'true' && steps.check-tests.outputs.skip != 'true' && steps.cache-memory-analysis.outputs.cache-hit != 'true' && steps.build.outcome == 'success'
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: memory-analysis-target.json
|
||||
key: ${{ steps.cache-key.outputs.cache-key }}
|
||||
@@ -1211,7 +1206,7 @@ jobs:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
cache-key: ${{ needs.common.outputs.cache-key }}
|
||||
- name: Cache platformio
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: platformio-memory-${{ fromJSON(needs.determine-jobs.outputs.memory_impact).platform }}-${{ hashFiles('platformio.ini') }}
|
||||
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Build
|
||||
@@ -94,9 +94,9 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.12"
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
path: lib/home-assistant
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: "3.14"
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ repos:
|
||||
rev: v3.21.2
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py312-plus]
|
||||
args: [--py311-plus]
|
||||
- repo: https://github.com/adrienverge/yamllint.git
|
||||
rev: v1.37.1
|
||||
hooks:
|
||||
|
||||
@@ -9,7 +9,7 @@ This document provides essential context for AI models interacting with this pro
|
||||
|
||||
## 2. Core Technologies & Stack
|
||||
|
||||
* **Languages:** Python (>=3.12), C++ (gnu++20)
|
||||
* **Languages:** Python (>=3.11), C++ (gnu++20)
|
||||
* **Frameworks & Runtimes:** PlatformIO, Arduino, ESP-IDF.
|
||||
* **Build Systems:** PlatformIO is the primary build system. CMake is used as an alternative.
|
||||
* **Configuration:** YAML.
|
||||
|
||||
@@ -266,7 +266,6 @@ esphome/components/integration/* @OttoWinter
|
||||
esphome/components/internal_temperature/* @Mat931
|
||||
esphome/components/interval/* @esphome/core
|
||||
esphome/components/ir_rf_proxy/* @kbx81
|
||||
esphome/components/it8951/* @koosoli @limengdu @Passific
|
||||
esphome/components/jsn_sr04t/* @Mafus1
|
||||
esphome/components/json/* @esphome/core
|
||||
esphome/components/kamstrup_kmp/* @cfeenstra1024
|
||||
@@ -579,7 +578,6 @@ esphome/components/wake_on_lan/* @clydebarrow @willwill2will54
|
||||
esphome/components/watchdog/* @oarcher
|
||||
esphome/components/water_heater/* @dhoeben
|
||||
esphome/components/waveshare_epaper/* @clydebarrow
|
||||
esphome/components/waveshare_io_ch32v003/* @latonita
|
||||
esphome/components/web_server/ota/* @esphome/core
|
||||
esphome/components/web_server_base/* @esphome/core
|
||||
esphome/components/web_server_idf/* @dentra
|
||||
|
||||
+12
-2
@@ -1,5 +1,5 @@
|
||||
ARG BUILD_VERSION=dev
|
||||
ARG BUILD_BASE_VERSION=2026.06.1
|
||||
ARG BUILD_BASE_VERSION=2026.06.0
|
||||
ARG BUILD_TYPE=docker
|
||||
|
||||
FROM ghcr.io/esphome/docker-base:debian-${BUILD_BASE_VERSION} AS base-source-docker
|
||||
@@ -11,6 +11,16 @@ FROM base-source-${BUILD_TYPE} AS base
|
||||
RUN git config --system --add safe.directory "*" \
|
||||
&& git config --system advice.detachedHead false
|
||||
|
||||
# Install build tools for Python packages that require compilation
|
||||
# (e.g., ruamel.yaml.clib used by ESP-IDF's idf-component-manager).
|
||||
# Also install libusb-1.0 at runtime so the ESP-IDF tools installer can
|
||||
# validate openocd-esp32 (it dynamically links libusb-1.0.so.0); without
|
||||
# it idf_tools.py rejects the openocd install with exit 127 and aborts
|
||||
# the whole framework setup.
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends build-essential libusb-1.0-0 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
|
||||
|
||||
RUN pip install --no-cache-dir -U pip uv==0.10.1
|
||||
@@ -22,7 +32,7 @@ RUN \
|
||||
-r /requirements.txt
|
||||
|
||||
# Install the ESPHome Device Builder dashboard.
|
||||
RUN uv pip install --no-cache-dir esphome-device-builder==1.0.21
|
||||
RUN uv pip install --no-cache-dir esphome-device-builder==1.0.14
|
||||
|
||||
RUN \
|
||||
platformio settings set enable_telemetry No \
|
||||
|
||||
+19
-28
@@ -52,6 +52,11 @@ from esphome.const import (
|
||||
CONF_WEB_SERVER,
|
||||
CONF_WIFI,
|
||||
ENV_NOGITIGNORE,
|
||||
KEY_CORE,
|
||||
KEY_TARGET_PLATFORM,
|
||||
PLATFORM_ESP32,
|
||||
PLATFORM_ESP8266,
|
||||
PLATFORM_RP2040,
|
||||
SECRETS_FILES,
|
||||
Toolchain,
|
||||
)
|
||||
@@ -354,7 +359,7 @@ def choose_upload_log_host(
|
||||
bootsel_permission_error = False
|
||||
if (
|
||||
purpose == Purpose.UPLOADING
|
||||
and CORE.is_rp2040
|
||||
and CORE.data.get(KEY_CORE, {}).get(KEY_TARGET_PLATFORM) == PLATFORM_RP2040
|
||||
and (picotool := _find_picotool()) is not None
|
||||
):
|
||||
bootsel = detect_rp2040_bootsel(picotool)
|
||||
@@ -401,7 +406,7 @@ def choose_upload_log_host(
|
||||
# Show helpful BOOTSEL instructions for RP2040 when no BOOTSEL device is found
|
||||
if (
|
||||
purpose == Purpose.UPLOADING
|
||||
and CORE.is_rp2040
|
||||
and CORE.data.get(KEY_CORE, {}).get(KEY_TARGET_PLATFORM) == PLATFORM_RP2040
|
||||
and not any(get_port_type(opt[1]) == PortType.BOOTSEL for opt in options)
|
||||
):
|
||||
if bootsel_permission_error:
|
||||
@@ -979,7 +984,7 @@ def upload_using_platformio(config: ConfigType, port: str) -> int:
|
||||
# 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.is_rp2040:
|
||||
if CORE.data.get(KEY_CORE, {}).get(KEY_TARGET_PLATFORM) == PLATFORM_RP2040:
|
||||
idedata = toolchain.get_idedata(config)
|
||||
build_dir = Path(idedata.firmware_elf_path).parent
|
||||
firmware_bin = build_dir / "firmware.bin"
|
||||
@@ -1164,10 +1169,10 @@ def upload_program(
|
||||
check_permissions(host)
|
||||
|
||||
exit_code = 1
|
||||
if CORE.is_esp32 or CORE.is_esp8266:
|
||||
if CORE.target_platform in (PLATFORM_ESP32, PLATFORM_ESP8266):
|
||||
file = getattr(args, "file", None)
|
||||
exit_code = upload_using_esptool(config, host, file, args.upload_speed)
|
||||
elif CORE.is_rp2040 or CORE.is_libretiny:
|
||||
elif CORE.target_platform == PLATFORM_RP2040 or CORE.is_libretiny:
|
||||
exit_code = upload_using_platformio(config, host)
|
||||
# else: Unknown target platform, exit_code remains 1
|
||||
|
||||
@@ -1488,29 +1493,12 @@ _LEGACY_REDACTION_REMOVAL = "2026.12.0"
|
||||
|
||||
def _redact_with_legacy_fallback(output: str) -> str:
|
||||
unmarked: set[str] = set()
|
||||
# Track the top-level ``substitutions:`` block. Its keys are arbitrary
|
||||
# user-chosen names with no schema validator, so the ``cv.sensitive(...)``
|
||||
# migration named in the warning can't be applied to them. Their values are
|
||||
# still redacted, but emitting the (unactionable) deprecation warning would
|
||||
# only confuse users.
|
||||
in_substitutions = False
|
||||
|
||||
lines = output.split("\n")
|
||||
for i, line in enumerate(lines):
|
||||
# A non-indented, non-blank line is a top-level key that opens or
|
||||
# closes the substitutions block.
|
||||
if line and not line[0].isspace():
|
||||
in_substitutions = line.startswith(f"{CONF_SUBSTITUTIONS}:")
|
||||
m = _LEGACY_REDACTION_RE.search(line)
|
||||
if m is None:
|
||||
continue
|
||||
if not in_substitutions:
|
||||
unmarked.add(m.group("key"))
|
||||
lines[i] = (
|
||||
f"{line[: m.start()]}{m.group('key')}: "
|
||||
f"\\033[8m{m.group('val')}\\033[28m{line[m.end() :]}"
|
||||
)
|
||||
output = "\n".join(lines)
|
||||
def _replace(m: re.Match[str]) -> str:
|
||||
unmarked.add(m.group("key"))
|
||||
return f"{m.group('key')}: \\033[8m{m.group('val')}\\033[28m"
|
||||
|
||||
output = _LEGACY_REDACTION_RE.sub(_replace, output)
|
||||
for key in sorted(unmarked):
|
||||
_LOGGER.warning(
|
||||
"Field '%s' is being redacted by a legacy substring heuristic. "
|
||||
@@ -1641,7 +1629,10 @@ def command_run(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
|
||||
# After BOOTSEL upload, wait for a new serial port to appear
|
||||
# so it shows up in the log chooser
|
||||
if successful_device is None and CORE.is_rp2040:
|
||||
if (
|
||||
successful_device is None
|
||||
and CORE.data.get(KEY_CORE, {}).get(KEY_TARGET_PLATFORM) == PLATFORM_RP2040
|
||||
):
|
||||
_wait_for_serial_port(known_ports=pre_upload_ports)
|
||||
# If exactly one new serial port appeared, use it directly
|
||||
serial_ports = get_serial_ports()
|
||||
|
||||
@@ -12,9 +12,12 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
from collections.abc import Awaitable, Callable
|
||||
import threading
|
||||
from typing import Generic, TypeVar
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
class AsyncThreadRunner[T](threading.Thread):
|
||||
class AsyncThreadRunner(threading.Thread, Generic[_T]):
|
||||
"""Run an async coroutine in a daemon thread and expose its result.
|
||||
|
||||
The runner catches all exceptions from the coroutine and stores them in
|
||||
@@ -32,10 +35,10 @@ class AsyncThreadRunner[T](threading.Thread):
|
||||
result = runner.result
|
||||
"""
|
||||
|
||||
def __init__(self, coro_factory: Callable[[], Awaitable[T]]) -> None:
|
||||
def __init__(self, coro_factory: Callable[[], Awaitable[_T]]) -> None:
|
||||
super().__init__(daemon=True)
|
||||
self._coro_factory = coro_factory
|
||||
self.result: T | None = None
|
||||
self.result: _T | None = None
|
||||
self.exception: BaseException | None = None
|
||||
self.event = threading.Event()
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ void A01nyubComponent::check_buffer_() {
|
||||
if (this->buffer_[3] == checksum) {
|
||||
float distance = (this->buffer_[1] << 8) + this->buffer_[2];
|
||||
if (distance > 280) {
|
||||
float meters = distance / 1000.0f;
|
||||
float meters = distance / 1000.0;
|
||||
ESP_LOGV(TAG, "Distance from sensor: %f mm, %f m", distance, meters);
|
||||
this->publish_state(meters);
|
||||
} else {
|
||||
|
||||
@@ -216,7 +216,7 @@ void AcDimmer::setup() {
|
||||
}
|
||||
|
||||
void AcDimmer::write_state(float state) {
|
||||
state = std::acos(1 - (2 * state)) / std::numbers::pi_v<float>; // RMS power compensation
|
||||
state = std::acos(1 - (2 * state)) / std::numbers::pi; // RMS power compensation
|
||||
auto new_value = static_cast<uint16_t>(roundf(state * 65535));
|
||||
if (new_value != 0 && this->store_.value == 0)
|
||||
this->store_.init_cycle = this->init_with_half_cycle_;
|
||||
|
||||
@@ -66,18 +66,15 @@ float ADCSensor::sample() {
|
||||
}
|
||||
|
||||
uint8_t pin = this->pin_->get_pin();
|
||||
#if defined(CYW43_USES_VSYS_PIN) && defined(USE_WIFI)
|
||||
#ifdef CYW43_USES_VSYS_PIN
|
||||
if (pin == PICO_VSYS_PIN) {
|
||||
// Measuring VSYS on Raspberry Pico W needs to be wrapped with
|
||||
// `cyw43_thread_enter()`/`cyw43_thread_exit()` as discussed in
|
||||
// https://github.com/raspberrypi/pico-sdk/issues/1222, since Wifi chip and
|
||||
// VSYS ADC both share GPIO29.
|
||||
// The USE_WIFI guard is required because CYW43_USES_VSYS_PIN can be defined
|
||||
// transitively (e.g. via lwip_wrap.h) even on non-WiFi boards where the CYW43
|
||||
// driver is never initialized; calling cyw43_thread_enter() there hard-faults.
|
||||
// VSYS ADC both share GPIO29
|
||||
cyw43_thread_enter();
|
||||
}
|
||||
#endif // defined(CYW43_USES_VSYS_PIN) && defined(USE_WIFI)
|
||||
#endif // CYW43_USES_VSYS_PIN
|
||||
|
||||
adc_gpio_init(pin);
|
||||
adc_select_input(pin - 26);
|
||||
@@ -87,11 +84,11 @@ float ADCSensor::sample() {
|
||||
aggr.add_sample(raw);
|
||||
}
|
||||
|
||||
#if defined(CYW43_USES_VSYS_PIN) && defined(USE_WIFI)
|
||||
#ifdef CYW43_USES_VSYS_PIN
|
||||
if (pin == PICO_VSYS_PIN) {
|
||||
cyw43_thread_exit();
|
||||
}
|
||||
#endif // defined(CYW43_USES_VSYS_PIN) && defined(USE_WIFI)
|
||||
#endif // CYW43_USES_VSYS_PIN
|
||||
|
||||
if (this->output_raw_) {
|
||||
return aggr.aggregate();
|
||||
|
||||
@@ -114,13 +114,13 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
|
||||
this->decoder_->decode(param->notify.value, param->notify.value_len);
|
||||
|
||||
if (this->decoder_->has_position()) {
|
||||
this->position = ((float) this->decoder_->position_ / 100.0f);
|
||||
this->position = ((float) this->decoder_->position_ / 100.0);
|
||||
if (!this->invert_position_)
|
||||
this->position = 1 - this->position;
|
||||
if (this->position > 0.97f)
|
||||
this->position = 1.0f;
|
||||
if (this->position < 0.02f)
|
||||
this->position = 0.0f;
|
||||
if (this->position > 0.97)
|
||||
this->position = 1.0;
|
||||
if (this->position < 0.02)
|
||||
this->position = 0.0;
|
||||
this->publish_state();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
|
||||
namespace esphome::anova {
|
||||
|
||||
float ftoc(float f) { return (f - 32.0f) * (5.0f / 9.0f); }
|
||||
float ftoc(float f) { return (f - 32.0) * (5.0f / 9.0f); }
|
||||
|
||||
float ctof(float c) { return (c * 9.0f / 5.0f) + 32.0f; }
|
||||
float ctof(float c) { return (c * 9.0f / 5.0f) + 32.0; }
|
||||
|
||||
AnovaPacket *AnovaCodec::clean_packet_() {
|
||||
this->packet_.length = strlen((char *) this->packet_.data);
|
||||
|
||||
@@ -305,7 +305,6 @@ CONFIG_SCHEMA = cv.All(
|
||||
rtl87xx=4, # Moderate RAM, BSD-style sockets
|
||||
host=4, # Abundant resources
|
||||
ln882x=4, # Moderate RAM
|
||||
nrf52=4, # ~256KB RAM, BSD sockets
|
||||
): cv.int_range(min=1, max=10),
|
||||
cv.SplitDefault(
|
||||
CONF_MAX_CONNECTIONS,
|
||||
@@ -316,7 +315,6 @@ CONFIG_SCHEMA = cv.All(
|
||||
rtl87xx=5, # Moderate RAM
|
||||
host=8, # Abundant resources
|
||||
ln882x=5, # Moderate RAM
|
||||
nrf52=4, # ~256KB RAM, BSD sockets, Thread (single HA controller)
|
||||
): cv.int_range(min=1, max=20),
|
||||
# Maximum queued send buffers per connection before dropping connection
|
||||
# Each buffer uses ~8-12 bytes overhead plus actual message size
|
||||
|
||||
@@ -31,13 +31,6 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#if defined(LOG_LEVEL_NONE)
|
||||
// Zephyr defines LOG_LEVEL_NONE as a logging macro that collides with the LogLevel enum value of
|
||||
// the same name in the generated api_pb2.h. Undefine it for the rest of this translation unit so
|
||||
// the enum parses; nothing below needs Zephyr's logging macro.
|
||||
#undef LOG_LEVEL_NONE
|
||||
#endif
|
||||
|
||||
namespace esphome::api {
|
||||
|
||||
// This file only provides includes, no actual code
|
||||
|
||||
@@ -395,7 +395,7 @@ async def to_code(config):
|
||||
)
|
||||
if data.mp3_support:
|
||||
cg.add_define("USE_AUDIO_MP3_SUPPORT")
|
||||
add_idf_component(name="esphome/micro-mp3", ref="0.4.0")
|
||||
add_idf_component(name="esphome/micro-mp3", ref="0.3.0")
|
||||
_emit_memory_pair(
|
||||
data.mp3.buffer_memory,
|
||||
"CONFIG_MICRO_MP3_PREFER_PSRAM",
|
||||
|
||||
@@ -112,7 +112,7 @@ float BinarySensorMap::bayesian_predicate_(bool sensor_state, float prior, float
|
||||
prob_state_source_false = 1 - prob_given_false;
|
||||
}
|
||||
|
||||
return prob_state_source_true / (prior * prob_state_source_true + (1.0f - prior) * prob_state_source_false);
|
||||
return prob_state_source_true / (prior * prob_state_source_true + (1.0 - prior) * prob_state_source_false);
|
||||
}
|
||||
|
||||
void BinarySensorMap::add_channel(binary_sensor::BinarySensor *sensor, float value) {
|
||||
|
||||
@@ -205,7 +205,7 @@ void BL0906::read_data_(const uint8_t address, const float reference, sensor::Se
|
||||
// Chip temperature
|
||||
if (reference == BL0906_TREF) {
|
||||
value = (float) to_int32_t(data_s24);
|
||||
value = (value - 64) * 12.5f / 59 - 40;
|
||||
value = (value - 64) * 12.5 / 59 - 40;
|
||||
}
|
||||
sensor->publish_state(value);
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ float BL0940::calculate_power_reference_() {
|
||||
float BL0940::calculate_energy_reference_() {
|
||||
// formula: 3600000 * 4046 * RL * R1 * 1000 / (1638.4 * 256) / Vref² / (R1 + R2)
|
||||
// or: power_reference_ * 3600000 / (1638.4 * 256)
|
||||
return this->power_reference_cal_ * 3600000 / (1638.4f * 256);
|
||||
return this->power_reference_cal_ * 3600000 / (1638.4 * 256);
|
||||
}
|
||||
|
||||
float BL0940::calculate_calibration_value_(float state) { return (100 + state) / 100; }
|
||||
|
||||
@@ -211,17 +211,6 @@ CONFIG_SCHEMA = (
|
||||
.add_extra(set_reference_values)
|
||||
)
|
||||
|
||||
# BL0940 datasheet: 4800 baud, 8 data bits, no parity (stop bits are 1.5 -- not
|
||||
# representable in the uart schema, so it isn't asserted).
|
||||
FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
|
||||
"bl0940",
|
||||
baud_rate=4800,
|
||||
data_bits=8,
|
||||
parity="NONE",
|
||||
require_rx=True,
|
||||
require_tx=True,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
|
||||
@@ -124,14 +124,14 @@ void BL0942::setup() {
|
||||
// If either current or voltage references are set explicitly by the user,
|
||||
// calculate the power reference from it unless that is also explicitly set.
|
||||
if ((this->current_reference_set_ || this->voltage_reference_set_) && !this->power_reference_set_) {
|
||||
this->power_reference_ = (this->voltage_reference_ * this->current_reference_ * 3537.0f / 305978.0f) / 73989.0f;
|
||||
this->power_reference_ = (this->voltage_reference_ * this->current_reference_ * 3537.0 / 305978.0) / 73989.0;
|
||||
this->power_reference_set_ = true;
|
||||
}
|
||||
|
||||
// Similarly for energy reference, if the power reference was set by the user
|
||||
// either implicitly or explicitly.
|
||||
if (this->power_reference_set_ && !this->energy_reference_set_) {
|
||||
this->energy_reference_ = this->power_reference_ * 3600000 / 419430.4f;
|
||||
this->energy_reference_ = this->power_reference_ * 3600000 / 419430.4;
|
||||
this->energy_reference_set_ = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import esp32, i2c
|
||||
from esphome.components.const import CONF_STATE_SAVE_INTERVAL
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, CONF_SAMPLE_RATE, CONF_TEMPERATURE_OFFSET, Framework
|
||||
|
||||
@@ -13,6 +12,7 @@ MULTI_CONF = True
|
||||
CONF_BME680_BSEC_ID = "bme680_bsec_id"
|
||||
CONF_IAQ_MODE = "iaq_mode"
|
||||
CONF_SUPPLY_VOLTAGE = "supply_voltage"
|
||||
CONF_STATE_SAVE_INTERVAL = "state_save_interval"
|
||||
|
||||
bme680_bsec_ns = cg.esphome_ns.namespace("bme680_bsec")
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import sensor
|
||||
from esphome.components.const import (
|
||||
CONF_BREATH_VOC_EQUIVALENT,
|
||||
CONF_CO2_EQUIVALENT,
|
||||
CONF_IAQ,
|
||||
)
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_GAS_RESISTANCE,
|
||||
@@ -34,6 +29,9 @@ from . import CONF_BME680_BSEC_ID, SAMPLE_RATE_OPTIONS, BME680BSECComponent
|
||||
|
||||
DEPENDENCIES = ["bme680_bsec"]
|
||||
|
||||
CONF_BREATH_VOC_EQUIVALENT = "breath_voc_equivalent"
|
||||
CONF_CO2_EQUIVALENT = "co2_equivalent"
|
||||
CONF_IAQ = "iaq"
|
||||
ICON_ACCURACY = "mdi:checkbox-marked-circle-outline"
|
||||
UNIT_IAQ = "IAQ"
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ from pathlib import Path
|
||||
|
||||
from esphome import core, external_files
|
||||
import esphome.codegen as cg
|
||||
from esphome.components.const import CONF_STATE_SAVE_INTERVAL
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
@@ -25,6 +24,7 @@ CONF_ALGORITHM_OUTPUT = "algorithm_output"
|
||||
CONF_BME68X_BSEC2_ID = "bme68x_bsec2_id"
|
||||
CONF_IAQ_MODE = "iaq_mode"
|
||||
CONF_OPERATING_AGE = "operating_age"
|
||||
CONF_STATE_SAVE_INTERVAL = "state_save_interval"
|
||||
CONF_SUPPLY_VOLTAGE = "supply_voltage"
|
||||
|
||||
bme68x_bsec2_ns = cg.esphome_ns.namespace("bme68x_bsec2")
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import sensor
|
||||
from esphome.components.const import (
|
||||
CONF_BREATH_VOC_EQUIVALENT,
|
||||
CONF_CO2_EQUIVALENT,
|
||||
CONF_IAQ,
|
||||
)
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_GAS_RESISTANCE,
|
||||
@@ -34,6 +29,9 @@ from . import CONF_BME68X_BSEC2_ID, SAMPLE_RATE_OPTIONS, BME68xBSEC2Component
|
||||
|
||||
DEPENDENCIES = ["bme68x_bsec2"]
|
||||
|
||||
CONF_BREATH_VOC_EQUIVALENT = "breath_voc_equivalent"
|
||||
CONF_CO2_EQUIVALENT = "co2_equivalent"
|
||||
CONF_IAQ = "iaq"
|
||||
CONF_IAQ_STATIC = "iaq_static"
|
||||
ICON_ACCURACY = "mdi:checkbox-marked-circle-outline"
|
||||
UNIT_IAQ = "IAQ"
|
||||
|
||||
@@ -204,7 +204,7 @@ void MedianCombinationComponent::handle_new_value(float value) {
|
||||
median = sensor_states[sensor_states_size / 2];
|
||||
} else {
|
||||
// Even number of measurements, use the average of the two middle measurements
|
||||
median = (sensor_states[sensor_states_size / 2] + sensor_states[sensor_states_size / 2 - 1]) / 2.0f;
|
||||
median = (sensor_states[sensor_states_size / 2] + sensor_states[sensor_states_size / 2 - 1]) / 2.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,8 @@ BYTE_ORDER_BIG = "big_endian"
|
||||
CONF_ACCELEROMETER_ODR = "accelerometer_odr"
|
||||
CONF_ACCELEROMETER_RANGE = "accelerometer_range"
|
||||
CONF_B_CONSTANT = "b_constant"
|
||||
CONF_BREATH_VOC_EQUIVALENT = "breath_voc_equivalent"
|
||||
CONF_BYTE_ORDER = "byte_order"
|
||||
CONF_CLIMATE_ID = "climate_id"
|
||||
CONF_CO2_EQUIVALENT = "co2_equivalent"
|
||||
CONF_COLOR_DEPTH = "color_depth"
|
||||
CONF_CRC_ENABLE = "crc_enable"
|
||||
CONF_DATA_BITS = "data_bits"
|
||||
@@ -19,7 +17,6 @@ CONF_DRAW_ROUNDING = "draw_rounding"
|
||||
CONF_ENABLED = "enabled"
|
||||
CONF_GYROSCOPE_ODR = "gyroscope_odr"
|
||||
CONF_GYROSCOPE_RANGE = "gyroscope_range"
|
||||
CONF_IAQ = "iaq"
|
||||
CONF_IGNORE_NOT_FOUND = "ignore_not_found"
|
||||
CONF_LIBRETINY = "libretiny"
|
||||
CONF_LOOP = "loop"
|
||||
@@ -31,7 +28,6 @@ CONF_RECEIVER_FREQUENCY = "receiver_frequency"
|
||||
CONF_REQUEST_HEADERS = "request_headers"
|
||||
CONF_ROWS = "rows"
|
||||
CONF_SHA256 = "sha256"
|
||||
CONF_STATE_SAVE_INTERVAL = "state_save_interval"
|
||||
CONF_STOP_BITS = "stop_bits"
|
||||
CONF_USE_PSRAM = "use_psram"
|
||||
CONF_VOLUME_INCREMENT = "volume_increment"
|
||||
|
||||
@@ -39,7 +39,7 @@ void CurrentBasedCover::control(const CoverCall &call) {
|
||||
auto opt_pos = call.get_position();
|
||||
if (opt_pos.has_value()) {
|
||||
auto pos = *opt_pos;
|
||||
if (fabsf(this->position - pos) < 0.01f) {
|
||||
if (fabsf(this->position - pos) < 0.01) {
|
||||
// already at target
|
||||
} else {
|
||||
auto op = pos < this->position ? COVER_OPERATION_CLOSING : COVER_OPERATION_OPENING;
|
||||
|
||||
@@ -151,7 +151,7 @@ uint8_t DaikinBrcClimate::temperature_() {
|
||||
// Temperature in remote is in F
|
||||
if (this->fahrenheit_) {
|
||||
temperature = (uint8_t) roundf(
|
||||
clamp<float>(((this->target_temperature * 1.8f) + 32), DAIKIN_BRC_TEMP_MIN_F, DAIKIN_BRC_TEMP_MAX_F));
|
||||
clamp<float>(((this->target_temperature * 1.8) + 32), DAIKIN_BRC_TEMP_MIN_F, DAIKIN_BRC_TEMP_MAX_F));
|
||||
} else {
|
||||
temperature = ((uint8_t) roundf(this->target_temperature) - 9) << 1;
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ float DallasTemperatureSensor::get_temp_c_() {
|
||||
if (this->scratch_pad_[7] == 0) {
|
||||
return NAN;
|
||||
}
|
||||
return (temp >> 1) + (this->scratch_pad_[7] - this->scratch_pad_[6]) / float(this->scratch_pad_[7]) - 0.25f;
|
||||
return (temp >> 1) + (this->scratch_pad_[7] - this->scratch_pad_[6]) / float(this->scratch_pad_[7]) - 0.25;
|
||||
}
|
||||
switch (this->resolution_) {
|
||||
case 9:
|
||||
|
||||
@@ -96,8 +96,7 @@ class DeepSleepComponent final : public Component {
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3) && \
|
||||
!defined(USE_ESP32_VARIANT_ESP32C5) && !defined(USE_ESP32_VARIANT_ESP32C6) && \
|
||||
!defined(USE_ESP32_VARIANT_ESP32C61) && !defined(USE_ESP32_VARIANT_ESP32H2)
|
||||
!defined(USE_ESP32_VARIANT_ESP32C6) && !defined(USE_ESP32_VARIANT_ESP32C61) && !defined(USE_ESP32_VARIANT_ESP32H2)
|
||||
void set_touch_wakeup(bool touch_wakeup);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace esphome::deep_sleep {
|
||||
// | ESP32-S3 | ✓ | ✓ | ✓ | |
|
||||
// | ESP32-C2 | | | | ✓ |
|
||||
// | ESP32-C3 | | | | ✓ |
|
||||
// | ESP32-C5 | | ✓ | | ✓ |
|
||||
// | ESP32-C5 | | (✓) | | (✓) |
|
||||
// | ESP32-C6 | | ✓ | | ✓ |
|
||||
// | ESP32-C61 | | ✓ | | ✓ |
|
||||
// | ESP32-H2 | | ✓ | | |
|
||||
@@ -56,8 +56,7 @@ void DeepSleepComponent::set_ext1_wakeup(Ext1Wakeup ext1_wakeup) { this->ext1_wa
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3) && \
|
||||
!defined(USE_ESP32_VARIANT_ESP32C5) && !defined(USE_ESP32_VARIANT_ESP32C6) && \
|
||||
!defined(USE_ESP32_VARIANT_ESP32C61) && !defined(USE_ESP32_VARIANT_ESP32H2)
|
||||
!defined(USE_ESP32_VARIANT_ESP32C6) && !defined(USE_ESP32_VARIANT_ESP32C61) && !defined(USE_ESP32_VARIANT_ESP32H2)
|
||||
void DeepSleepComponent::set_touch_wakeup(bool touch_wakeup) { this->touch_wakeup_ = touch_wakeup; }
|
||||
#endif
|
||||
|
||||
@@ -100,8 +99,7 @@ void DeepSleepComponent::deep_sleep_() {
|
||||
|
||||
// Single pin wakeup (ext0) - ESP32, S2, S3 only
|
||||
#if !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3) && \
|
||||
!defined(USE_ESP32_VARIANT_ESP32C5) && !defined(USE_ESP32_VARIANT_ESP32C6) && \
|
||||
!defined(USE_ESP32_VARIANT_ESP32C61) && !defined(USE_ESP32_VARIANT_ESP32H2)
|
||||
!defined(USE_ESP32_VARIANT_ESP32C6) && !defined(USE_ESP32_VARIANT_ESP32H2)
|
||||
if (this->wakeup_pin_ != nullptr) {
|
||||
const auto gpio_pin = gpio_num_t(this->wakeup_pin_->get_pin());
|
||||
if (this->wakeup_pin_->get_flags() & gpio::FLAG_PULLUP) {
|
||||
@@ -124,9 +122,9 @@ void DeepSleepComponent::deep_sleep_() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// GPIO wakeup - C2, C3, C5, C6, C61 only
|
||||
#if defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C5) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32C61)
|
||||
// GPIO wakeup - C2, C3, C6, C61 only
|
||||
#if defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \
|
||||
defined(USE_ESP32_VARIANT_ESP32C61)
|
||||
if (this->wakeup_pin_ != nullptr) {
|
||||
const auto gpio_pin = gpio_num_t(this->wakeup_pin_->get_pin());
|
||||
// Make sure GPIO is in input mode, not all RTC GPIO pins are input by default
|
||||
@@ -156,8 +154,7 @@ void DeepSleepComponent::deep_sleep_() {
|
||||
|
||||
// Touch wakeup - ESP32, S2, S3 only
|
||||
#if !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3) && \
|
||||
!defined(USE_ESP32_VARIANT_ESP32C5) && !defined(USE_ESP32_VARIANT_ESP32C6) && \
|
||||
!defined(USE_ESP32_VARIANT_ESP32C61) && !defined(USE_ESP32_VARIANT_ESP32H2)
|
||||
!defined(USE_ESP32_VARIANT_ESP32C6) && !defined(USE_ESP32_VARIANT_ESP32C61) && !defined(USE_ESP32_VARIANT_ESP32H2)
|
||||
if (this->touch_wakeup_.has_value() && *(this->touch_wakeup_)) {
|
||||
esp_sleep_enable_touchpad_wakeup();
|
||||
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||
|
||||
@@ -15,7 +15,7 @@ class DemoSensor final : public sensor::Sensor, public PollingComponent {
|
||||
float base = std::isnan(this->state) ? 0.0f : this->state;
|
||||
this->publish_state(base + val * 10);
|
||||
} else {
|
||||
if (val < 0.1f) {
|
||||
if (val < 0.1) {
|
||||
this->publish_state(NAN);
|
||||
} else {
|
||||
this->publish_state(val * 100);
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace esphome::demo {
|
||||
class DemoSwitch final : public switch_::Switch, public Component {
|
||||
public:
|
||||
void setup() override {
|
||||
bool initial = random_float() < 0.5f;
|
||||
bool initial = random_float() < 0.5;
|
||||
this->publish_state(initial);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,9 @@ class DemoTextSensor final : public text_sensor::TextSensor, public PollingCompo
|
||||
public:
|
||||
void update() override {
|
||||
float val = random_float();
|
||||
if (val < 0.33f) {
|
||||
if (val < 0.33) {
|
||||
this->publish_state("foo");
|
||||
} else if (val < 0.66f) {
|
||||
} else if (val < 0.66) {
|
||||
this->publish_state("bar");
|
||||
} else {
|
||||
this->publish_state("foobar");
|
||||
|
||||
@@ -121,51 +121,51 @@ DetRangeCfgCommand::DetRangeCfgCommand(float min1, float max1, float min2, float
|
||||
|
||||
this->cmd_ = "detRangeCfg -1 0 0";
|
||||
} else if (min2 < 0 || max2 < 0) {
|
||||
this->min1_ = min1 = roundf(min1 / 0.15f) * 0.15f;
|
||||
this->max1_ = max1 = roundf(max1 / 0.15f) * 0.15f;
|
||||
this->min1_ = min1 = round(min1 / 0.15) * 0.15;
|
||||
this->max1_ = max1 = round(max1 / 0.15) * 0.15;
|
||||
this->min2_ = min2 = this->max2_ = max2 = this->min3_ = min3 = this->max3_ = max3 = this->min4_ = min4 =
|
||||
this->max4_ = max4 = -1;
|
||||
|
||||
char buf[72]; // max 72: "detRangeCfg -1 "(15) + 8 * (float(5) + space(1)) + null
|
||||
snprintf(buf, sizeof(buf), "detRangeCfg -1 %.0f %.0f", min1 / 0.15f, max1 / 0.15f);
|
||||
snprintf(buf, sizeof(buf), "detRangeCfg -1 %.0f %.0f", min1 / 0.15, max1 / 0.15);
|
||||
this->cmd_ = buf;
|
||||
} else if (min3 < 0 || max3 < 0) {
|
||||
this->min1_ = min1 = roundf(min1 / 0.15f) * 0.15f;
|
||||
this->max1_ = max1 = roundf(max1 / 0.15f) * 0.15f;
|
||||
this->min2_ = min2 = roundf(min2 / 0.15f) * 0.15f;
|
||||
this->max2_ = max2 = roundf(max2 / 0.15f) * 0.15f;
|
||||
this->min1_ = min1 = round(min1 / 0.15) * 0.15;
|
||||
this->max1_ = max1 = round(max1 / 0.15) * 0.15;
|
||||
this->min2_ = min2 = round(min2 / 0.15) * 0.15;
|
||||
this->max2_ = max2 = round(max2 / 0.15) * 0.15;
|
||||
this->min3_ = min3 = this->max3_ = max3 = this->min4_ = min4 = this->max4_ = max4 = -1;
|
||||
|
||||
char buf[72]; // max 72: "detRangeCfg -1 "(15) + 8 * (float(5) + space(1)) + null
|
||||
snprintf(buf, sizeof(buf), "detRangeCfg -1 %.0f %.0f %.0f %.0f", min1 / 0.15f, max1 / 0.15f, min2 / 0.15f,
|
||||
max2 / 0.15f);
|
||||
snprintf(buf, sizeof(buf), "detRangeCfg -1 %.0f %.0f %.0f %.0f", min1 / 0.15, max1 / 0.15, min2 / 0.15,
|
||||
max2 / 0.15);
|
||||
this->cmd_ = buf;
|
||||
} else if (min4 < 0 || max4 < 0) {
|
||||
this->min1_ = min1 = roundf(min1 / 0.15f) * 0.15f;
|
||||
this->max1_ = max1 = roundf(max1 / 0.15f) * 0.15f;
|
||||
this->min2_ = min2 = roundf(min2 / 0.15f) * 0.15f;
|
||||
this->max2_ = max2 = roundf(max2 / 0.15f) * 0.15f;
|
||||
this->min3_ = min3 = roundf(min3 / 0.15f) * 0.15f;
|
||||
this->max3_ = max3 = roundf(max3 / 0.15f) * 0.15f;
|
||||
this->min1_ = min1 = round(min1 / 0.15) * 0.15;
|
||||
this->max1_ = max1 = round(max1 / 0.15) * 0.15;
|
||||
this->min2_ = min2 = round(min2 / 0.15) * 0.15;
|
||||
this->max2_ = max2 = round(max2 / 0.15) * 0.15;
|
||||
this->min3_ = min3 = round(min3 / 0.15) * 0.15;
|
||||
this->max3_ = max3 = round(max3 / 0.15) * 0.15;
|
||||
this->min4_ = min4 = this->max4_ = max4 = -1;
|
||||
|
||||
char buf[72]; // max 72: "detRangeCfg -1 "(15) + 8 * (float(5) + space(1)) + null
|
||||
snprintf(buf, sizeof(buf), "detRangeCfg -1 %.0f %.0f %.0f %.0f %.0f %.0f", min1 / 0.15f, max1 / 0.15f, min2 / 0.15f,
|
||||
max2 / 0.15f, min3 / 0.15f, max3 / 0.15f);
|
||||
snprintf(buf, sizeof(buf), "detRangeCfg -1 %.0f %.0f %.0f %.0f %.0f %.0f", min1 / 0.15, max1 / 0.15, min2 / 0.15,
|
||||
max2 / 0.15, min3 / 0.15, max3 / 0.15);
|
||||
this->cmd_ = buf;
|
||||
} else {
|
||||
this->min1_ = min1 = roundf(min1 / 0.15f) * 0.15f;
|
||||
this->max1_ = max1 = roundf(max1 / 0.15f) * 0.15f;
|
||||
this->min2_ = min2 = roundf(min2 / 0.15f) * 0.15f;
|
||||
this->max2_ = max2 = roundf(max2 / 0.15f) * 0.15f;
|
||||
this->min3_ = min3 = roundf(min3 / 0.15f) * 0.15f;
|
||||
this->max3_ = max3 = roundf(max3 / 0.15f) * 0.15f;
|
||||
this->min4_ = min4 = roundf(min4 / 0.15f) * 0.15f;
|
||||
this->max4_ = max4 = roundf(max4 / 0.15f) * 0.15f;
|
||||
this->min1_ = min1 = round(min1 / 0.15) * 0.15;
|
||||
this->max1_ = max1 = round(max1 / 0.15) * 0.15;
|
||||
this->min2_ = min2 = round(min2 / 0.15) * 0.15;
|
||||
this->max2_ = max2 = round(max2 / 0.15) * 0.15;
|
||||
this->min3_ = min3 = round(min3 / 0.15) * 0.15;
|
||||
this->max3_ = max3 = round(max3 / 0.15) * 0.15;
|
||||
this->min4_ = min4 = round(min4 / 0.15) * 0.15;
|
||||
this->max4_ = max4 = round(max4 / 0.15) * 0.15;
|
||||
|
||||
char buf[72]; // max 72: "detRangeCfg -1 "(15) + 8 * (float(5) + space(1)) + null
|
||||
snprintf(buf, sizeof(buf), "detRangeCfg -1 %.0f %.0f %.0f %.0f %.0f %.0f %.0f %.0f", min1 / 0.15f, max1 / 0.15f,
|
||||
min2 / 0.15f, max2 / 0.15f, min3 / 0.15f, max3 / 0.15f, min4 / 0.15f, max4 / 0.15f);
|
||||
snprintf(buf, sizeof(buf), "detRangeCfg -1 %.0f %.0f %.0f %.0f %.0f %.0f %.0f %.0f", min1 / 0.15, max1 / 0.15,
|
||||
min2 / 0.15, max2 / 0.15, min3 / 0.15, max3 / 0.15, min4 / 0.15, max4 / 0.15);
|
||||
this->cmd_ = buf;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,10 +42,10 @@ void Display::line_at_angle(int x, int y, int angle, int length, Color color) {
|
||||
|
||||
void Display::line_at_angle(int x, int y, int angle, int start_radius, int stop_radius, Color color) {
|
||||
// Calculate start and end points
|
||||
int x1 = (start_radius * std::cos(angle * std::numbers::pi_v<float> / 180)) + x;
|
||||
int y1 = (start_radius * std::sin(angle * std::numbers::pi_v<float> / 180)) + y;
|
||||
int x2 = (stop_radius * std::cos(angle * std::numbers::pi_v<float> / 180)) + x;
|
||||
int y2 = (stop_radius * std::sin(angle * std::numbers::pi_v<float> / 180)) + y;
|
||||
int x1 = (start_radius * cos(angle * M_PI / 180)) + x;
|
||||
int y1 = (start_radius * sin(angle * M_PI / 180)) + y;
|
||||
int x2 = (stop_radius * cos(angle * M_PI / 180)) + x;
|
||||
int y2 = (stop_radius * sin(angle * M_PI / 180)) + y;
|
||||
|
||||
// Draw line
|
||||
this->line(x1, y1, x2, y2, color);
|
||||
@@ -228,7 +228,7 @@ void Display::filled_gauge(int center_x, int center_y, int radius1, int radius2,
|
||||
int e2max, e2min;
|
||||
progress = std::max(0, std::min(progress, 100)); // 0..100
|
||||
int draw_progress = progress > 50 ? (100 - progress) : progress;
|
||||
float tan_a = (progress == 50) ? 65535 : tanf(float(draw_progress) * std::numbers::pi_v<float> / 100); // slope
|
||||
float tan_a = (progress == 50) ? 65535 : tan(float(draw_progress) * M_PI / 100); // slope
|
||||
|
||||
do {
|
||||
// outer dots
|
||||
@@ -444,15 +444,15 @@ void HOT Display::get_regular_polygon_vertex(int vertex_id, int *vertex_x, int *
|
||||
// hence we rotate the shape by 270° to orient the polygon up.
|
||||
rotation_degrees += ROTATION_270_DEGREES;
|
||||
// Convert the rotation to radians, easier to use in trigonometrical calculations
|
||||
float rotation_radians = rotation_degrees * std::numbers::pi_v<float> / 180;
|
||||
float rotation_radians = rotation_degrees * std::numbers::pi / 180;
|
||||
// A pointy top variation means the first vertex of the polygon is at the top center of the shape, this requires no
|
||||
// additional rotation of the shape.
|
||||
// A flat top variation means the first point of the polygon has to be rotated so that the first edge is horizontal,
|
||||
// this requires to rotate the shape by π/edges radians counter-clockwise so that the first point is located on the
|
||||
// left side of the first horizontal edge.
|
||||
rotation_radians -= (variation == VARIATION_FLAT_TOP) ? std::numbers::pi_v<float> / edges : 0.0f;
|
||||
rotation_radians -= (variation == VARIATION_FLAT_TOP) ? std::numbers::pi / edges : 0.0;
|
||||
|
||||
float vertex_angle = ((float) vertex_id) / edges * 2 * std::numbers::pi_v<float> + rotation_radians;
|
||||
float vertex_angle = ((float) vertex_id) / edges * 2 * std::numbers::pi + rotation_radians;
|
||||
*vertex_x = (int) std::round(std::cos(vertex_angle) * radius) + center_x;
|
||||
*vertex_y = (int) std::round(std::sin(vertex_angle) * radius) + center_y;
|
||||
}
|
||||
|
||||
@@ -136,8 +136,12 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(DlmsMeterComponent),
|
||||
cv.Optional(CONF_DECRYPTION_KEY): cv.bind_key(name="Decryption key"),
|
||||
cv.Optional(CONF_AUTH_KEY): cv.bind_key(name="Authentication key"),
|
||||
cv.Optional(CONF_DECRYPTION_KEY): lambda value: cv.bind_key(
|
||||
value, name="Decryption key"
|
||||
),
|
||||
cv.Optional(CONF_AUTH_KEY): lambda value: cv.bind_key(
|
||||
value, name="Authentication key"
|
||||
),
|
||||
cv.Optional(CONF_CUSTOM_PATTERNS): cv.ensure_list(CUSTOM_PATTERN_SCHEMA),
|
||||
cv.Optional(CONF_SKIP_CRC, default=False): cv.boolean,
|
||||
cv.Optional(CONF_PROVIDER): cv.string,
|
||||
|
||||
@@ -12,7 +12,7 @@ class DS2484OneWireBus final : public one_wire::OneWireBus, public i2c::I2CDevic
|
||||
public:
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override { return setup_priority::BUS - 1.0f; }
|
||||
float get_setup_priority() const override { return setup_priority::BUS - 1.0; }
|
||||
|
||||
bool reset_device();
|
||||
int reset_int() override;
|
||||
|
||||
@@ -40,7 +40,9 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(Dsmr),
|
||||
cv.Optional(CONF_DECRYPTION_KEY): cv.bind_key(name="Decryption key"),
|
||||
cv.Optional(CONF_DECRYPTION_KEY): lambda value: cv.bind_key(
|
||||
value, name="Decryption key"
|
||||
),
|
||||
cv.Optional(CONF_CRC_CHECK, default=True): cv.boolean,
|
||||
cv.Optional(CONF_GAS_MBUS_ID, default=1): cv.int_,
|
||||
cv.Optional(CONF_WATER_MBUS_ID, default=2): cv.int_,
|
||||
|
||||
@@ -64,21 +64,4 @@ constexpr NATIVE_COLOR color_to_bwyr(Color color, NATIVE_COLOR hw_black, NATIVE_
|
||||
}
|
||||
}
|
||||
|
||||
/** Map RGB color to discrete BWR (black/white/red) 3 color key
|
||||
*
|
||||
* Convenience wrapper over color_to_bwyr for panels without a yellow ink; the yellow corner is
|
||||
* folded into white.
|
||||
*
|
||||
* @tparam NATIVE_COLOR Type of native hardware color values
|
||||
* @param color RGB color to convert from
|
||||
* @param hw_black Native value for black
|
||||
* @param hw_white Native value for white
|
||||
* @param hw_red Native value for red
|
||||
* @return Converted native hardware color value
|
||||
*/
|
||||
template<typename NATIVE_COLOR>
|
||||
constexpr NATIVE_COLOR color_to_bwr(Color color, NATIVE_COLOR hw_black, NATIVE_COLOR hw_white, NATIVE_COLOR hw_red) {
|
||||
return color_to_bwyr<NATIVE_COLOR>(color, hw_black, hw_white, /*hw_yellow=*/hw_white, hw_red);
|
||||
}
|
||||
|
||||
} // namespace esphome::epaper_spi
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
// Reference: https://github.com/SolderedElectronics/Inkplate-Arduino-library (src/boards/Inkplate2)
|
||||
|
||||
#include "epaper_spi_inkplate2.h"
|
||||
#include "colorconv.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome::epaper_spi {
|
||||
|
||||
static constexpr const char *const TAG = "epaper_spi.inkplate2";
|
||||
|
||||
// Map RGB to the panel's black/white/red via the shared converter.
|
||||
enum class Inkplate2Color : uint8_t { BLACK, WHITE, RED };
|
||||
|
||||
static Inkplate2Color to_inkplate2_color(Color color) {
|
||||
return color_to_bwr<Inkplate2Color>(color, Inkplate2Color::BLACK, Inkplate2Color::WHITE, Inkplate2Color::RED);
|
||||
}
|
||||
|
||||
void EPaperInkplate2::power_on() {
|
||||
// Power-on (0x04) leads the init sequence, so there is nothing to do here.
|
||||
ESP_LOGV(TAG, "Power on");
|
||||
}
|
||||
|
||||
void EPaperInkplate2::power_off() {
|
||||
ESP_LOGV(TAG, "Power off");
|
||||
this->cmd_data(0x50, {0xF7}); // VCOM and data interval
|
||||
this->command(0x02); // power off
|
||||
}
|
||||
|
||||
void EPaperInkplate2::refresh_screen(bool partial) {
|
||||
ESP_LOGV(TAG, "Refresh screen"); // full refresh only; partial is unused
|
||||
// Send 0x11 then 0x12 back-to-back: 0x11 raises busy until the refresh finishes, so waiting for idle
|
||||
// between them (as the state machine does between states) would add a ~16s stall.
|
||||
this->cmd_data(0x11, {0x00}); // stop data transfer
|
||||
this->command(0x12); // display refresh
|
||||
}
|
||||
|
||||
void EPaperInkplate2::deep_sleep() {
|
||||
ESP_LOGV(TAG, "Deep sleep");
|
||||
this->cmd_data(0x07, {0xA5});
|
||||
}
|
||||
|
||||
void EPaperInkplate2::fill(Color color) {
|
||||
if (this->get_clipping().is_set()) {
|
||||
EPaperBase::fill(color); // clipping active: defer to the base per-pixel path
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t half_buffer = this->buffer_length_ / 2;
|
||||
|
||||
// Plane encoding: B/W plane 1=white, 0=black; red plane 0=red, 1=no-red.
|
||||
uint8_t bw_byte;
|
||||
uint8_t red_byte;
|
||||
switch (to_inkplate2_color(color)) {
|
||||
case Inkplate2Color::BLACK:
|
||||
bw_byte = 0x00;
|
||||
red_byte = 0xFF;
|
||||
break;
|
||||
case Inkplate2Color::RED:
|
||||
bw_byte = 0xFF;
|
||||
red_byte = 0x00;
|
||||
break;
|
||||
case Inkplate2Color::WHITE:
|
||||
default:
|
||||
bw_byte = 0xFF;
|
||||
red_byte = 0xFF;
|
||||
break;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < half_buffer; i++)
|
||||
this->buffer_[i] = bw_byte;
|
||||
for (size_t i = half_buffer; i < this->buffer_length_; i++)
|
||||
this->buffer_[i] = red_byte;
|
||||
|
||||
this->x_low_ = 0;
|
||||
this->y_low_ = 0;
|
||||
this->x_high_ = this->width_;
|
||||
this->y_high_ = this->height_;
|
||||
}
|
||||
|
||||
void EPaperInkplate2::clear() { this->fill(COLOR_ON); }
|
||||
|
||||
void HOT EPaperInkplate2::draw_pixel_at(int x, int y, Color color) {
|
||||
if (!this->rotate_coordinates_(x, y))
|
||||
return;
|
||||
|
||||
const size_t half_buffer = this->buffer_length_ / 2;
|
||||
const size_t pos = y * this->row_width_ + x / 8;
|
||||
const uint8_t mask = 0x80 >> (x & 0x07); // MSB first; see fill() for plane encoding
|
||||
|
||||
switch (to_inkplate2_color(color)) {
|
||||
case Inkplate2Color::BLACK:
|
||||
this->buffer_[pos] &= ~mask;
|
||||
this->buffer_[pos + half_buffer] |= mask;
|
||||
break;
|
||||
case Inkplate2Color::RED:
|
||||
this->buffer_[pos] |= mask;
|
||||
this->buffer_[pos + half_buffer] &= ~mask;
|
||||
break;
|
||||
case Inkplate2Color::WHITE:
|
||||
default:
|
||||
this->buffer_[pos] |= mask;
|
||||
this->buffer_[pos + half_buffer] |= mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool HOT EPaperInkplate2::send_buffer_range_(size_t end, uint32_t start_time) {
|
||||
uint8_t bytes_to_send[MAX_TRANSFER_SIZE];
|
||||
size_t buf_idx = 0;
|
||||
while (this->current_data_index_ < end) {
|
||||
bytes_to_send[buf_idx++] = this->buffer_[this->current_data_index_++];
|
||||
if (buf_idx == sizeof bytes_to_send) {
|
||||
this->start_data_();
|
||||
this->write_array(bytes_to_send, buf_idx);
|
||||
this->disable();
|
||||
buf_idx = 0;
|
||||
if (millis() - start_time > MAX_TRANSFER_TIME)
|
||||
return false; // yield; resume next loop
|
||||
}
|
||||
}
|
||||
if (buf_idx != 0) {
|
||||
this->start_data_();
|
||||
this->write_array(bytes_to_send, buf_idx);
|
||||
this->disable();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HOT EPaperInkplate2::transfer_data() {
|
||||
const uint32_t start_time = millis();
|
||||
const size_t half_buffer = this->buffer_length_ / 2;
|
||||
|
||||
// Black/white plane (first half) then red plane (second half).
|
||||
if (this->current_data_index_ == 0)
|
||||
this->command(0x10);
|
||||
if (this->current_data_index_ < half_buffer && !this->send_buffer_range_(half_buffer, start_time))
|
||||
return false;
|
||||
|
||||
if (this->current_data_index_ == half_buffer)
|
||||
this->command(0x13);
|
||||
if (!this->send_buffer_range_(this->buffer_length_, start_time))
|
||||
return false;
|
||||
|
||||
this->current_data_index_ = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace esphome::epaper_spi
|
||||
@@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "epaper_spi.h"
|
||||
|
||||
namespace esphome::epaper_spi {
|
||||
|
||||
// Soldered Inkplate 2: 104x212 black/white/red (BWR) e-paper, UC8xxx-family controller.
|
||||
class EPaperInkplate2 final : public EPaperBase {
|
||||
public:
|
||||
EPaperInkplate2(const char *name, uint16_t width, uint16_t height, const uint8_t *init_sequence,
|
||||
size_t init_sequence_length)
|
||||
: EPaperBase(name, width, height, init_sequence, init_sequence_length, DISPLAY_TYPE_COLOR) {
|
||||
// Dual-plane buffer: black/white plane followed by red plane, 1 bit per pixel each.
|
||||
this->buffer_length_ = this->row_width_ * this->height_ * 2;
|
||||
}
|
||||
|
||||
void fill(Color color) override;
|
||||
void clear() override;
|
||||
void draw_pixel_at(int x, int y, Color color) override;
|
||||
|
||||
protected:
|
||||
void refresh_screen(bool partial) override;
|
||||
void power_on() override;
|
||||
void power_off() override;
|
||||
void deep_sleep() override;
|
||||
|
||||
bool transfer_data() override;
|
||||
|
||||
// Streams buffer_[current_data_index_ .. end) in chunks; returns false if it yields on MAX_TRANSFER_TIME.
|
||||
bool send_buffer_range_(size_t end, uint32_t start_time);
|
||||
};
|
||||
|
||||
} // namespace esphome::epaper_spi
|
||||
@@ -1,13 +0,0 @@
|
||||
#include "epaper_waveshare_b.h"
|
||||
|
||||
namespace esphome::epaper_spi {
|
||||
|
||||
bool EpaperWaveshareB::reset() {
|
||||
if (EPaperBase::reset()) {
|
||||
this->command(0x12);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace esphome::epaper_spi
|
||||
@@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
#include "epaper_weact_3c.h"
|
||||
|
||||
namespace esphome::epaper_spi {
|
||||
|
||||
/**
|
||||
* Waveshare (B) series BWR e-paper displays using SSD1680-compatible controllers.
|
||||
* Waveshare uses 0=red, 1=no-red, the inverse of EPaperWeAct3C
|
||||
*/
|
||||
class EpaperWaveshareB : public EPaperWeAct3C {
|
||||
public:
|
||||
using EPaperWeAct3C::EPaperWeAct3C;
|
||||
|
||||
protected:
|
||||
bool reset() override;
|
||||
uint8_t transform_red_byte(uint8_t byte) const override { return static_cast<uint8_t>(~byte); }
|
||||
};
|
||||
|
||||
} // namespace esphome::epaper_spi
|
||||
@@ -144,7 +144,7 @@ bool HOT EPaperWeAct3C::transfer_data() {
|
||||
size_t bytes_to_copy = std::min(MAX_TRANSFER_SIZE, half_buffer - this->current_data_index_);
|
||||
|
||||
for (size_t i = 0; i < bytes_to_copy; i++) {
|
||||
bytes_to_send[i] = this->transform_red_byte(this->buffer_[red_offset + this->current_data_index_ + i]);
|
||||
bytes_to_send[i] = this->buffer_[red_offset + this->current_data_index_ + i];
|
||||
}
|
||||
|
||||
this->write_array(bytes_to_send, bytes_to_copy);
|
||||
|
||||
@@ -34,9 +34,6 @@ class EPaperWeAct3C : public EPaperBase {
|
||||
void draw_pixel_at(int x, int y, Color color) override;
|
||||
|
||||
bool transfer_data() override;
|
||||
|
||||
// Hook for subclasses to transform red plane bytes before they go on the wire.
|
||||
virtual uint8_t transform_red_byte(uint8_t byte) const { return byte; }
|
||||
};
|
||||
|
||||
} // namespace esphome::epaper_spi
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
# Reference: https://github.com/SolderedElectronics/Inkplate-Arduino-library
|
||||
|
||||
from . import EpaperModel
|
||||
|
||||
|
||||
class Inkplate2Model(EpaperModel):
|
||||
def __init__(self, name, class_name="EPaperInkplate2", **kwargs):
|
||||
super().__init__(name, class_name, **kwargs)
|
||||
|
||||
def get_init_sequence(self, config: dict):
|
||||
width, height = self.get_dimensions(config)
|
||||
return (
|
||||
(0x04,), # power on
|
||||
(
|
||||
0x00, # panel setting
|
||||
0x0F, # LUT from OTP
|
||||
0x89, # temperature/boost/timing
|
||||
),
|
||||
(
|
||||
0x61, # resolution
|
||||
width, # width: 1 byte
|
||||
height >> 8, # height: 2 bytes, high byte first ...
|
||||
height & 0xFF, # ... then low byte
|
||||
),
|
||||
(
|
||||
0x50, # VCOM and data interval
|
||||
0x77,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
# Native orientation is portrait (104x212); use `rotation: 90` for the board's landscape orientation.
|
||||
inkplate2 = Inkplate2Model(
|
||||
"inkplate2",
|
||||
width=104,
|
||||
height=212,
|
||||
data_rate="10MHz",
|
||||
# A full 3-color refresh takes ~20s, so don't allow updates faster than that.
|
||||
minimum_update_interval="30s",
|
||||
# Default GPIO pins for the on-board Inkplate 2 wiring.
|
||||
reset_pin=19,
|
||||
dc_pin=33,
|
||||
cs_pin=15,
|
||||
busy_pin={
|
||||
"number": 32,
|
||||
"inverted": True, # hardware: LOW=busy, HIGH=idle
|
||||
"mode": {
|
||||
"input": True,
|
||||
"pullup": True,
|
||||
},
|
||||
},
|
||||
)
|
||||
@@ -1,26 +0,0 @@
|
||||
from . import EpaperModel
|
||||
|
||||
|
||||
class WaveshareB(EpaperModel):
|
||||
def __init__(self, name, **defaults):
|
||||
super().__init__(name, "EpaperWaveshareB", **defaults)
|
||||
|
||||
def get_init_sequence(self, config):
|
||||
_, height = self.get_dimensions(config)
|
||||
h = height - 1
|
||||
return (
|
||||
(0x01, h & 0xFF, h >> 8, 0x00), # Driver output control
|
||||
(0x11, 0x03), # Data entry mode
|
||||
(0x3C, 0x05), # Border waveform
|
||||
(0x18, 0x80), # Internal temperature sensor
|
||||
(0x21, 0x80, 0x80), # Display update control
|
||||
)
|
||||
|
||||
|
||||
WaveshareB(
|
||||
"waveshare-2.13in-bv4",
|
||||
width=122,
|
||||
height=250,
|
||||
data_rate="10MHz",
|
||||
minimum_update_interval="1s",
|
||||
)
|
||||
@@ -169,14 +169,14 @@ bool ES7210::configure_mic_gain_() {
|
||||
|
||||
uint8_t ES7210::es7210_gain_reg_value_(float mic_gain) {
|
||||
// reg: 12 - 34.5dB, 13 - 36dB, 14 - 37.5dB
|
||||
mic_gain += 0.5f;
|
||||
if (mic_gain <= 33.0f) {
|
||||
mic_gain += 0.5;
|
||||
if (mic_gain <= 33.0) {
|
||||
return (uint8_t) (mic_gain / 3);
|
||||
}
|
||||
if (mic_gain < 36.0f) {
|
||||
if (mic_gain < 36.0) {
|
||||
return 12;
|
||||
}
|
||||
if (mic_gain < 37.0f) {
|
||||
if (mic_gain < 37.0) {
|
||||
return 13;
|
||||
}
|
||||
return 14;
|
||||
|
||||
@@ -105,14 +105,14 @@ bool ES7243E::configure_mic_gain_() {
|
||||
|
||||
uint8_t ES7243E::es7243e_gain_reg_value_(float mic_gain) {
|
||||
// reg: 12 - 34.5dB, 13 - 36dB, 14 - 37.5dB
|
||||
mic_gain += 0.5f;
|
||||
if (mic_gain <= 33.0f) {
|
||||
mic_gain += 0.5;
|
||||
if (mic_gain <= 33.0) {
|
||||
return (uint8_t) mic_gain / 3;
|
||||
}
|
||||
if (mic_gain < 36.0f) {
|
||||
if (mic_gain < 36.0) {
|
||||
return 12;
|
||||
}
|
||||
if (mic_gain < 37.0f) {
|
||||
if (mic_gain < 37.0) {
|
||||
return 13;
|
||||
}
|
||||
return 14;
|
||||
|
||||
@@ -173,14 +173,8 @@ bool ES8388::set_mute_state_(bool mute_state) {
|
||||
ES8388_ERROR_CHECK(this->read_byte(ES8388_DACCONTROL3, &value));
|
||||
ESP_LOGV(TAG, "Read ES8388_DACCONTROL3: 0x%02X", value);
|
||||
|
||||
// Only toggle the DACMute bit; the other bits of this register hold unrelated
|
||||
// DAC settings that must be preserved. Previously muting overwrote the whole
|
||||
// register with 0x3C and unmuting never cleared the bit, so once muted the DAC
|
||||
// could not be unmuted again.
|
||||
if (mute_state) {
|
||||
value |= ES8388_DACCONTROL3_DAC_MUTE;
|
||||
} else {
|
||||
value &= ~ES8388_DACCONTROL3_DAC_MUTE;
|
||||
value = 0x3C;
|
||||
}
|
||||
|
||||
ESP_LOGV(TAG, "Setting ES8388_DACCONTROL3 to 0x%02X (muted: %s)", value, YESNO(mute_state));
|
||||
|
||||
@@ -38,7 +38,6 @@ static const uint8_t ES8388_ADCCONTROL14 = 0x16;
|
||||
static const uint8_t ES8388_DACCONTROL1 = 0x17;
|
||||
static const uint8_t ES8388_DACCONTROL2 = 0x18;
|
||||
static const uint8_t ES8388_DACCONTROL3 = 0x19;
|
||||
static const uint8_t ES8388_DACCONTROL3_DAC_MUTE = 0x04; // DACMute, bit 2 of DACCONTROL3
|
||||
static const uint8_t ES8388_DACCONTROL4 = 0x1a;
|
||||
static const uint8_t ES8388_DACCONTROL5 = 0x1b;
|
||||
static const uint8_t ES8388_DACCONTROL6 = 0x1c;
|
||||
|
||||
@@ -1102,8 +1102,6 @@ def final_validate(config):
|
||||
# Imported locally to avoid circular import issues
|
||||
from esphome.components.psram import DOMAIN as PSRAM_DOMAIN
|
||||
|
||||
from .gpio import final_validate_pins
|
||||
|
||||
errs = []
|
||||
conf_fw = config[CONF_FRAMEWORK]
|
||||
advanced = conf_fw[CONF_ADVANCED]
|
||||
@@ -1187,8 +1185,6 @@ def final_validate(config):
|
||||
)
|
||||
)
|
||||
|
||||
final_validate_pins(full_config)
|
||||
|
||||
if (
|
||||
config[CONF_FLASH_SIZE] == "32MB"
|
||||
and "ota" in full_config
|
||||
@@ -2372,14 +2368,14 @@ async def to_code(config):
|
||||
add_idf_sdkconfig_option("CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES", True)
|
||||
add_idf_sdkconfig_option(
|
||||
"CONFIG_SECURE_BOOT_SIGNING_KEY",
|
||||
signed_ota[CONF_SIGNING_KEY].resolve().as_posix(),
|
||||
str(signed_ota[CONF_SIGNING_KEY].resolve()),
|
||||
)
|
||||
else:
|
||||
# Public key mode — verification only, external signing required
|
||||
add_idf_sdkconfig_option("CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES", False)
|
||||
add_idf_sdkconfig_option(
|
||||
"CONFIG_SECURE_BOOT_VERIFICATION_KEY",
|
||||
signed_ota[CONF_VERIFICATION_KEY].resolve().as_posix(),
|
||||
str(signed_ota[CONF_VERIFICATION_KEY].resolve()),
|
||||
)
|
||||
|
||||
cg.add_define("USE_OTA_SIGNED_VERIFICATION")
|
||||
|
||||
@@ -18,7 +18,6 @@ from esphome.const import (
|
||||
PLATFORM_ESP32,
|
||||
)
|
||||
from esphome.core import CORE
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from . import boards
|
||||
from .const import (
|
||||
@@ -51,11 +50,7 @@ from .gpio_esp32_h4 import esp32_h4_validate_gpio_pin, esp32_h4_validate_support
|
||||
from .gpio_esp32_h21 import esp32_h21_validate_gpio_pin, esp32_h21_validate_supports
|
||||
from .gpio_esp32_p4 import esp32_p4_validate_gpio_pin, esp32_p4_validate_supports
|
||||
from .gpio_esp32_s2 import esp32_s2_validate_gpio_pin, esp32_s2_validate_supports
|
||||
from .gpio_esp32_s3 import (
|
||||
esp32_s3_final_validate_pins,
|
||||
esp32_s3_validate_gpio_pin,
|
||||
esp32_s3_validate_supports,
|
||||
)
|
||||
from .gpio_esp32_s3 import esp32_s3_validate_gpio_pin, esp32_s3_validate_supports
|
||||
from .gpio_esp32_s31 import esp32_s31_validate_gpio_pin, esp32_s31_validate_supports
|
||||
|
||||
ESP32InternalGPIOPin = esp32_ns.class_("ESP32InternalGPIOPin", cg.InternalGPIOPin)
|
||||
@@ -101,7 +96,6 @@ def _translate_pin(value):
|
||||
class ESP32ValidationFunctions:
|
||||
pin_validation: Callable[[int], int]
|
||||
usage_validation: Callable[[dict[str, Any]], dict[str, Any]]
|
||||
final_validate: Callable[[ConfigType], None] | None = None
|
||||
|
||||
|
||||
_esp32_validations = {
|
||||
@@ -151,7 +145,6 @@ _esp32_validations = {
|
||||
VARIANT_ESP32S3: ESP32ValidationFunctions(
|
||||
pin_validation=esp32_s3_validate_gpio_pin,
|
||||
usage_validation=esp32_s3_validate_supports,
|
||||
final_validate=esp32_s3_final_validate_pins,
|
||||
),
|
||||
VARIANT_ESP32S31: ESP32ValidationFunctions(
|
||||
pin_validation=esp32_s31_validate_gpio_pin,
|
||||
@@ -268,10 +261,3 @@ async def esp32_pin_to_code(config):
|
||||
cg.add(var.set_drive_strength(config[CONF_DRIVE_STRENGTH]))
|
||||
cg.add(var.set_flags(pins.gpio_flags_expr(config[CONF_MODE])))
|
||||
return var
|
||||
|
||||
|
||||
def final_validate_pins(full_config: ConfigType) -> None:
|
||||
"""Run the active variant's pin final-validation, if it defines one."""
|
||||
funcs = _esp32_validations.get(CORE.data[KEY_ESP32][KEY_VARIANT])
|
||||
if funcs is not None and funcs.final_validate is not None:
|
||||
funcs.final_validate(full_config)
|
||||
|
||||
@@ -2,15 +2,8 @@ import logging
|
||||
from typing import Any
|
||||
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_DISABLED,
|
||||
CONF_INPUT,
|
||||
CONF_MODE,
|
||||
CONF_NUMBER,
|
||||
PLATFORM_ESP32,
|
||||
)
|
||||
from esphome.pins import PIN_SCHEMA_REGISTRY, check_strapping_pin
|
||||
from esphome.types import ConfigType
|
||||
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER
|
||||
from esphome.pins import check_strapping_pin
|
||||
|
||||
_ESP32S3_SPI_PSRAM_PINS = {
|
||||
26: "SPICS1",
|
||||
@@ -45,9 +38,11 @@ def esp32_s3_validate_gpio_pin(value: int) -> int:
|
||||
raise cv.Invalid(
|
||||
f"This pin cannot be used on ESP32-S3s and is already used by the SPI/PSRAM interface(function: {_ESP32S3_SPI_PSRAM_PINS[value]})"
|
||||
)
|
||||
# GPIO33-37 (_ESP32S3R8_PSRAM_PINS) are only taken by the PSRAM interface in
|
||||
# octal mode -- whether that applies isn't known here, so the warning is
|
||||
# deferred to final_validate_pins() in gpio.py once the PSRAM mode is resolved.
|
||||
if value in _ESP32S3R8_PSRAM_PINS:
|
||||
_LOGGER.warning(
|
||||
"GPIO%d is used by the PSRAM interface on ESP32-S3R8 / ESP32-S3R8V and should be avoided on these models",
|
||||
value,
|
||||
)
|
||||
|
||||
if value in (22, 23, 24, 25):
|
||||
# These pins are not exposed in GPIO mux (reason unknown)
|
||||
@@ -76,29 +71,3 @@ def esp32_s3_validate_supports(value: dict[str, Any]) -> dict[str, Any]:
|
||||
|
||||
check_strapping_pin(value, _ESP32S3_STRAPPING_PINS, _LOGGER)
|
||||
return value
|
||||
|
||||
|
||||
def esp32_s3_final_validate_pins(full_config: ConfigType) -> None:
|
||||
"""Warn about GPIO33-37 usage, but only when octal PSRAM (which uses them) is set.
|
||||
|
||||
These pins are only taken by the PSRAM interface in octal mode (ESP32-S3R8 /
|
||||
S3R8V); on quad-PSRAM variants -- or when the psram block is disabled, so the
|
||||
octal interface is never configured -- they are free. The per-pin validator
|
||||
can't know the PSRAM mode, so the check is deferred here, where
|
||||
PIN_SCHEMA_REGISTRY.pins_used already lists every used pin.
|
||||
"""
|
||||
# Imported locally to avoid circular import issues
|
||||
from esphome.components.psram import DOMAIN as PSRAM_DOMAIN, TYPE_OCTAL
|
||||
|
||||
psram_config = full_config.get(PSRAM_DOMAIN, {})
|
||||
if psram_config.get(CONF_DISABLED) or psram_config.get(CONF_MODE) != TYPE_OCTAL:
|
||||
return
|
||||
for number in sorted(
|
||||
number
|
||||
for key, _client_id, number in PIN_SCHEMA_REGISTRY.pins_used
|
||||
if key == PLATFORM_ESP32 and number in _ESP32S3R8_PSRAM_PINS
|
||||
):
|
||||
_LOGGER.warning(
|
||||
"GPIO%d is used by the PSRAM interface in octal mode and should be avoided",
|
||||
number,
|
||||
)
|
||||
|
||||
@@ -2,16 +2,13 @@ import logging
|
||||
from typing import Any
|
||||
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER, CONF_SCL, CONF_SDA
|
||||
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER
|
||||
from esphome.pins import check_strapping_pin
|
||||
|
||||
# Per the ESP32-S31 datasheet (page 96):
|
||||
# https://documentation.espressif.com/esp32-s31_datasheet_en.pdf
|
||||
_ESP32S31_SPI_FLASH_PINS: set[int] = {27, 28, 29, 31, 32, 33}
|
||||
# GPIO60/GPIO61 set the boot mode; GPIO37 selects the JTAG signal source.
|
||||
_ESP32S31_STRAPPING_PINS: set[int] = {37, 60, 61}
|
||||
# LP I2C is fixed to GPIO6 (SCL) / GPIO7 (SDA) per the datasheet IO MUX table.
|
||||
_ESP32S31_I2C_LP_PINS = {"SDA": 7, "SCL": 6}
|
||||
_ESP32S31_STRAPPING_PINS: set[int] = {60, 61}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -39,13 +36,3 @@ def esp32_s31_validate_supports(value: dict[str, Any]) -> dict[str, Any]:
|
||||
|
||||
check_strapping_pin(value, _ESP32S31_STRAPPING_PINS, _LOGGER)
|
||||
return value
|
||||
|
||||
|
||||
def esp32_s31_validate_lp_i2c(value):
|
||||
lp_sda_pin = _ESP32S31_I2C_LP_PINS["SDA"]
|
||||
lp_scl_pin = _ESP32S31_I2C_LP_PINS["SCL"]
|
||||
if int(value[CONF_SDA]) != lp_sda_pin or int(value[CONF_SCL]) != lp_scl_pin:
|
||||
raise cv.Invalid(
|
||||
f"Low power i2c interface is only supported on GPIO{lp_sda_pin} SDA and GPIO{lp_scl_pin} SCL for ESP32-S31"
|
||||
)
|
||||
return value
|
||||
|
||||
@@ -77,15 +77,13 @@ template<typename... Ts> class BLECharacteristicSetValueAction final : public Ac
|
||||
// Set initial value
|
||||
this->parent_->set_value(this->buffer_.value(x...));
|
||||
// Set the listener for read events
|
||||
// ``mutable`` keeps by-copy captures non-const for triggers passing args by reference
|
||||
// (e.g. climate on_control's ClimateCall&). See #17142.
|
||||
this->parent_->on_read([this, x...](uint16_t id) mutable {
|
||||
this->parent_->on_read([this, x...](uint16_t id) {
|
||||
// Set the value of the characteristic every time it is read
|
||||
this->parent_->set_value(this->buffer_.value(x...));
|
||||
});
|
||||
// Set the listener in the global manager so only one BLECharacteristicSetValueAction is set for each characteristic
|
||||
BLECharacteristicSetValueActionManager::get_instance()->set_listener(
|
||||
this->parent_, [this, x...]() mutable { this->parent_->set_value(this->buffer_.value(x...)); });
|
||||
this->parent_, [this, x...]() { this->parent_->set_value(this->buffer_.value(x...)); });
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -28,6 +28,9 @@ namespace esphome::espnow {
|
||||
|
||||
static constexpr const char *TAG = "espnow";
|
||||
|
||||
static const esp_err_t CONFIG_ESPNOW_WAKE_WINDOW = 50;
|
||||
static const esp_err_t CONFIG_ESPNOW_WAKE_INTERVAL = 100;
|
||||
|
||||
ESPNowComponent *global_esp_now = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
static const LogString *espnow_error_to_str(esp_err_t error) {
|
||||
@@ -201,6 +204,11 @@ void ESPNowComponent::enable_() {
|
||||
|
||||
esp_wifi_get_mac(WIFI_IF_STA, this->own_address_);
|
||||
|
||||
#ifdef USE_DEEP_SLEEP
|
||||
esp_now_set_wake_window(CONFIG_ESPNOW_WAKE_WINDOW);
|
||||
esp_wifi_connectionless_module_set_wake_interval(CONFIG_ESPNOW_WAKE_INTERVAL);
|
||||
#endif
|
||||
|
||||
this->state_ = ESPNOW_STATE_ENABLED;
|
||||
|
||||
for (auto peer : this->peers_) {
|
||||
@@ -303,9 +311,7 @@ void ESPNowComponent::loop() {
|
||||
ESP_LOGV(TAG, ">>> [%s] %s", addr_buf, LOG_STR_ARG(espnow_error_to_str(packet->packet_.sent.status)));
|
||||
#endif
|
||||
if (this->current_send_packet_ != nullptr) {
|
||||
if (this->current_send_packet_->callback_ != nullptr) {
|
||||
this->current_send_packet_->callback_(packet->packet_.sent.status);
|
||||
}
|
||||
this->current_send_packet_->callback_(packet->packet_.sent.status);
|
||||
this->send_packet_pool_.release(this->current_send_packet_);
|
||||
this->current_send_packet_ = nullptr; // Reset current packet after sending
|
||||
}
|
||||
|
||||
@@ -126,8 +126,6 @@ ETHERNET_TYPES = {
|
||||
"ENC28J60": EthernetType.ETHERNET_TYPE_ENC28J60,
|
||||
"W6100": EthernetType.ETHERNET_TYPE_W6100,
|
||||
"W6300": EthernetType.ETHERNET_TYPE_W6300,
|
||||
"GENERIC": EthernetType.ETHERNET_TYPE_GENERIC,
|
||||
"YT8531": EthernetType.ETHERNET_TYPE_YT8531,
|
||||
}
|
||||
|
||||
# PHY types that need compile-time defines for conditional compilation
|
||||
@@ -147,8 +145,6 @@ _PHY_TYPE_TO_DEFINE = {
|
||||
"ENC28J60": "USE_ETHERNET_ENC28J60",
|
||||
"W6100": "USE_ETHERNET_W6100",
|
||||
"W6300": "USE_ETHERNET_W6300",
|
||||
"GENERIC": "USE_ETHERNET_GENERIC",
|
||||
"YT8531": "USE_ETHERNET_YT8531",
|
||||
}
|
||||
|
||||
|
||||
@@ -313,24 +309,6 @@ def _validate(config):
|
||||
f"({CORE.target_framework} {CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION]}), "
|
||||
f"'{CONF_INTERRUPT_PIN}' is a required option for [ethernet]."
|
||||
)
|
||||
elif config[CONF_TYPE] in ("GENERIC", "YT8531"):
|
||||
from esphome.components.esp32 import (
|
||||
VARIANT_ESP32S31,
|
||||
get_esp32_variant,
|
||||
idf_version,
|
||||
)
|
||||
|
||||
eth_type = config[CONF_TYPE]
|
||||
variant = get_esp32_variant()
|
||||
if variant != VARIANT_ESP32S31:
|
||||
raise cv.Invalid(
|
||||
f"The '{eth_type}' (RGMII) PHY is only supported on gigabit-capable "
|
||||
f"variants (ESP32-S31), not {variant}"
|
||||
)
|
||||
if idf_version() < cv.Version(6, 0, 0):
|
||||
raise cv.Invalid(
|
||||
f"The '{eth_type}' (RGMII) PHY requires ESP-IDF 6.0 or newer."
|
||||
)
|
||||
elif config[CONF_TYPE] != "OPENETH":
|
||||
from esphome.components.esp32 import (
|
||||
VARIANT_ESP32,
|
||||
@@ -414,23 +392,6 @@ RMII_SCHEMA = cv.All(
|
||||
cv.only_on([Platform.ESP32]),
|
||||
)
|
||||
|
||||
# Generic IEEE 802.3 PHY over the internal EMAC RGMII interface (e.g. ESP32-S31).
|
||||
# RGMII data pins come from the IDF per-target default config.
|
||||
GENERIC_SCHEMA = cv.All(
|
||||
BASE_SCHEMA.extend(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_MDC_PIN): pins.internal_gpio_output_pin_number,
|
||||
cv.Required(CONF_MDIO_PIN): pins.internal_gpio_output_pin_number,
|
||||
cv.Optional(CONF_PHY_ADDR, default=0): cv.int_range(min=0, max=31),
|
||||
cv.Optional(CONF_POWER_PIN): pins.internal_gpio_output_pin_number,
|
||||
cv.Optional(CONF_PHY_REGISTERS): cv.ensure_list(PHY_REGISTER_SCHEMA),
|
||||
}
|
||||
)
|
||||
),
|
||||
cv.only_on([Platform.ESP32]),
|
||||
)
|
||||
|
||||
SPI_SCHEMA = cv.All(
|
||||
BASE_SCHEMA.extend(
|
||||
cv.Schema(
|
||||
@@ -481,8 +442,6 @@ CONFIG_SCHEMA = cv.All(
|
||||
"W6100": cv.All(SPI_SCHEMA, cv.only_on([Platform.RP2040])),
|
||||
"W6300": cv.All(SPI_SCHEMA, cv.only_on([Platform.RP2040])),
|
||||
"LAN8670": RMII_SCHEMA,
|
||||
"GENERIC": GENERIC_SCHEMA,
|
||||
"YT8531": GENERIC_SCHEMA,
|
||||
},
|
||||
upper=True,
|
||||
),
|
||||
@@ -612,20 +571,6 @@ async def _to_code_esp32(var: cg.Pvariable, config: ConfigType) -> None:
|
||||
elif config[CONF_TYPE] == "OPENETH":
|
||||
cg.add_define("USE_ETHERNET_OPENETH")
|
||||
add_idf_sdkconfig_option("CONFIG_ETH_USE_OPENETH", True)
|
||||
elif config[CONF_TYPE] in ("GENERIC", "YT8531"):
|
||||
# RGMII data pins come from the IDF default config; set MDC/MDIO + PHY addr.
|
||||
cg.add(var.set_phy_addr(config[CONF_PHY_ADDR]))
|
||||
cg.add(var.set_mdc_pin(config[CONF_MDC_PIN]))
|
||||
cg.add(var.set_mdio_pin(config[CONF_MDIO_PIN]))
|
||||
if CONF_POWER_PIN in config:
|
||||
cg.add(var.set_power_pin(config[CONF_POWER_PIN]))
|
||||
for register_value in config.get(CONF_PHY_REGISTERS, []):
|
||||
reg = phy_register(
|
||||
register_value.get(CONF_ADDRESS),
|
||||
register_value.get(CONF_VALUE),
|
||||
register_value.get(CONF_PAGE_ID),
|
||||
)
|
||||
cg.add(var.add_phy_register(reg))
|
||||
else:
|
||||
cg.add(var.set_phy_addr(config[CONF_PHY_ADDR]))
|
||||
cg.add(var.set_mdc_pin(config[CONF_MDC_PIN]))
|
||||
|
||||
@@ -86,8 +86,6 @@ enum EthernetType : uint8_t {
|
||||
ETHERNET_TYPE_ENC28J60,
|
||||
ETHERNET_TYPE_W6100,
|
||||
ETHERNET_TYPE_W6300,
|
||||
ETHERNET_TYPE_GENERIC,
|
||||
ETHERNET_TYPE_YT8531,
|
||||
};
|
||||
|
||||
struct ManualIP {
|
||||
@@ -231,11 +229,6 @@ class EthernetComponent final : public Component {
|
||||
#ifdef USE_ETHERNET_KSZ8081
|
||||
/// @brief Set `RMII Reference Clock Select` bit for KSZ8081.
|
||||
void ksz8081_set_clock_reference_(esp_eth_mac_t *mac);
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_YT8531
|
||||
/// @brief Apply YT8531-specific config: re-enable auto-negotiation (disabled on
|
||||
/// reset) and set the RGMII Tx/Rx clock delays needed for reliable data sampling.
|
||||
void yt8531_phy_init_();
|
||||
#endif
|
||||
/// @brief Set arbitratry PHY registers from config.
|
||||
void write_phy_register_(esp_eth_mac_t *mac, PHYRegister register_data);
|
||||
|
||||
@@ -254,14 +254,9 @@ void EthernetComponent::ethernet_lazy_init_() {
|
||||
esp32_emac_config.smi_mdc_gpio_num = this->mdc_pin_;
|
||||
esp32_emac_config.smi_mdio_gpio_num = this->mdio_pin_;
|
||||
#endif
|
||||
// The RGMII types (GENERIC, YT8531) use the RGMII interface and default GPIO map from
|
||||
// eth_esp32_emac_default_config(); writing the RMII clock config would clobber that
|
||||
// union, so skip the RMII clock override for them.
|
||||
if (this->type_ != ETHERNET_TYPE_GENERIC && this->type_ != ETHERNET_TYPE_YT8531) {
|
||||
esp32_emac_config.clock_config.rmii.clock_mode = this->clk_mode_;
|
||||
esp32_emac_config.clock_config.rmii.clock_gpio =
|
||||
static_cast<decltype(esp32_emac_config.clock_config.rmii.clock_gpio)>(this->clk_pin_);
|
||||
}
|
||||
esp32_emac_config.clock_config.rmii.clock_mode = this->clk_mode_;
|
||||
esp32_emac_config.clock_config.rmii.clock_gpio =
|
||||
static_cast<decltype(esp32_emac_config.clock_config.rmii.clock_gpio)>(this->clk_pin_);
|
||||
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
|
||||
#endif
|
||||
@@ -324,20 +319,6 @@ void EthernetComponent::ethernet_lazy_init_() {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
|
||||
// GENERIC and YT8531 both use the built-in generic 802.3 PHY driver; YT8531 gets
|
||||
// extra chip-specific tuning applied later in ethernet_lazy_init_().
|
||||
#ifdef USE_ETHERNET_GENERIC
|
||||
case ETHERNET_TYPE_GENERIC:
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_YT8531
|
||||
case ETHERNET_TYPE_YT8531:
|
||||
#endif
|
||||
#if defined(USE_ETHERNET_GENERIC) || defined(USE_ETHERNET_YT8531)
|
||||
this->phy_ = esp_eth_phy_new_generic(&phy_config);
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_SPI
|
||||
#if defined(USE_ETHERNET_W5500)
|
||||
@@ -382,30 +363,7 @@ void EthernetComponent::ethernet_lazy_init_() {
|
||||
for (const auto &phy_register : this->phy_registers_) {
|
||||
this->write_phy_register_(mac, phy_register);
|
||||
}
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
|
||||
#ifdef USE_ETHERNET_GENERIC
|
||||
// The generic 802.3 PHY driver only resets the PHY in its init; it never enables
|
||||
// auto-negotiation. A PHY that resets into a forced-speed mode (BMCR auto-nego bit
|
||||
// clear) therefore stays there, and esp_eth_start() skips negotiation because the
|
||||
// driver cached auto_nego_en=false at install time. Force auto-negotiation on here
|
||||
// (which also updates that cached state) so esp_eth_start() restarts a proper
|
||||
// negotiation. (YT8531 does this as part of its own chip-specific init below.)
|
||||
if (this->type_ == ETHERNET_TYPE_GENERIC) {
|
||||
bool autoneg_enable = true;
|
||||
err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_S_AUTONEGO, &autoneg_enable);
|
||||
ESPHL_ERROR_CHECK(err, "Enable auto-negotiation failed");
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_YT8531
|
||||
if (this->type_ == ETHERNET_TYPE_YT8531) {
|
||||
this->yt8531_phy_init_();
|
||||
if (this->is_failed())
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif // ESP_IDF_VERSION >= 6.0.0
|
||||
#endif // !USE_ETHERNET_SPI
|
||||
|
||||
// use ESP internal eth mac
|
||||
uint8_t mac_addr[6];
|
||||
@@ -528,16 +486,6 @@ void EthernetComponent::dump_config() {
|
||||
eth_type = "LAN8670";
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_GENERIC
|
||||
case ETHERNET_TYPE_GENERIC:
|
||||
eth_type = "Generic (RGMII)";
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_ETHERNET_YT8531
|
||||
case ETHERNET_TYPE_YT8531:
|
||||
eth_type = "YT8531 (RGMII)";
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
eth_type = "Unknown";
|
||||
@@ -834,19 +782,6 @@ void EthernetComponent::dump_connect_params_() {
|
||||
char dns1_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
char dns2_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
char mac_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||
uint16_t link_speed = 10;
|
||||
switch (this->get_link_speed()) {
|
||||
case ETH_SPEED_100M:
|
||||
link_speed = 100;
|
||||
break;
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(6, 0, 0)
|
||||
case ETH_SPEED_1000M:
|
||||
link_speed = 1000;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ESP_LOGCONFIG(TAG,
|
||||
" IP Address: %s\n"
|
||||
" Hostname: '%s'\n"
|
||||
@@ -861,7 +796,7 @@ void EthernetComponent::dump_connect_params_() {
|
||||
network::IPAddress(&ip.netmask).str_to(subnet_buf), network::IPAddress(&ip.gw).str_to(gateway_buf),
|
||||
network::IPAddress(dns_ip1).str_to(dns1_buf), network::IPAddress(dns_ip2).str_to(dns2_buf),
|
||||
this->get_eth_mac_address_pretty_into_buffer(mac_buf),
|
||||
YESNO(this->get_duplex_mode() == ETH_DUPLEX_FULL), link_speed);
|
||||
YESNO(this->get_duplex_mode() == ETH_DUPLEX_FULL), this->get_link_speed() == ETH_SPEED_100M ? 100 : 10);
|
||||
|
||||
#if USE_NETWORK_IPV6
|
||||
struct esp_ip6_addr if_ip6s[CONFIG_LWIP_IPV6_NUM_ADDRESSES];
|
||||
@@ -1023,50 +958,6 @@ void EthernetComponent::write_phy_register_(esp_eth_mac_t *mac, PHYRegister regi
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_ETHERNET_YT8531
|
||||
void EthernetComponent::yt8531_phy_init_() {
|
||||
esp_err_t err;
|
||||
|
||||
// The YT8531 disables auto-negotiation on hardware reset (undocumented behavior), and the
|
||||
// generic 802.3 driver only resets the PHY, so re-enable it (this also updates the driver's
|
||||
// cached auto-nego state used by esp_eth_start()).
|
||||
bool autoneg_enable = true;
|
||||
err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_S_AUTONEGO, &autoneg_enable);
|
||||
ESPHL_ERROR_CHECK(err, "YT8531 enable auto-negotiation failed");
|
||||
|
||||
// RGMII needs ~2 ns Tx and Rx clock delays for reliable data sampling. These are set through
|
||||
// the YT8531 extended-register interface: write the ext-register address to 0x1E, then
|
||||
// read/modify/write its value via 0x1F.
|
||||
esp_eth_phy_reg_rw_data_t phy_reg;
|
||||
uint32_t reg_val;
|
||||
phy_reg.reg_value_p = ®_val;
|
||||
|
||||
// RX ~2 ns coarse delay: EXT_CHIP_CONFIG (0xA001), set rxc_dly_en (bit 8).
|
||||
reg_val = 0xA001;
|
||||
phy_reg.reg_addr = 0x1E;
|
||||
err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_WRITE_PHY_REG, &phy_reg);
|
||||
ESPHL_ERROR_CHECK(err, "YT8531 select Chip_Config failed");
|
||||
phy_reg.reg_addr = 0x1F;
|
||||
err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_READ_PHY_REG, &phy_reg);
|
||||
ESPHL_ERROR_CHECK(err, "YT8531 read Chip_Config failed");
|
||||
reg_val |= (1U << 8);
|
||||
err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_WRITE_PHY_REG, &phy_reg);
|
||||
ESPHL_ERROR_CHECK(err, "YT8531 write Chip_Config failed");
|
||||
|
||||
// TX ~2 ns delay: EXT_RGMII_CONFIG1 (0xA003), tx_delay_sel[3:0] and tx_delay_sel_fe[7:4] = 13.
|
||||
reg_val = 0xA003;
|
||||
phy_reg.reg_addr = 0x1E;
|
||||
err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_WRITE_PHY_REG, &phy_reg);
|
||||
ESPHL_ERROR_CHECK(err, "YT8531 select RGMII_Config1 failed");
|
||||
phy_reg.reg_addr = 0x1F;
|
||||
err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_READ_PHY_REG, &phy_reg);
|
||||
ESPHL_ERROR_CHECK(err, "YT8531 read RGMII_Config1 failed");
|
||||
reg_val = (reg_val & ~0x00FFU) | (13U << 4) | (13U << 0);
|
||||
err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_WRITE_PHY_REG, &phy_reg);
|
||||
ESPHL_ERROR_CHECK(err, "YT8531 write RGMII_Config1 failed");
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace esphome::ethernet
|
||||
|
||||
@@ -139,7 +139,7 @@ void Graph::draw(Display *buff, uint16_t x_offset, uint16_t y_offset, Color colo
|
||||
/// Draw grid
|
||||
if (!std::isnan(this->gridspacing_y_)) {
|
||||
for (int y = yn; y <= ym; y++) {
|
||||
int16_t py = (int16_t) roundf((this->height_ - 1) * (1.0f - (float) (y - yn) / (ym - yn)));
|
||||
int16_t py = (int16_t) roundf((this->height_ - 1) * (1.0 - (float) (y - yn) / (ym - yn)));
|
||||
for (uint32_t x = 0; x < this->width_; x += 2) {
|
||||
buff->draw_pixel_at(x_offset + x, y_offset + py, color);
|
||||
}
|
||||
@@ -177,7 +177,7 @@ void Graph::draw(Display *buff, uint16_t x_offset, uint16_t y_offset, Color colo
|
||||
uint8_t bit = 1 << ((i % (thick * LineType::PATTERN_LENGTH)) / thick);
|
||||
bool b = (trace->get_line_type() & bit) == bit;
|
||||
if (b) {
|
||||
int16_t y = (int16_t) roundf((this->height_ - 1) * (1.0f - v)) - thick / 2 + y_offset;
|
||||
int16_t y = (int16_t) roundf((this->height_ - 1) * (1.0 - v)) - thick / 2 + y_offset;
|
||||
auto draw_pixel_at = [&buff, c, y_offset, this](int16_t x, int16_t y) {
|
||||
if (y >= y_offset && static_cast<uint32_t>(y) < y_offset + this->height_)
|
||||
buff->draw_pixel_at(x, y, c);
|
||||
|
||||
@@ -122,7 +122,7 @@ void GroveMotorDriveTB6612FNG::stepper_run(StepperModeTypeT mode, int16_t steps,
|
||||
|
||||
rpm = clamp<uint16_t>(rpm, 1, 300);
|
||||
|
||||
ms_per_step = (uint16_t) (3000.0f / (float) rpm);
|
||||
ms_per_step = (uint16_t) (3000.0 / (float) rpm);
|
||||
buffer_[0] = mode;
|
||||
buffer_[1] = cw; //(cw=1) => cw; (cw=0) => ccw
|
||||
buffer_[2] = steps;
|
||||
@@ -153,7 +153,7 @@ void GroveMotorDriveTB6612FNG::stepper_keep_run(StepperModeTypeT mode, uint16_t
|
||||
uint16_t ms_per_step = 0;
|
||||
|
||||
rpm = clamp<uint16_t>(rpm, 1, 300);
|
||||
ms_per_step = (uint16_t) (3000.0f / (float) rpm);
|
||||
ms_per_step = (uint16_t) (3000.0 / (float) rpm);
|
||||
|
||||
buffer_[0] = mode;
|
||||
buffer_[1] = cw; //(cw=1) => cw; (cw=0) => ccw
|
||||
|
||||
@@ -607,7 +607,7 @@ haier_protocol::HaierMessage HonClimate::get_control_message() {
|
||||
if (climate_control.target_temperature.has_value()) {
|
||||
float target_temp = climate_control.target_temperature.value();
|
||||
out_data->set_point = ((int) target_temp) - 16; // set the temperature with offset 16
|
||||
out_data->half_degree = (target_temp - ((int) target_temp) >= 0.49f) ? 1 : 0;
|
||||
out_data->half_degree = (target_temp - ((int) target_temp) >= 0.49) ? 1 : 0;
|
||||
}
|
||||
if (out_data->ac_power == 0) {
|
||||
// If AC is off - no presets allowed
|
||||
|
||||
@@ -341,7 +341,7 @@ haier_protocol::HaierMessage Smartair2Climate::get_control_message() {
|
||||
if (climate_control.target_temperature.has_value()) {
|
||||
float target_temp = climate_control.target_temperature.value();
|
||||
out_data->set_point = ((int) target_temp) - 16; // set the temperature with offset 16
|
||||
out_data->half_degree = (target_temp - ((int) target_temp) >= 0.49f) ? 1 : 0;
|
||||
out_data->half_degree = (target_temp - ((int) target_temp) >= 0.49) ? 1 : 0;
|
||||
}
|
||||
if (out_data->ac_power == 0) {
|
||||
// If AC is off - no presets allowed
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import light, output
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_OUTPUT_ID, CONF_PIN_A, CONF_PIN_B, CONF_UPDATE_INTERVAL
|
||||
from esphome.const import CONF_OUTPUT_ID, CONF_PIN_A, CONF_PIN_B
|
||||
|
||||
from .. import hbridge_ns
|
||||
|
||||
CODEOWNERS = ["@DotNetDann"]
|
||||
|
||||
HBridgeLightOutput = hbridge_ns.class_(
|
||||
"HBridgeLightOutput", cg.PollingComponent, light.LightOutput
|
||||
"HBridgeLightOutput", cg.Component, light.LightOutput
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend(
|
||||
@@ -16,14 +16,12 @@ CONFIG_SCHEMA = light.RGB_LIGHT_SCHEMA.extend(
|
||||
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(HBridgeLightOutput),
|
||||
cv.Required(CONF_PIN_A): cv.use_id(output.FloatOutput),
|
||||
cv.Required(CONF_PIN_B): cv.use_id(output.FloatOutput),
|
||||
cv.Optional(CONF_UPDATE_INTERVAL, default="8ms"): cv.update_interval,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
|
||||
cg.add(var.set_update_interval(config.pop(CONF_UPDATE_INTERVAL)))
|
||||
await cg.register_component(var, config)
|
||||
await light.register_light(var, config)
|
||||
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
#include "esphome/components/light/light_output.h"
|
||||
#include "esphome/components/output/float_output.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
namespace esphome::hbridge {
|
||||
|
||||
class HBridgeLightOutput final : public PollingComponent, public light::LightOutput {
|
||||
class HBridgeLightOutput final : public Component, public light::LightOutput {
|
||||
public:
|
||||
void set_pina_pin(output::FloatOutput *pina_pin) { this->pina_pin_ = pina_pin; }
|
||||
void set_pinb_pin(output::FloatOutput *pinb_pin) { this->pinb_pin_ = pinb_pin; }
|
||||
@@ -19,12 +20,11 @@ class HBridgeLightOutput final : public PollingComponent, public light::LightOut
|
||||
return traits;
|
||||
}
|
||||
|
||||
void setup() override { this->stop_poller(); }
|
||||
void setup() override { this->disable_loop(); }
|
||||
|
||||
void update() override {
|
||||
// Flip the H-bridge direction to multiplex cold/warm white. update_interval must stay
|
||||
// slower than the output's PWM period (flipping faster collapses the output onto one
|
||||
// channel) but fast enough to avoid flicker (issue #17030).
|
||||
void loop() override {
|
||||
// Only called when both channels are active — alternate H-bridge direction
|
||||
// each iteration to multiplex cold and warm white.
|
||||
if (!this->forward_direction_) {
|
||||
this->pina_pin_->set_level(this->pina_duty_);
|
||||
this->pinb_pin_->set_level(0);
|
||||
@@ -46,17 +46,13 @@ class HBridgeLightOutput final : public PollingComponent, public light::LightOut
|
||||
this->pinb_duty_ = new_pinb;
|
||||
|
||||
if (new_pina != 0.0f && new_pinb != 0.0f) {
|
||||
// Both channels active — multiplex the H-bridge direction via the poller.
|
||||
if (!this->multiplexing_) {
|
||||
this->multiplexing_ = true;
|
||||
this->start_poller();
|
||||
}
|
||||
// Both channels active — need loop to alternate H-bridge direction
|
||||
this->high_freq_.start();
|
||||
this->enable_loop();
|
||||
} else {
|
||||
// Zero or one channel active — drive pins directly, no multiplexing needed.
|
||||
if (this->multiplexing_) {
|
||||
this->multiplexing_ = false;
|
||||
this->stop_poller();
|
||||
}
|
||||
// Zero or one channel active — drive pins directly, no multiplexing needed
|
||||
this->high_freq_.stop();
|
||||
this->disable_loop();
|
||||
this->pina_pin_->set_level(new_pina);
|
||||
this->pinb_pin_->set_level(new_pinb);
|
||||
}
|
||||
@@ -68,7 +64,7 @@ class HBridgeLightOutput final : public PollingComponent, public light::LightOut
|
||||
float pina_duty_{0};
|
||||
float pinb_duty_{0};
|
||||
bool forward_direction_{false};
|
||||
bool multiplexing_{false};
|
||||
HighFrequencyLoopRequester high_freq_;
|
||||
};
|
||||
|
||||
} // namespace esphome::hbridge
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace esphome::hm3301 {
|
||||
|
||||
static const uint8_t SELECT_COMM_CMD = 0x88;
|
||||
|
||||
class HM3301Component final : public PollingComponent, public i2c::I2CDevice {
|
||||
class HM3301Component : public PollingComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
HM3301Component() = default;
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/application.h"
|
||||
|
||||
#include <numbers>
|
||||
|
||||
namespace esphome::hmc5883l {
|
||||
|
||||
static const char *const TAG = "hmc5883l";
|
||||
@@ -128,7 +126,7 @@ void HMC5883LComponent::update() {
|
||||
const float y = int16_t(raw_y) * mg_per_bit * 0.1f;
|
||||
const float z = int16_t(raw_z) * mg_per_bit * 0.1f;
|
||||
|
||||
float heading = atan2f(0.0f - x, y) * 180.0f / std::numbers::pi_v<float>;
|
||||
float heading = atan2f(0.0f - x, y) * 180.0f / M_PI;
|
||||
ESP_LOGD(TAG, "Got x=%0.02fµT y=%0.02fµT z=%0.02fµT heading=%0.01f°", x, y, z, heading);
|
||||
|
||||
if (this->x_sensor_ != nullptr)
|
||||
|
||||
@@ -34,7 +34,7 @@ enum HMC5883LRange {
|
||||
HMC5883L_RANGE_810_UT = 0b111,
|
||||
};
|
||||
|
||||
class HMC5883LComponent final : public PollingComponent, public i2c::I2CDevice {
|
||||
class HMC5883LComponent : public PollingComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace esphome::homeassistant {
|
||||
|
||||
class HomeassistantBinarySensor final : public binary_sensor::BinarySensor, public Component {
|
||||
class HomeassistantBinarySensor : public binary_sensor::BinarySensor, public Component {
|
||||
public:
|
||||
void set_entity_id(const char *entity_id) { this->entity_id_ = entity_id; }
|
||||
void set_attribute(const char *attribute) { this->attribute_ = attribute; }
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace esphome::homeassistant {
|
||||
|
||||
class HomeassistantNumber final : public number::Number, public Component {
|
||||
class HomeassistantNumber : public number::Number, public Component {
|
||||
public:
|
||||
void set_entity_id(const char *entity_id) { this->entity_id_ = entity_id; }
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace esphome::homeassistant {
|
||||
|
||||
class HomeassistantSensor final : public sensor::Sensor, public Component {
|
||||
class HomeassistantSensor : public sensor::Sensor, public Component {
|
||||
public:
|
||||
void set_entity_id(const char *entity_id) { this->entity_id_ = entity_id; }
|
||||
void set_attribute(const char *attribute) { this->attribute_ = attribute; }
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace esphome::homeassistant {
|
||||
|
||||
class HomeassistantSwitch final : public switch_::Switch, public Component {
|
||||
class HomeassistantSwitch : public switch_::Switch, public Component {
|
||||
public:
|
||||
void set_entity_id(const char *entity_id) { this->entity_id_ = entity_id; }
|
||||
void setup() override;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace esphome::homeassistant {
|
||||
|
||||
class HomeassistantTextSensor final : public text_sensor::TextSensor, public Component {
|
||||
class HomeassistantTextSensor : public text_sensor::TextSensor, public Component {
|
||||
public:
|
||||
void set_entity_id(const char *entity_id) { this->entity_id_ = entity_id; }
|
||||
void set_attribute(const char *attribute) { this->attribute_ = attribute; }
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
namespace esphome::honeywell_hih_i2c {
|
||||
|
||||
class HoneywellHIComponent final : public PollingComponent, public i2c::I2CDevice {
|
||||
class HoneywellHIComponent : public PollingComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
void dump_config() override;
|
||||
void loop() override;
|
||||
|
||||
@@ -55,9 +55,7 @@ float HONEYWELLABPSensor::countstopressure_(const int counts, const float min_pr
|
||||
|
||||
// Converts a digital temperature measurement in counts to temperature in C
|
||||
// This will be invalid if sensore daoes not have temperature measurement capability
|
||||
float HONEYWELLABPSensor::countstotemperatures_(const int counts) {
|
||||
return (((float) counts / 2047.0f) * 200.0f) - 50.0f;
|
||||
}
|
||||
float HONEYWELLABPSensor::countstotemperatures_(const int counts) { return (((float) counts / 2047.0) * 200.0) - 50.0; }
|
||||
|
||||
// Pressure value from the most recent reading in units
|
||||
float HONEYWELLABPSensor::read_pressure_() {
|
||||
@@ -71,9 +69,9 @@ void HONEYWELLABPSensor::update() {
|
||||
ESP_LOGV(TAG, "Update Honeywell ABP Sensor");
|
||||
if (readsensor_() == 0) {
|
||||
if (this->pressure_sensor_ != nullptr)
|
||||
this->pressure_sensor_->publish_state(read_pressure_() * 1.0f);
|
||||
this->pressure_sensor_->publish_state(read_pressure_() * 1.0);
|
||||
if (this->temperature_sensor_ != nullptr)
|
||||
this->temperature_sensor_->publish_state(read_temperature_() * 1.0f);
|
||||
this->temperature_sensor_->publish_state(read_temperature_() * 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
namespace esphome::honeywellabp {
|
||||
|
||||
class HONEYWELLABPSensor final : public PollingComponent,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
|
||||
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_200KHZ> {
|
||||
class HONEYWELLABPSensor : public PollingComponent,
|
||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
|
||||
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_200KHZ> {
|
||||
public:
|
||||
void set_pressure_sensor(sensor::Sensor *pressure_sensor) { pressure_sensor_ = pressure_sensor; }
|
||||
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; }
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace esphome::honeywellabp2_i2c {
|
||||
|
||||
enum ABP2TRANFERFUNCTION { ABP2_TRANS_FUNC_A = 0, ABP2_TRANS_FUNC_B = 1 };
|
||||
|
||||
class HONEYWELLABP2Sensor final : public PollingComponent, public i2c::I2CDevice {
|
||||
class HONEYWELLABP2Sensor : public PollingComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
void set_pressure_sensor(sensor::Sensor *pressure_sensor) { this->pressure_sensor_ = pressure_sensor; };
|
||||
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; };
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace esphome::host {
|
||||
|
||||
class HostGPIOPin final : public InternalGPIOPin {
|
||||
class HostGPIOPin : public InternalGPIOPin {
|
||||
public:
|
||||
void set_pin(uint8_t pin) { pin_ = pin; }
|
||||
void set_inverted(bool inverted) { inverted_ = inverted; }
|
||||
|
||||
@@ -10,8 +10,8 @@ class HostPreferenceBackend final {
|
||||
public:
|
||||
explicit HostPreferenceBackend(uint32_t key) : key_(key) {}
|
||||
|
||||
bool save(const uint8_t *data, size_t len) const;
|
||||
bool load(uint8_t *data, size_t len) const;
|
||||
bool save(const uint8_t *data, size_t len);
|
||||
bool load(uint8_t *data, size_t len);
|
||||
|
||||
protected:
|
||||
uint32_t key_{};
|
||||
|
||||
@@ -14,31 +14,21 @@ static const char *const TAG = "preferences";
|
||||
void HostPreferences::setup_() {
|
||||
if (this->setup_complete_)
|
||||
return;
|
||||
const char *prefdir = getenv("ESPHOME_PREFDIR");
|
||||
std::string pref_path;
|
||||
if (prefdir != nullptr) {
|
||||
pref_path = prefdir;
|
||||
} else {
|
||||
const char *home = getenv("HOME");
|
||||
if (home == nullptr) {
|
||||
ESP_LOGE(TAG, "ESPHOME_PREFDIR and HOME environment variables not set, unable to save preferences");
|
||||
return;
|
||||
}
|
||||
pref_path = std::string(home) + "/.esphome/prefs";
|
||||
const char *home = getenv("HOME");
|
||||
if (home == nullptr) {
|
||||
ESP_LOGE(TAG, "HOME environment variable is not set");
|
||||
abort();
|
||||
}
|
||||
std::error_code ec;
|
||||
fs::create_directories(pref_path, ec);
|
||||
if (ec) {
|
||||
ESP_LOGE(TAG, "Failed to create preferences directory: %s (%s)", pref_path.c_str(), ec.message().c_str());
|
||||
return;
|
||||
}
|
||||
this->filename_ = pref_path;
|
||||
this->filename_.append(home);
|
||||
this->filename_.append("/.esphome");
|
||||
this->filename_.append("/prefs");
|
||||
fs::create_directories(this->filename_);
|
||||
this->filename_.append("/");
|
||||
this->filename_.append(App.get_name());
|
||||
this->filename_.append(".prefs");
|
||||
FILE *fp = fopen(this->filename_.c_str(), "rb");
|
||||
if (fp != nullptr) {
|
||||
while (!feof(fp)) {
|
||||
while (!feof((fp))) {
|
||||
uint32_t key;
|
||||
uint8_t len;
|
||||
if (fread(&key, sizeof(key), 1, fp) != 1)
|
||||
@@ -49,7 +39,7 @@ void HostPreferences::setup_() {
|
||||
if (fread(data, sizeof(uint8_t), len, fp) != len)
|
||||
break;
|
||||
std::vector vec(data, data + len);
|
||||
this->data_[key] = vec;
|
||||
this->data[key] = vec;
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
@@ -58,33 +48,29 @@ void HostPreferences::setup_() {
|
||||
|
||||
bool HostPreferences::sync() {
|
||||
this->setup_();
|
||||
if (this->filename_.empty()) {
|
||||
ESP_LOGE(TAG, "Preferences filename not set, unable to save preferences");
|
||||
return false;
|
||||
}
|
||||
FILE *fp = fopen(this->filename_.c_str(), "wb");
|
||||
if (fp == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to open preferences file for writing: %s", this->filename_.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto &it : this->data_) {
|
||||
fwrite(&it.first, sizeof(uint32_t), 1, fp);
|
||||
uint8_t len = it.second.size();
|
||||
for (auto it = this->data.begin(); it != this->data.end(); ++it) {
|
||||
fwrite(&it->first, sizeof(uint32_t), 1, fp);
|
||||
uint8_t len = it->second.size();
|
||||
fwrite(&len, sizeof(len), 1, fp);
|
||||
fwrite(it.second.data(), sizeof(uint8_t), it.second.size(), fp);
|
||||
fwrite(it->second.data(), sizeof(uint8_t), it->second.size(), fp);
|
||||
}
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HostPreferences::reset() {
|
||||
host_preferences->data_.clear();
|
||||
host_preferences->data.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
ESPPreferenceObject HostPreferences::make_preference(size_t length, uint32_t type, bool in_flash) {
|
||||
auto *backend = new HostPreferenceBackend(type);
|
||||
auto backend = new HostPreferenceBackend(type);
|
||||
return ESPPreferenceObject(backend);
|
||||
};
|
||||
|
||||
@@ -97,13 +83,11 @@ void setup_preferences() {
|
||||
global_preferences = &s_preferences;
|
||||
}
|
||||
|
||||
bool HostPreferenceBackend::save(const uint8_t *data, size_t len) const {
|
||||
bool HostPreferenceBackend::save(const uint8_t *data, size_t len) {
|
||||
return host_preferences->save(this->key_, data, len);
|
||||
}
|
||||
|
||||
bool HostPreferenceBackend::load(uint8_t *data, size_t len) const {
|
||||
return host_preferences->load(this->key_, data, len);
|
||||
}
|
||||
bool HostPreferenceBackend::load(uint8_t *data, size_t len) { return host_preferences->load(this->key_, data, len); }
|
||||
|
||||
HostPreferences *host_preferences; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class HostPreferences final : public PreferencesMixin<HostPreferences> {
|
||||
return false;
|
||||
this->setup_();
|
||||
std::vector vec(data, data + len);
|
||||
this->data_[key] = vec;
|
||||
this->data[key] = vec;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ class HostPreferences final : public PreferencesMixin<HostPreferences> {
|
||||
if (len > 255)
|
||||
return false;
|
||||
this->setup_();
|
||||
auto it = this->data_.find(key);
|
||||
if (it == this->data_.end())
|
||||
auto it = this->data.find(key);
|
||||
if (it == this->data.end())
|
||||
return false;
|
||||
const auto &vec = it->second;
|
||||
if (vec.size() != len)
|
||||
@@ -45,7 +45,7 @@ class HostPreferences final : public PreferencesMixin<HostPreferences> {
|
||||
void setup_();
|
||||
bool setup_complete_{};
|
||||
std::string filename_{};
|
||||
std::map<uint32_t, std::vector<uint8_t>> data_{};
|
||||
std::map<uint32_t, std::vector<uint8_t>> data{};
|
||||
};
|
||||
|
||||
void setup_preferences();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace esphome::host {
|
||||
|
||||
class HostTime final : public time::RealTimeClock {
|
||||
class HostTime : public time::RealTimeClock {
|
||||
public:
|
||||
void update() override {}
|
||||
};
|
||||
|
||||
@@ -55,7 +55,7 @@ void HrxlMaxsonarWrComponent::check_buffer_() {
|
||||
millimeters = millimeters * 10;
|
||||
}
|
||||
|
||||
float meters = float(millimeters) / 1000.0f;
|
||||
float meters = float(millimeters) / 1000.0;
|
||||
ESP_LOGV(TAG, "Distance from sensor: %d mm, %f m", millimeters, meters);
|
||||
this->publish_state(meters);
|
||||
} else {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace esphome::hrxl_maxsonar_wr {
|
||||
|
||||
class HrxlMaxsonarWrComponent final : public sensor::Sensor, public Component, public uart::UARTDevice {
|
||||
class HrxlMaxsonarWrComponent : public sensor::Sensor, public Component, public uart::UARTDevice {
|
||||
public:
|
||||
// Nothing really public.
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
namespace esphome::hte501 {
|
||||
|
||||
/// This class implements support for the hte501 of temperature i2c sensors.
|
||||
class HTE501Component final : public PollingComponent, public i2c::I2CDevice {
|
||||
class HTE501Component : public PollingComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; }
|
||||
void set_humidity_sensor(sensor::Sensor *humidity_sensor) { humidity_sensor_ = humidity_sensor; }
|
||||
|
||||
@@ -311,7 +311,7 @@ inline HttpReadResult http_read_fully(HttpContainer *container, uint8_t *buffer,
|
||||
return {HttpReadStatus::OK, 0};
|
||||
}
|
||||
|
||||
class HttpRequestResponseTrigger final : public Trigger<std::shared_ptr<HttpContainer>, std::string &> {
|
||||
class HttpRequestResponseTrigger : public Trigger<std::shared_ptr<HttpContainer>, std::string &> {
|
||||
public:
|
||||
void process(const std::shared_ptr<HttpContainer> &container, std::string &response_body) {
|
||||
this->trigger(container, response_body);
|
||||
@@ -447,7 +447,7 @@ class HttpRequestComponent : public Component {
|
||||
uint32_t watchdog_timeout_{0};
|
||||
};
|
||||
|
||||
template<typename... Ts> class HttpRequestSendAction final : public Action<Ts...> {
|
||||
template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
|
||||
public:
|
||||
HttpRequestSendAction(HttpRequestComponent *parent) : parent_(parent) {}
|
||||
TEMPLATABLE_VALUE(std::string, url)
|
||||
|
||||
@@ -46,7 +46,7 @@ class HttpContainerArduino : public HttpContainer {
|
||||
size_t chunk_remaining_{0}; ///< Bytes remaining in current chunk
|
||||
};
|
||||
|
||||
class HttpRequestArduino final : public HttpRequestComponent {
|
||||
class HttpRequestArduino : public HttpRequestComponent {
|
||||
public:
|
||||
#ifdef USE_ESP8266
|
||||
void set_tls_buffer_size_rx(uint16_t size) { this->tls_buffer_size_rx_ = size; }
|
||||
|
||||
@@ -16,7 +16,7 @@ class HttpContainerHost : public HttpContainer {
|
||||
std::vector<uint8_t> response_body_{};
|
||||
};
|
||||
|
||||
class HttpRequestHost final : public HttpRequestComponent {
|
||||
class HttpRequestHost : public HttpRequestComponent {
|
||||
public:
|
||||
std::shared_ptr<HttpContainer> perform(const std::string &url, const std::string &method, const std::string &body,
|
||||
const std::vector<Header> &request_headers,
|
||||
|
||||
@@ -26,7 +26,7 @@ class HttpContainerIDF : public HttpContainer {
|
||||
esp_http_client_handle_t client_;
|
||||
};
|
||||
|
||||
class HttpRequestIDF final : public HttpRequestComponent {
|
||||
class HttpRequestIDF : public HttpRequestComponent {
|
||||
public:
|
||||
void dump_config() override;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user