mirror of
https://github.com/esphome/esphome.git
synced 2025-04-20 13:47:18 +00:00
Compare commits
No commits in common. "dev" and "2024.6.0b2" have entirely different histories.
dev
...
2024.6.0b2
36
.clang-tidy
36
.clang-tidy
@ -7,39 +7,28 @@ Checks: >-
|
||||
-boost-*,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-bugprone-implicit-widening-of-multiplication-result,
|
||||
-bugprone-multi-level-implicit-pointer-conversion,
|
||||
-bugprone-narrowing-conversions,
|
||||
-bugprone-signed-char-misuse,
|
||||
-bugprone-switch-missing-default-case,
|
||||
-cert-dcl50-cpp,
|
||||
-cert-err33-c,
|
||||
-cert-err58-cpp,
|
||||
-cert-oop57-cpp,
|
||||
-cert-str34-c,
|
||||
-clang-analyzer-optin.core.EnumCastOutOfRange,
|
||||
-clang-analyzer-optin.cplusplus.UninitializedObject,
|
||||
-clang-analyzer-osx.*,
|
||||
-clang-diagnostic-delete-abstract-non-virtual-dtor,
|
||||
-clang-diagnostic-delete-non-abstract-non-virtual-dtor,
|
||||
-clang-diagnostic-deprecated-declarations,
|
||||
-clang-diagnostic-ignored-optimization-argument,
|
||||
-clang-diagnostic-missing-field-initializers,
|
||||
-clang-diagnostic-shadow-field,
|
||||
-clang-diagnostic-unused-const-variable,
|
||||
-clang-diagnostic-unused-parameter,
|
||||
-clang-diagnostic-vla-cxx-extension,
|
||||
-concurrency-*,
|
||||
-cppcoreguidelines-avoid-c-arrays,
|
||||
-cppcoreguidelines-avoid-const-or-ref-data-members,
|
||||
-cppcoreguidelines-avoid-do-while,
|
||||
-cppcoreguidelines-avoid-magic-numbers,
|
||||
-cppcoreguidelines-init-variables,
|
||||
-cppcoreguidelines-macro-to-enum,
|
||||
-cppcoreguidelines-macro-usage,
|
||||
-cppcoreguidelines-missing-std-forward,
|
||||
-cppcoreguidelines-narrowing-conversions,
|
||||
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||
-cppcoreguidelines-owning-memory,
|
||||
-cppcoreguidelines-prefer-member-initializer,
|
||||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||
-cppcoreguidelines-pro-bounds-constant-array-index,
|
||||
@ -51,9 +40,7 @@ Checks: >-
|
||||
-cppcoreguidelines-pro-type-static-cast-downcast,
|
||||
-cppcoreguidelines-pro-type-union-access,
|
||||
-cppcoreguidelines-pro-type-vararg,
|
||||
-cppcoreguidelines-rvalue-reference-param-not-moved,
|
||||
-cppcoreguidelines-special-member-functions,
|
||||
-cppcoreguidelines-use-default-member-init,
|
||||
-cppcoreguidelines-virtual-class-destructor,
|
||||
-fuchsia-multiple-inheritance,
|
||||
-fuchsia-overloaded-operator,
|
||||
@ -73,32 +60,20 @@ Checks: >-
|
||||
-llvm-include-order,
|
||||
-llvm-qualified-auto,
|
||||
-llvmlibc-*,
|
||||
-misc-const-correctness,
|
||||
-misc-include-cleaner,
|
||||
-misc-no-recursion,
|
||||
-misc-non-private-member-variables-in-classes,
|
||||
-misc-no-recursion,
|
||||
-misc-unused-parameters,
|
||||
-misc-use-anonymous-namespace,
|
||||
-modernize-avoid-bind,
|
||||
-modernize-avoid-c-arrays,
|
||||
-modernize-avoid-bind,
|
||||
-modernize-concat-nested-namespaces,
|
||||
-modernize-macro-to-enum,
|
||||
-modernize-return-braced-init-list,
|
||||
-modernize-type-traits,
|
||||
-modernize-use-auto,
|
||||
-modernize-use-constraints,
|
||||
-modernize-use-default-member-init,
|
||||
-modernize-use-equals-default,
|
||||
-modernize-use-nodiscard,
|
||||
-modernize-use-nullptr,
|
||||
-modernize-use-nodiscard,
|
||||
-modernize-use-nullptr,
|
||||
-modernize-use-trailing-return-type,
|
||||
-modernize-use-nodiscard,
|
||||
-mpi-*,
|
||||
-objc-*,
|
||||
-performance-enum-size,
|
||||
-readability-avoid-nested-conditional-operator,
|
||||
-readability-container-contains,
|
||||
-readability-container-data-pointer,
|
||||
-readability-convert-member-functions-to-static,
|
||||
-readability-else-after-return,
|
||||
@ -107,14 +82,11 @@ Checks: >-
|
||||
-readability-isolate-declaration,
|
||||
-readability-magic-numbers,
|
||||
-readability-make-member-function-const,
|
||||
-readability-named-parameter,
|
||||
-readability-redundant-casting,
|
||||
-readability-redundant-inline-specifier,
|
||||
-readability-redundant-member-init,
|
||||
-readability-redundant-string-init,
|
||||
-readability-uppercase-literal-suffix,
|
||||
-readability-use-anyofallof,
|
||||
WarningsAsErrors: '*'
|
||||
AnalyzeTemporaryDtors: false
|
||||
FormatStyle: google
|
||||
CheckOptions:
|
||||
- key: google-readability-function-size.StatementThreshold
|
||||
|
@ -1,9 +1,7 @@
|
||||
{
|
||||
"name": "ESPHome Dev",
|
||||
"image": "ghcr.io/esphome/esphome-lint:dev",
|
||||
"postCreateCommand": [
|
||||
"script/devcontainer-post-create"
|
||||
],
|
||||
"postCreateCommand": ["script/devcontainer-post-create"],
|
||||
"containerEnv": {
|
||||
"DEVCONTAINER": "1",
|
||||
"PIP_BREAK_SYSTEM_PACKAGES": "1",
|
||||
@ -29,9 +27,6 @@
|
||||
"extensions": [
|
||||
// python
|
||||
"ms-python.python",
|
||||
"ms-python.pylint",
|
||||
"ms-python.flake8",
|
||||
"charliermarsh.ruff",
|
||||
"visualstudioexptteam.vscodeintellicode",
|
||||
// yaml
|
||||
"redhat.vscode-yaml",
|
||||
@ -43,18 +38,9 @@
|
||||
"settings": {
|
||||
"python.languageServer": "Pylance",
|
||||
"python.pythonPath": "/usr/bin/python3",
|
||||
"pylint.args": [
|
||||
"--rcfile=${workspaceFolder}/pyproject.toml"
|
||||
],
|
||||
"flake8.args": [
|
||||
"--config=${workspaceFolder}/.flake8"
|
||||
],
|
||||
"ruff.configuration": "${workspaceFolder}/pyproject.toml",
|
||||
"[python]": {
|
||||
// VS will say "Value is not accepted" before building the devcontainer, but the warning
|
||||
// should go away after build is completed.
|
||||
"editor.defaultFormatter": "charliermarsh.ruff"
|
||||
},
|
||||
"python.linting.pylintEnabled": true,
|
||||
"python.linting.enabled": true,
|
||||
"python.formatting.provider": "black",
|
||||
"editor.formatOnPaste": false,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnType": true,
|
||||
|
@ -75,9 +75,6 @@ target/
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# asdf
|
||||
.tool-versions
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
|
4
.github/FUNDING.yml
vendored
Normal file
4
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
---
|
||||
# These are supported funding model platforms
|
||||
|
||||
custom: https://www.nabucasa.com
|
15
.github/PULL_REQUEST_TEMPLATE.md
vendored
15
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -7,16 +7,11 @@
|
||||
- [ ] Bugfix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] Code quality improvements to existing code or addition of tests
|
||||
- [ ] Other
|
||||
|
||||
**Related issue or feature (if applicable):**
|
||||
**Related issue or feature (if applicable):** fixes <link to issue>
|
||||
|
||||
- fixes <link to issue>
|
||||
|
||||
**Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):**
|
||||
|
||||
- esphome/esphome-docs#<esphome-docs PR number goes here>
|
||||
**Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):** esphome/esphome-docs#<esphome-docs PR number goes here>
|
||||
|
||||
## Test Environment
|
||||
|
||||
@ -28,6 +23,12 @@
|
||||
- [ ] RTL87xx
|
||||
|
||||
## Example entry for `config.yaml`:
|
||||
<!--
|
||||
Supplying a configuration snippet, makes it easier for a maintainer to test
|
||||
your PR. Furthermore, for new integrations, it gives an impression of how
|
||||
the configuration would look like.
|
||||
Note: Remove this section if this PR does not have an example entry.
|
||||
-->
|
||||
|
||||
```yaml
|
||||
# Example config.yaml
|
||||
|
10
.github/actions/build-image/action.yaml
vendored
10
.github/actions/build-image/action.yaml
vendored
@ -46,10 +46,7 @@ runs:
|
||||
|
||||
- name: Build and push to ghcr by digest
|
||||
id: build-ghcr
|
||||
uses: docker/build-push-action@v6.15.0
|
||||
env:
|
||||
DOCKER_BUILD_SUMMARY: false
|
||||
DOCKER_BUILD_RECORD_UPLOAD: false
|
||||
uses: docker/build-push-action@v5.4.0
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
@ -72,10 +69,7 @@ runs:
|
||||
|
||||
- name: Build and push to dockerhub by digest
|
||||
id: build-dockerhub
|
||||
uses: docker/build-push-action@v6.15.0
|
||||
env:
|
||||
DOCKER_BUILD_SUMMARY: false
|
||||
DOCKER_BUILD_RECORD_UPLOAD: false
|
||||
uses: docker/build-push-action@v5.4.0
|
||||
with:
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
|
4
.github/actions/restore-python/action.yml
vendored
4
.github/actions/restore-python/action.yml
vendored
@ -17,12 +17,12 @@ runs:
|
||||
steps:
|
||||
- name: Set up Python ${{ inputs.python-version }}
|
||||
id: python
|
||||
uses: actions/setup-python@v5.5.0
|
||||
uses: actions/setup-python@v5.1.0
|
||||
with:
|
||||
python-version: ${{ inputs.python-version }}
|
||||
- name: Restore Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.3
|
||||
uses: actions/cache/restore@v4.0.2
|
||||
with:
|
||||
path: venv
|
||||
# yamllint disable-line rule:line-length
|
||||
|
7
.github/dependabot.yml
vendored
7
.github/dependabot.yml
vendored
@ -13,13 +13,6 @@ updates:
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
groups:
|
||||
docker-actions:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "docker/setup-qemu-action"
|
||||
- "docker/login-action"
|
||||
- "docker/setup-buildx-action"
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/.github/actions/build-image"
|
||||
schedule:
|
||||
|
4
.github/workflows/ci-api-proto.yml
vendored
4
.github/workflows/ci-api-proto.yml
vendored
@ -21,9 +21,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5.5.0
|
||||
uses: actions/setup-python@v5.1.0
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
|
14
.github/workflows/ci-docker.yml
vendored
14
.github/workflows/ci-docker.yml
vendored
@ -33,20 +33,22 @@ concurrency:
|
||||
jobs:
|
||||
check-docker:
|
||||
name: Build docker containers
|
||||
runs-on: ${{ matrix.os }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: ["ubuntu-latest", "ubuntu-24.04-arm"]
|
||||
arch: [amd64, armv7, aarch64]
|
||||
build_type: ["ha-addon", "docker", "lint"]
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.7
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5.5.0
|
||||
uses: actions/setup-python@v5.1.0
|
||||
with:
|
||||
python-version: "3.9"
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.10.0
|
||||
uses: docker/setup-buildx-action@v3.3.0
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3.0.0
|
||||
|
||||
- name: Set TAG
|
||||
run: |
|
||||
@ -56,6 +58,6 @@ jobs:
|
||||
run: |
|
||||
docker/build.py \
|
||||
--tag "${TAG}" \
|
||||
--arch "${{ matrix.os == 'ubuntu-24.04-arm' && 'aarch64' || 'amd64' }}" \
|
||||
--arch "${{ matrix.arch }}" \
|
||||
--build-type "${{ matrix.build_type }}" \
|
||||
build
|
||||
|
167
.github/workflows/ci.yml
vendored
167
.github/workflows/ci.yml
vendored
@ -9,11 +9,9 @@ on:
|
||||
paths:
|
||||
- "**"
|
||||
- "!.github/workflows/*.yml"
|
||||
- "!.github/actions/build-image/*"
|
||||
- ".github/workflows/ci.yml"
|
||||
- "!.yamllint"
|
||||
- "!.github/dependabot.yml"
|
||||
- "!docker/**"
|
||||
merge_group:
|
||||
|
||||
permissions:
|
||||
@ -31,23 +29,23 @@ concurrency:
|
||||
jobs:
|
||||
common:
|
||||
name: Create common environment
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
cache-key: ${{ steps.cache-key.outputs.key }}
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Generate cache-key
|
||||
id: cache-key
|
||||
run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
id: python
|
||||
uses: actions/setup-python@v5.5.0
|
||||
uses: actions/setup-python@v5.1.0
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
- name: Restore Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v4.2.3
|
||||
uses: actions/cache@v4.0.2
|
||||
with:
|
||||
path: venv
|
||||
# yamllint disable-line rule:line-length
|
||||
@ -61,35 +59,35 @@ jobs:
|
||||
pip install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt
|
||||
pip install -e .
|
||||
|
||||
ruff:
|
||||
name: Check ruff
|
||||
runs-on: ubuntu-24.04
|
||||
black:
|
||||
name: Check black
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Restore Python
|
||||
uses: ./.github/actions/restore-python
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
cache-key: ${{ needs.common.outputs.cache-key }}
|
||||
- name: Run Ruff
|
||||
- name: Run black
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
ruff format esphome tests
|
||||
black --verbose esphome tests
|
||||
- name: Suggested changes
|
||||
run: script/ci-suggest-changes
|
||||
if: always()
|
||||
|
||||
flake8:
|
||||
name: Check flake8
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Restore Python
|
||||
uses: ./.github/actions/restore-python
|
||||
with:
|
||||
@ -105,12 +103,12 @@ jobs:
|
||||
|
||||
pylint:
|
||||
name: Check pylint
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Restore Python
|
||||
uses: ./.github/actions/restore-python
|
||||
with:
|
||||
@ -126,12 +124,12 @@ jobs:
|
||||
|
||||
pyupgrade:
|
||||
name: Check pyupgrade
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Restore Python
|
||||
uses: ./.github/actions/restore-python
|
||||
with:
|
||||
@ -147,12 +145,12 @@ jobs:
|
||||
|
||||
ci-custom:
|
||||
name: Run script/ci-custom
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Restore Python
|
||||
uses: ./.github/actions/restore-python
|
||||
with:
|
||||
@ -201,7 +199,7 @@ jobs:
|
||||
- common
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Restore Python
|
||||
uses: ./.github/actions/restore-python
|
||||
with:
|
||||
@ -220,18 +218,18 @@ jobs:
|
||||
. venv/bin/activate
|
||||
pytest -vv --cov-report=xml --tb=native tests
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v5.4.2
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
clang-format:
|
||||
name: Check clang-format
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Restore Python
|
||||
uses: ./.github/actions/restore-python
|
||||
with:
|
||||
@ -250,12 +248,78 @@ jobs:
|
||||
run: script/ci-suggest-changes
|
||||
if: always()
|
||||
|
||||
clang-tidy:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ubuntu-24.04
|
||||
compile-tests-list:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Find all YAML test files
|
||||
id: set-matrix
|
||||
run: echo "matrix=$(ls tests/test*.yaml | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT
|
||||
|
||||
validate-tests:
|
||||
name: Validate YAML test ${{ matrix.file }}
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
- ruff
|
||||
- compile-tests-list
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }}
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Restore Python
|
||||
uses: ./.github/actions/restore-python
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
cache-key: ${{ needs.common.outputs.cache-key }}
|
||||
- name: Run esphome config ${{ matrix.file }}
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
esphome config ${{ matrix.file }}
|
||||
|
||||
compile-tests:
|
||||
name: Run YAML test ${{ matrix.file }}
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
- black
|
||||
- ci-custom
|
||||
- clang-format
|
||||
- flake8
|
||||
- pylint
|
||||
- pytest
|
||||
- pyupgrade
|
||||
- compile-tests-list
|
||||
- validate-tests
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 2
|
||||
matrix:
|
||||
file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }}
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Restore Python
|
||||
uses: ./.github/actions/restore-python
|
||||
with:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
cache-key: ${{ needs.common.outputs.cache-key }}
|
||||
- name: Run esphome compile ${{ matrix.file }}
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
esphome compile ${{ matrix.file }}
|
||||
|
||||
clang-tidy:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
- black
|
||||
- ci-custom
|
||||
- clang-format
|
||||
- flake8
|
||||
@ -294,7 +358,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Restore Python
|
||||
uses: ./.github/actions/restore-python
|
||||
with:
|
||||
@ -303,30 +367,26 @@ jobs:
|
||||
|
||||
- name: Cache platformio
|
||||
if: github.ref == 'refs/heads/dev'
|
||||
uses: actions/cache@v4.2.3
|
||||
uses: actions/cache@v4.0.2
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: platformio-${{ matrix.pio_cache_key }}
|
||||
|
||||
- name: Cache platformio
|
||||
if: github.ref != 'refs/heads/dev'
|
||||
uses: actions/cache/restore@v4.2.3
|
||||
uses: actions/cache/restore@v4.0.2
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: platformio-${{ matrix.pio_cache_key }}
|
||||
|
||||
- name: Install clang-tidy
|
||||
run: sudo apt-get install clang-tidy-14
|
||||
|
||||
- name: Register problem matchers
|
||||
run: |
|
||||
echo "::add-matcher::.github/workflows/matchers/gcc.json"
|
||||
echo "::add-matcher::.github/workflows/matchers/clang-tidy.json"
|
||||
|
||||
- name: Run 'pio run --list-targets -e esp32-idf-tidy'
|
||||
if: matrix.name == 'Run script/clang-tidy for ESP32 IDF'
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
mkdir -p .temp
|
||||
pio run --list-targets -e esp32-idf-tidy
|
||||
|
||||
- name: Run clang-tidy
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
@ -341,7 +401,7 @@ jobs:
|
||||
if: always()
|
||||
|
||||
list-components:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
if: github.event_name == 'pull_request'
|
||||
@ -350,7 +410,7 @@ jobs:
|
||||
count: ${{ steps.list-components.outputs.count }}
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
# Fetch enough history so `git merge-base refs/remotes/origin/dev HEAD` works.
|
||||
fetch-depth: 500
|
||||
@ -383,7 +443,7 @@ jobs:
|
||||
|
||||
test-build-components:
|
||||
name: Component test ${{ matrix.file }}
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
- list-components
|
||||
@ -395,12 +455,10 @@ jobs:
|
||||
file: ${{ fromJson(needs.list-components.outputs.components) }}
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install libsdl2-dev
|
||||
run: sudo apt-get install libsodium-dev libsdl2-dev
|
||||
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Restore Python
|
||||
uses: ./.github/actions/restore-python
|
||||
with:
|
||||
@ -417,7 +475,7 @@ jobs:
|
||||
|
||||
test-build-components-splitter:
|
||||
name: Split components for testing into 20 groups maximum
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
- list-components
|
||||
@ -426,7 +484,7 @@ jobs:
|
||||
matrix: ${{ steps.split.outputs.components }}
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Split components into 20 groups
|
||||
id: split
|
||||
run: |
|
||||
@ -435,7 +493,7 @@ jobs:
|
||||
|
||||
test-build-components-split:
|
||||
name: Test split components
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
- list-components
|
||||
@ -451,12 +509,10 @@ jobs:
|
||||
run: echo ${{ matrix.components }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install libsdl2-dev
|
||||
run: sudo apt-get install libsodium-dev libsdl2-dev
|
||||
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Restore Python
|
||||
uses: ./.github/actions/restore-python
|
||||
with:
|
||||
@ -471,24 +527,23 @@ jobs:
|
||||
- name: Compile config
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
mkdir build_cache
|
||||
export PLATFORMIO_BUILD_CACHE_DIR=$PWD/build_cache
|
||||
for component in ${{ matrix.components }}; do
|
||||
./script/test_build_components -e compile -c $component
|
||||
done
|
||||
|
||||
ci-status:
|
||||
name: CI Status
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
- ruff
|
||||
- black
|
||||
- ci-custom
|
||||
- clang-format
|
||||
- flake8
|
||||
- pylint
|
||||
- pytest
|
||||
- pyupgrade
|
||||
- compile-tests
|
||||
- clang-tidy
|
||||
- list-components
|
||||
- test-build-components
|
||||
|
91
.github/workflows/codeql.yml
vendored
91
.github/workflows/codeql.yml
vendored
@ -1,91 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL Advanced"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: "30 18 * * 4"
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze (${{ matrix.language }})
|
||||
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
||||
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
||||
# - https://gh.io/supported-runners-and-hardware-resources
|
||||
# - https://gh.io/using-larger-runners (GitHub.com only)
|
||||
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
|
||||
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
|
||||
permissions:
|
||||
# required for all workflows
|
||||
security-events: write
|
||||
|
||||
# required to fetch internal or private CodeQL packs
|
||||
packages: read
|
||||
|
||||
# only required for workflows in private repositories
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# - language: c-cpp
|
||||
# build-mode: autobuild
|
||||
- language: python
|
||||
build-mode: none
|
||||
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
|
||||
# Use `c-cpp` to analyze code written in C, C++ or both
|
||||
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
|
||||
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
|
||||
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
|
||||
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
|
||||
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
|
||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
# If the analyze step fails for one of the languages you are analyzing with
|
||||
# "We were unable to automatically build your code", modify the matrix above
|
||||
# to set the build mode to "manual" for that language. Then modify this step
|
||||
# to build your code.
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
- if: matrix.build-mode == 'manual'
|
||||
shell: bash
|
||||
run: |
|
||||
echo 'If you are using a "manual" build mode for one or more of the' \
|
||||
'languages you are analyzing, replace this with the commands to build' \
|
||||
'your code, for example:'
|
||||
echo ' make bootstrap'
|
||||
echo ' make release'
|
||||
exit 1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
4
.github/workflows/matchers/lint-python.json
vendored
4
.github/workflows/matchers/lint-python.json
vendored
@ -1,11 +1,11 @@
|
||||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "ruff",
|
||||
"owner": "black",
|
||||
"severity": "error",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^(.*): (Please format this file with the ruff formatter)",
|
||||
"regexp": "^(.*): (Please format this file with the black formatter)",
|
||||
"file": 1,
|
||||
"message": 2
|
||||
}
|
||||
|
33
.github/workflows/release.yml
vendored
33
.github/workflows/release.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
||||
tag: ${{ steps.tag.outputs.tag }}
|
||||
branch_build: ${{ steps.tag.outputs.branch_build }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.7
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Get tag
|
||||
id: tag
|
||||
# yamllint disable rule:line-length
|
||||
@ -51,9 +51,9 @@ jobs:
|
||||
contents: read
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.7
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5.5.0
|
||||
uses: actions/setup-python@v5.1.0
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- name: Set up python environment
|
||||
@ -65,7 +65,7 @@ jobs:
|
||||
pip3 install build
|
||||
python3 -m build
|
||||
- name: Publish
|
||||
uses: pypa/gh-action-pypi-publish@v1.12.4
|
||||
uses: pypa/gh-action-pypi-publish@v1.8.14
|
||||
|
||||
deploy-docker:
|
||||
name: Build ESPHome ${{ matrix.platform }}
|
||||
@ -80,27 +80,28 @@ jobs:
|
||||
matrix:
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm/v7
|
||||
- linux/arm64
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.7
|
||||
- uses: actions/checkout@v4.1.6
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5.5.0
|
||||
uses: actions/setup-python@v5.1.0
|
||||
with:
|
||||
python-version: "3.9"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.10.0
|
||||
uses: docker/setup-buildx-action@v3.3.0
|
||||
- name: Set up QEMU
|
||||
if: matrix.platform != 'linux/amd64'
|
||||
uses: docker/setup-qemu-action@v3.6.0
|
||||
uses: docker/setup-qemu-action@v3.0.0
|
||||
|
||||
- name: Log in to docker hub
|
||||
uses: docker/login-action@v3.4.0
|
||||
uses: docker/login-action@v3.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USER }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Log in to the GitHub container registry
|
||||
uses: docker/login-action@v3.4.0
|
||||
uses: docker/login-action@v3.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@ -140,7 +141,7 @@ jobs:
|
||||
echo name=$(cat /tmp/platform) >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Upload digests
|
||||
uses: actions/upload-artifact@v4.6.2
|
||||
uses: actions/upload-artifact@v4.3.3
|
||||
with:
|
||||
name: digests-${{ steps.sanitize.outputs.name }}
|
||||
path: /tmp/digests
|
||||
@ -173,27 +174,27 @@ jobs:
|
||||
- ghcr
|
||||
- dockerhub
|
||||
steps:
|
||||
- uses: actions/checkout@v4.1.7
|
||||
- uses: actions/checkout@v4.1.6
|
||||
|
||||
- name: Download digests
|
||||
uses: actions/download-artifact@v4.2.1
|
||||
uses: actions/download-artifact@v4.1.7
|
||||
with:
|
||||
pattern: digests-*
|
||||
path: /tmp/digests
|
||||
merge-multiple: true
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.10.0
|
||||
uses: docker/setup-buildx-action@v3.3.0
|
||||
|
||||
- name: Log in to docker hub
|
||||
if: matrix.registry == 'dockerhub'
|
||||
uses: docker/login-action@v3.4.0
|
||||
uses: docker/login-action@v3.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USER }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Log in to the GitHub container registry
|
||||
if: matrix.registry == 'ghcr'
|
||||
uses: docker/login-action@v3.4.0
|
||||
uses: docker/login-action@v3.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
4
.github/workflows/stale.yml
vendored
4
.github/workflows/stale.yml
vendored
@ -17,7 +17,7 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v9.1.0
|
||||
- uses: actions/stale@v9.0.0
|
||||
with:
|
||||
days-before-pr-stale: 90
|
||||
days-before-pr-close: 7
|
||||
@ -37,7 +37,7 @@ jobs:
|
||||
close-issues:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v9.1.0
|
||||
- uses: actions/stale@v9.0.0
|
||||
with:
|
||||
days-before-pr-stale: -1
|
||||
days-before-pr-close: -1
|
||||
|
12
.github/workflows/sync-device-classes.yml
vendored
12
.github/workflows/sync-device-classes.yml
vendored
@ -13,16 +13,16 @@ jobs:
|
||||
if: github.repository == 'esphome/esphome'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
|
||||
- name: Checkout Home Assistant
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
with:
|
||||
repository: home-assistant/core
|
||||
path: lib/home-assistant
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5.5.0
|
||||
uses: actions/setup-python@v5.1.0
|
||||
with:
|
||||
python-version: 3.12
|
||||
|
||||
@ -36,11 +36,11 @@ jobs:
|
||||
python ./script/sync-device_class.py
|
||||
|
||||
- name: Commit changes
|
||||
uses: peter-evans/create-pull-request@v7.0.8
|
||||
uses: peter-evans/create-pull-request@v6.0.5
|
||||
with:
|
||||
commit-message: "Synchronise Device Classes from Home Assistant"
|
||||
committer: esphomebot <esphome@openhomefoundation.org>
|
||||
author: esphomebot <esphome@openhomefoundation.org>
|
||||
committer: esphomebot <esphome@nabucasa.com>
|
||||
author: esphomebot <esphome@nabucasa.com>
|
||||
branch: sync/device-classes
|
||||
delete-branch: true
|
||||
title: "Synchronise Device Classes from Home Assistant"
|
||||
|
2
.github/workflows/yaml-lint.yml
vendored
2
.github/workflows/yaml-lint.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: actions/checkout@v4.1.7
|
||||
uses: actions/checkout@v4.1.6
|
||||
- name: Run yamllint
|
||||
uses: frenck/action-yamllint@v1.5.0
|
||||
with:
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -75,9 +75,6 @@ cov.xml
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# asdf
|
||||
.tool-versions
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
@ -141,5 +138,3 @@ sdkconfig.*
|
||||
.tests/
|
||||
|
||||
/components
|
||||
/managed_components
|
||||
|
||||
|
@ -2,21 +2,20 @@
|
||||
# See https://pre-commit.com for more information
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.11.0
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 24.4.2
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff
|
||||
args: [--fix]
|
||||
# Run the formatter.
|
||||
- id: ruff-format
|
||||
- id: black
|
||||
args:
|
||||
- --safe
|
||||
- --quiet
|
||||
files: ^((esphome|script|tests)/.+)?[^/]+\.py$
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 7.2.0
|
||||
rev: 6.1.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies:
|
||||
- flake8-docstrings==1.7.0
|
||||
- flake8-docstrings==1.5.0
|
||||
- pydocstyle==5.1.1
|
||||
files: ^(esphome|tests)/.+\.py$
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
@ -45,6 +44,6 @@ repos:
|
||||
hooks:
|
||||
- id: pylint
|
||||
name: pylint
|
||||
entry: python3 script/run-in-env.py pylint
|
||||
language: system
|
||||
entry: script/run-in-env.sh pylint
|
||||
language: script
|
||||
types: [python]
|
||||
|
73
CODEOWNERS
73
CODEOWNERS
@ -24,7 +24,6 @@ esphome/components/ade7953_i2c/* @angelnu
|
||||
esphome/components/ade7953_spi/* @angelnu
|
||||
esphome/components/ads1118/* @solomondg1
|
||||
esphome/components/ags10/* @mak-42
|
||||
esphome/components/aic3204/* @kbx81
|
||||
esphome/components/airthings_ble/* @jeromelaban
|
||||
esphome/components/airthings_wave_base/* @jeromelaban @kpfleming @ncareau
|
||||
esphome/components/airthings_wave_mini/* @ncareau
|
||||
@ -38,7 +37,6 @@ esphome/components/am43/sensor/* @buxtronix
|
||||
esphome/components/analog_threshold/* @ianchi
|
||||
esphome/components/animation/* @syndlex
|
||||
esphome/components/anova/* @buxtronix
|
||||
esphome/components/apds9306/* @aodrenah
|
||||
esphome/components/api/* @OttoWinter
|
||||
esphome/components/as5600/* @ammmze
|
||||
esphome/components/as5600/sensor/* @ammmze
|
||||
@ -47,11 +45,6 @@ esphome/components/async_tcp/* @OttoWinter
|
||||
esphome/components/at581x/* @X-Ryl669
|
||||
esphome/components/atc_mithermometer/* @ahpohl
|
||||
esphome/components/atm90e26/* @danieltwagner
|
||||
esphome/components/atm90e32/* @circuitsetup @descipher
|
||||
esphome/components/audio/* @kahrendt
|
||||
esphome/components/audio_adc/* @kbx81
|
||||
esphome/components/audio_dac/* @kbx81
|
||||
esphome/components/axs15231/* @clydebarrow
|
||||
esphome/components/b_parasite/* @rbaron
|
||||
esphome/components/ballu/* @bazuchan
|
||||
esphome/components/bang_bang/* @OttoWinter
|
||||
@ -63,21 +56,15 @@ esphome/components/beken_spi_led_strip/* @Mat931
|
||||
esphome/components/bh1750/* @OttoWinter
|
||||
esphome/components/binary_sensor/* @esphome/core
|
||||
esphome/components/bk72xx/* @kuba2k2
|
||||
esphome/components/bl0906/* @athom-tech @jesserockz @tarontop
|
||||
esphome/components/bl0939/* @ziceva
|
||||
esphome/components/bl0940/* @tobias-
|
||||
esphome/components/bl0942/* @dbuezas @dwmw2
|
||||
esphome/components/bl0942/* @dbuezas
|
||||
esphome/components/ble_client/* @buxtronix @clydebarrow
|
||||
esphome/components/bluetooth_proxy/* @jesserockz
|
||||
esphome/components/bme280_base/* @esphome/core
|
||||
esphome/components/bme280_spi/* @apbodrov
|
||||
esphome/components/bme680_bsec/* @trvrnrth
|
||||
esphome/components/bme68x_bsec2/* @kbx81 @neffs
|
||||
esphome/components/bme68x_bsec2_i2c/* @kbx81 @neffs
|
||||
esphome/components/bmi160/* @flaviut
|
||||
esphome/components/bmp280_base/* @ademuri
|
||||
esphome/components/bmp280_i2c/* @ademuri
|
||||
esphome/components/bmp280_spi/* @ademuri
|
||||
esphome/components/bmp3xx/* @latonita
|
||||
esphome/components/bmp3xx_base/* @latonita @martgras
|
||||
esphome/components/bmp3xx_i2c/* @latonita
|
||||
@ -86,14 +73,11 @@ esphome/components/bmp581/* @kahrendt
|
||||
esphome/components/bp1658cj/* @Cossid
|
||||
esphome/components/bp5758d/* @Cossid
|
||||
esphome/components/button/* @esphome/core
|
||||
esphome/components/bytebuffer/* @clydebarrow
|
||||
esphome/components/canbus/* @danielschramm @mvturnho
|
||||
esphome/components/cap1188/* @mreditor97
|
||||
esphome/components/captive_portal/* @OttoWinter
|
||||
esphome/components/ccs811/* @habbie
|
||||
esphome/components/cd74hc4067/* @asoehlke
|
||||
esphome/components/ch422g/* @clydebarrow @jesterret
|
||||
esphome/components/chsc6x/* @kkosik20
|
||||
esphome/components/climate/* @esphome/core
|
||||
esphome/components/climate_ir/* @glmnet
|
||||
esphome/components/color_temperature/* @jesserockz
|
||||
@ -133,10 +117,6 @@ esphome/components/ens160_base/* @latonita @vincentscode
|
||||
esphome/components/ens160_i2c/* @latonita
|
||||
esphome/components/ens160_spi/* @latonita
|
||||
esphome/components/ens210/* @itn3rd77
|
||||
esphome/components/es7210/* @kahrendt
|
||||
esphome/components/es7243e/* @kbx81
|
||||
esphome/components/es8156/* @kbx81
|
||||
esphome/components/es8311/* @kahrendt @kroimon
|
||||
esphome/components/esp32/* @esphome/core
|
||||
esphome/components/esp32_ble/* @Rapsssito @jesserockz
|
||||
esphome/components/esp32_ble_client/* @jesserockz
|
||||
@ -149,7 +129,6 @@ esphome/components/esp32_rmt_led_strip/* @jesserockz
|
||||
esphome/components/esp8266/* @esphome/core
|
||||
esphome/components/ethernet_info/* @gtjadsonsantos
|
||||
esphome/components/event/* @nohat
|
||||
esphome/components/event_emitter/* @Rapsssito
|
||||
esphome/components/exposure_notifications/* @OttoWinter
|
||||
esphome/components/ezo/* @ssieb
|
||||
esphome/components/ezo_pmp/* @carlos-sarmiento
|
||||
@ -164,7 +143,6 @@ esphome/components/ft63x6/* @gpambrozio
|
||||
esphome/components/gcja5/* @gcormier
|
||||
esphome/components/gdk101/* @Szewcson
|
||||
esphome/components/globals/* @esphome/core
|
||||
esphome/components/gp2y1010au0f/* @zry98
|
||||
esphome/components/gp8403/* @jesserockz
|
||||
esphome/components/gpio/* @esphome/core
|
||||
esphome/components/gpio/one_wire/* @ssieb
|
||||
@ -172,7 +150,6 @@ esphome/components/gps/* @coogle
|
||||
esphome/components/graph/* @synco
|
||||
esphome/components/graphical_display_menu/* @MrMDavidson
|
||||
esphome/components/gree/* @orestismers
|
||||
esphome/components/grove_gas_mc_v2/* @YorkshireIoT
|
||||
esphome/components/grove_tb6612fng/* @max246
|
||||
esphome/components/growatt_solar/* @leeuwte
|
||||
esphome/components/gt911/* @clydebarrow @jesserockz
|
||||
@ -180,20 +157,15 @@ esphome/components/haier/* @paveldn
|
||||
esphome/components/haier/binary_sensor/* @paveldn
|
||||
esphome/components/haier/button/* @paveldn
|
||||
esphome/components/haier/sensor/* @paveldn
|
||||
esphome/components/haier/switch/* @paveldn
|
||||
esphome/components/haier/text_sensor/* @paveldn
|
||||
esphome/components/havells_solar/* @sourabhjaiswal
|
||||
esphome/components/hbridge/fan/* @WeekendWarrior
|
||||
esphome/components/hbridge/light/* @DotNetDann
|
||||
esphome/components/hbridge/switch/* @dwmw2
|
||||
esphome/components/he60r/* @clydebarrow
|
||||
esphome/components/heatpumpir/* @rob-deutsch
|
||||
esphome/components/hitachi_ac424/* @sourabhjaiswal
|
||||
esphome/components/hm3301/* @freekode
|
||||
esphome/components/hmac_md5/* @dwmw2
|
||||
esphome/components/homeassistant/* @OttoWinter @esphome/core
|
||||
esphome/components/homeassistant/number/* @landonr
|
||||
esphome/components/homeassistant/switch/* @Links2004
|
||||
esphome/components/homeassistant/* @OttoWinter
|
||||
esphome/components/honeywell_hih_i2c/* @Benichou34
|
||||
esphome/components/honeywellabp/* @RubyBailey
|
||||
esphome/components/honeywellabp2_i2c/* @jpfaff
|
||||
@ -207,11 +179,10 @@ esphome/components/htu31d/* @betterengineering
|
||||
esphome/components/hydreon_rgxx/* @functionpointer
|
||||
esphome/components/hyt271/* @Philippe12
|
||||
esphome/components/i2c/* @esphome/core
|
||||
esphome/components/i2c_device/* @gabest11
|
||||
esphome/components/i2s_audio/* @jesserockz
|
||||
esphome/components/i2s_audio/media_player/* @jesserockz
|
||||
esphome/components/i2s_audio/microphone/* @jesserockz
|
||||
esphome/components/i2s_audio/speaker/* @jesserockz @kahrendt
|
||||
esphome/components/i2s_audio/speaker/* @jesserockz
|
||||
esphome/components/iaqcore/* @yozik04
|
||||
esphome/components/ili9xxx/* @clydebarrow @nielsnl68
|
||||
esphome/components/improv_base/* @esphome/core
|
||||
@ -235,7 +206,6 @@ esphome/components/kuntze/* @ssieb
|
||||
esphome/components/lcd_menu/* @numo68
|
||||
esphome/components/ld2410/* @regevbr @sebcaps
|
||||
esphome/components/ld2420/* @descipher
|
||||
esphome/components/ld2450/* @hareeshmu
|
||||
esphome/components/ledc/* @OttoWinter
|
||||
esphome/components/libretiny/* @kuba2k2
|
||||
esphome/components/libretiny_pwm/* @kuba2k2
|
||||
@ -244,15 +214,9 @@ esphome/components/lightwaverf/* @max246
|
||||
esphome/components/lilygo_t5_47/touchscreen/* @jesserockz
|
||||
esphome/components/lock/* @esphome/core
|
||||
esphome/components/logger/* @esphome/core
|
||||
esphome/components/logger/select/* @clydebarrow
|
||||
esphome/components/ltr390/* @latonita @sjtrny
|
||||
esphome/components/ltr501/* @latonita
|
||||
esphome/components/ltr390/* @sjtrny
|
||||
esphome/components/ltr_als_ps/* @latonita
|
||||
esphome/components/lvgl/* @clydebarrow
|
||||
esphome/components/m5stack_8angle/* @rnauber
|
||||
esphome/components/mapping/* @clydebarrow
|
||||
esphome/components/matrix_keypad/* @ssieb
|
||||
esphome/components/max17043/* @blacknell
|
||||
esphome/components/max31865/* @DAVe3283
|
||||
esphome/components/max44009/* @berfenger
|
||||
esphome/components/max6956/* @looping40
|
||||
@ -267,7 +231,6 @@ esphome/components/mcp23x17_base/* @jesserockz
|
||||
esphome/components/mcp23xxx_base/* @jesserockz
|
||||
esphome/components/mcp2515/* @danielschramm @mvturnho
|
||||
esphome/components/mcp3204/* @rsumner
|
||||
esphome/components/mcp4461/* @p1ngb4ck
|
||||
esphome/components/mcp4728/* @berfenger
|
||||
esphome/components/mcp47a1/* @jesserockz
|
||||
esphome/components/mcp9600/* @mreditor97
|
||||
@ -282,7 +245,6 @@ esphome/components/mics_4514/* @jesserockz
|
||||
esphome/components/midea/* @dudanov
|
||||
esphome/components/midea_ir/* @dudanov
|
||||
esphome/components/mitsubishi/* @RubyBailey
|
||||
esphome/components/mixer/speaker/* @kahrendt
|
||||
esphome/components/mlx90393/* @functionpointer
|
||||
esphome/components/mlx90614/* @jesserockz
|
||||
esphome/components/mmc5603/* @benhoff
|
||||
@ -301,8 +263,6 @@ esphome/components/mopeka_std_check/* @Fabian-Schmidt
|
||||
esphome/components/mpl3115a2/* @kbickar
|
||||
esphome/components/mpu6886/* @fabaff
|
||||
esphome/components/ms8607/* @e28eta
|
||||
esphome/components/msa3xx/* @latonita
|
||||
esphome/components/nau7802/* @cujomalainey
|
||||
esphome/components/network/* @esphome/core
|
||||
esphome/components/nextion/* @edwardtfn @senexcrenshaw
|
||||
esphome/components/nextion/binary_sensor/* @senexcrenshaw
|
||||
@ -311,11 +271,8 @@ esphome/components/nextion/switch/* @senexcrenshaw
|
||||
esphome/components/nextion/text_sensor/* @senexcrenshaw
|
||||
esphome/components/nfc/* @jesserockz @kbx81
|
||||
esphome/components/noblex/* @AGalfra
|
||||
esphome/components/npi19/* @bakerkj
|
||||
esphome/components/number/* @esphome/core
|
||||
esphome/components/one_wire/* @ssieb
|
||||
esphome/components/online_image/* @clydebarrow @guillempages
|
||||
esphome/components/opentherm/* @olegtarasov
|
||||
esphome/components/ota/* @esphome/core
|
||||
esphome/components/output/* @esphome/core
|
||||
esphome/components/pca6416a/* @Mat931
|
||||
@ -325,7 +282,6 @@ esphome/components/pcf8563/* @KoenBreeman
|
||||
esphome/components/pid/* @OttoWinter
|
||||
esphome/components/pipsolar/* @andreashergert1984
|
||||
esphome/components/pm1006/* @habbie
|
||||
esphome/components/pm2005/* @andrewjswan
|
||||
esphome/components/pmsa003i/* @sjtrny
|
||||
esphome/components/pmwcs3/* @SeByDocKy
|
||||
esphome/components/pn532/* @OttoWinter @jesserockz
|
||||
@ -344,14 +300,14 @@ esphome/components/pvvx_mithermometer/* @pasiz
|
||||
esphome/components/pylontech/* @functionpointer
|
||||
esphome/components/qmp6988/* @andrewpc
|
||||
esphome/components/qr_code/* @wjtje
|
||||
esphome/components/qspi_dbi/* @clydebarrow
|
||||
esphome/components/qspi_amoled/* @clydebarrow
|
||||
esphome/components/qwiic_pir/* @kahrendt
|
||||
esphome/components/radon_eye_ble/* @jeffeb3
|
||||
esphome/components/radon_eye_rd200/* @jeffeb3
|
||||
esphome/components/rc522/* @glmnet
|
||||
esphome/components/rc522_i2c/* @glmnet
|
||||
esphome/components/rc522_spi/* @glmnet
|
||||
esphome/components/resampler/speaker/* @kahrendt
|
||||
esphome/components/resistance_sampler/* @jesserockz
|
||||
esphome/components/restart/* @esphome/core
|
||||
esphome/components/rf_bridge/* @jesserockz
|
||||
esphome/components/rgbct/* @jesserockz
|
||||
@ -364,12 +320,10 @@ esphome/components/rtttl/* @glmnet
|
||||
esphome/components/safe_mode/* @jsuanet @kbx81 @paulmonigatti
|
||||
esphome/components/scd4x/* @martgras @sjtrny
|
||||
esphome/components/script/* @esphome/core
|
||||
esphome/components/sdl/* @bdm310 @clydebarrow
|
||||
esphome/components/sdl/* @clydebarrow
|
||||
esphome/components/sdm_meter/* @jesserockz @polyfaces
|
||||
esphome/components/sdp3x/* @Azimath
|
||||
esphome/components/seeed_mr24hpc1/* @limengdu
|
||||
esphome/components/seeed_mr60bha2/* @limengdu
|
||||
esphome/components/seeed_mr60fda2/* @limengdu
|
||||
esphome/components/selec_meter/* @sourabhjaiswal
|
||||
esphome/components/select/* @esphome/core
|
||||
esphome/components/sen0321/* @notjj
|
||||
@ -395,8 +349,7 @@ esphome/components/smt100/* @piechade
|
||||
esphome/components/sn74hc165/* @jesserockz
|
||||
esphome/components/socket/* @esphome/core
|
||||
esphome/components/sonoff_d1/* @anatoly-savchenkov
|
||||
esphome/components/speaker/* @jesserockz @kahrendt
|
||||
esphome/components/speaker/media_player/* @kahrendt @synesthesiam
|
||||
esphome/components/speaker/* @jesserockz
|
||||
esphome/components/spi/* @clydebarrow @esphome/core
|
||||
esphome/components/spi_device/* @clydebarrow
|
||||
esphome/components/spi_led_strip/* @clydebarrow
|
||||
@ -420,20 +373,15 @@ esphome/components/st7701s/* @clydebarrow
|
||||
esphome/components/st7735/* @SenexCrenshaw
|
||||
esphome/components/st7789v/* @kbx81
|
||||
esphome/components/st7920/* @marsjan155
|
||||
esphome/components/statsd/* @Links2004
|
||||
esphome/components/substitutions/* @esphome/core
|
||||
esphome/components/sun/* @OttoWinter
|
||||
esphome/components/sun_gtil2/* @Mat931
|
||||
esphome/components/switch/* @esphome/core
|
||||
esphome/components/switch/binary_sensor/* @ssieb
|
||||
esphome/components/t6615/* @tylermenezes
|
||||
esphome/components/tc74/* @sethgirvan
|
||||
esphome/components/tca9548a/* @andreashergert1984
|
||||
esphome/components/tca9555/* @mobrembski
|
||||
esphome/components/tcl112/* @glmnet
|
||||
esphome/components/tee501/* @Stock-M
|
||||
esphome/components/teleinfo/* @0hax
|
||||
esphome/components/tem3200/* @bakerkj
|
||||
esphome/components/template/alarm_control_panel/* @grahambrown11 @hwstar
|
||||
esphome/components/template/datetime/* @rfdarter
|
||||
esphome/components/template/event/* @nohat
|
||||
@ -451,7 +399,6 @@ esphome/components/tmp102/* @timsavage
|
||||
esphome/components/tmp1075/* @sybrenstuvel
|
||||
esphome/components/tmp117/* @Azimath
|
||||
esphome/components/tof10120/* @wstrzalka
|
||||
esphome/components/tormatic/* @ti-mo
|
||||
esphome/components/toshiba/* @kbx81
|
||||
esphome/components/touchscreen/* @jesserockz @nielsnl68
|
||||
esphome/components/tsl2591/* @wjcarpenter
|
||||
@ -465,7 +412,6 @@ esphome/components/tuya/switch/* @jesserockz
|
||||
esphome/components/tuya/text_sensor/* @dentra
|
||||
esphome/components/uart/* @esphome/core
|
||||
esphome/components/uart/button/* @ssieb
|
||||
esphome/components/udp/* @clydebarrow
|
||||
esphome/components/ufire_ec/* @pvizeli
|
||||
esphome/components/ufire_ise/* @pvizeli
|
||||
esphome/components/ultrasonic/* @OttoWinter
|
||||
@ -478,7 +424,6 @@ esphome/components/veml7700/* @latonita
|
||||
esphome/components/version/* @esphome/core
|
||||
esphome/components/voice_assistant/* @jesserockz
|
||||
esphome/components/wake_on_lan/* @clydebarrow @willwill2will54
|
||||
esphome/components/watchdog/* @oarcher
|
||||
esphome/components/waveshare_epaper/* @clydebarrow
|
||||
esphome/components/web_server_base/* @OttoWinter
|
||||
esphome/components/web_server_idf/* @dentra
|
||||
@ -501,13 +446,11 @@ esphome/components/wl_134/* @hobbypunk90
|
||||
esphome/components/x9c/* @EtienneMD
|
||||
esphome/components/xgzp68xx/* @gcormier
|
||||
esphome/components/xiaomi_hhccjcy10/* @fariouche
|
||||
esphome/components/xiaomi_lywsd02mmc/* @juanluss31
|
||||
esphome/components/xiaomi_lywsd03mmc/* @ahpohl
|
||||
esphome/components/xiaomi_mhoc303/* @drug123
|
||||
esphome/components/xiaomi_mhoc401/* @vevsvevs
|
||||
esphome/components/xiaomi_rtcgq02lm/* @jesserockz
|
||||
esphome/components/xl9535/* @mreditor97
|
||||
esphome/components/xpt2046/touchscreen/* @nielsnl68 @numo68
|
||||
esphome/components/xxtea/* @clydebarrow
|
||||
esphome/components/zhlt01/* @cfeenstra1024
|
||||
esphome/components/zio_ultrasonic/* @kahrendt
|
||||
|
@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at esphome@openhomefoundation.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at esphome@nabucasa.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
|
@ -1,14 +1,12 @@
|
||||
# Contributing to ESPHome [](https://discord.gg/KhAMKrd) [](https://GitHub.com/esphome/esphome/releases/)
|
||||
# Contributing to ESPHome
|
||||
|
||||
We welcome contributions to the ESPHome suite of code and documentation!
|
||||
For a detailed guide, please see https://esphome.io/guides/contributing.html#contributing-to-esphome
|
||||
|
||||
Please read our [contributing guide](https://esphome.io/guides/contributing.html) if you wish to contribute to the
|
||||
project and be sure to join us on [Discord](https://discord.gg/KhAMKrd).
|
||||
Things to note when contributing:
|
||||
|
||||
**See also:**
|
||||
|
||||
[Documentation](https://esphome.io) -- [Issues](https://github.com/esphome/issues/issues) -- [Feature requests](https://github.com/esphome/feature-requests/issues)
|
||||
|
||||
---
|
||||
|
||||
[](https://www.openhomefoundation.org/)
|
||||
- Please test your changes :)
|
||||
- If a new feature is added or an existing user-facing feature is changed, you should also
|
||||
update the [docs](https://github.com/esphome/esphome-docs). See [contributing to esphome-docs](https://esphome.io/guides/contributing.html#contributing-to-esphomedocs)
|
||||
for more information.
|
||||
- Please also update the tests in the `tests/` folder. You can do so by just adding a line in one of the YAML files
|
||||
which checks if your new feature compiles correctly.
|
||||
|
15
README.md
15
README.md
@ -1,16 +1,9 @@
|
||||
# ESPHome [](https://discord.gg/KhAMKrd) [](https://GitHub.com/esphome/esphome/releases/)
|
||||
|
||||
<a href="https://esphome.io/">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://esphome.io/_static/logo-text-on-dark.svg", alt="ESPHome Logo">
|
||||
<img src="https://esphome.io/_static/logo-text-on-light.svg" alt="ESPHome Logo">
|
||||
</picture>
|
||||
</a>
|
||||
[](https://esphome.io/)
|
||||
|
||||
---
|
||||
**Documentation:** https://esphome.io/
|
||||
|
||||
[Documentation](https://esphome.io) -- [Issues](https://github.com/esphome/issues/issues) -- [Feature requests](https://github.com/esphome/feature-requests/issues)
|
||||
For issues, please go to [the issue tracker](https://github.com/esphome/issues/issues).
|
||||
|
||||
---
|
||||
|
||||
[](https://www.openhomefoundation.org/)
|
||||
For feature requests, please see [feature requests](https://github.com/esphome/feature-requests/issues).
|
||||
|
@ -29,18 +29,33 @@ RUN \
|
||||
# Use pinned versions so that we get updates with build caching
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
python3-pip=23.0.1+dfsg-1 \
|
||||
python3-setuptools=66.1.1-1+deb12u1 \
|
||||
python3-setuptools=66.1.1-1 \
|
||||
python3-venv=3.11.2-1+b1 \
|
||||
python3-wheel=0.38.4-2 \
|
||||
iputils-ping=3:20221126-1+deb12u1 \
|
||||
git=1:2.39.5-0+deb12u2 \
|
||||
curl=7.88.1-10+deb12u12 \
|
||||
openssh-client=1:9.2p1-2+deb12u5 \
|
||||
iputils-ping=3:20221126-1 \
|
||||
git=1:2.39.2-1.1 \
|
||||
curl=7.88.1-10+deb12u5 \
|
||||
openssh-client=1:9.2p1-2+deb12u2 \
|
||||
python3-cffi=1.15.1-5 \
|
||||
libcairo2=1.16.0-7 \
|
||||
libmagic1=1:5.44-3 \
|
||||
patch=2.7.6-7 \
|
||||
&& rm -rf \
|
||||
patch=2.7.6-7; \
|
||||
if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
|
||||
apt-get install -y --no-install-recommends \
|
||||
build-essential=12.9 \
|
||||
python3-dev=3.11.2-1+b1 \
|
||||
zlib1g-dev=1:1.2.13.dfsg-1 \
|
||||
libjpeg-dev=1:2.1.5-2 \
|
||||
libfreetype-dev=2.12.1+dfsg-5 \
|
||||
libssl-dev=3.0.11-1~deb12u2 \
|
||||
libffi-dev=3.4.4-1 \
|
||||
libopenjp2-7=2.5.0-2 \
|
||||
libtiff6=4.5.0-6+deb12u1 \
|
||||
cargo=0.66.0+ds1-1 \
|
||||
pkg-config=1.8.1-1 \
|
||||
gcc-arm-linux-gnueabihf=4:12.2.0-3; \
|
||||
fi; \
|
||||
rm -rf \
|
||||
/tmp/* \
|
||||
/var/{cache,log}/* \
|
||||
/var/lib/apt/lists/*
|
||||
@ -51,11 +66,23 @@ ENV \
|
||||
# Store globally installed pio libs in /piolibs
|
||||
PLATFORMIO_GLOBALLIB_DIR=/piolibs
|
||||
|
||||
# Support legacy binaries on Debian multiarch system. There is no "correct" way
|
||||
# to do this, other than using properly built toolchains...
|
||||
# See: https://unix.stackexchange.com/questions/553743/correct-way-to-add-lib-ld-linux-so-3-in-debian
|
||||
RUN \
|
||||
if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
|
||||
ln -s /lib/arm-linux-gnueabihf/ld-linux-armhf.so.3 /lib/ld-linux.so.3; \
|
||||
fi
|
||||
|
||||
RUN \
|
||||
# Ubuntu python3-pip is missing wheel
|
||||
if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
|
||||
export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
|
||||
fi; \
|
||||
pip3 install \
|
||||
--break-system-packages --no-cache-dir \
|
||||
# Keep platformio version in sync with requirements.txt
|
||||
platformio==6.1.18 \
|
||||
platformio==6.1.15 \
|
||||
# Change some platformio settings
|
||||
&& platformio settings set enable_telemetry No \
|
||||
&& platformio settings set check_platformio_interval 1000000 \
|
||||
@ -65,46 +92,14 @@ RUN \
|
||||
# First install requirements to leverage caching when requirements don't change
|
||||
# tmpfs is for https://github.com/rust-lang/cargo/issues/8719
|
||||
|
||||
COPY requirements.txt requirements_optional.txt /
|
||||
RUN --mount=type=tmpfs,target=/root/.cargo <<END-OF-RUN
|
||||
# Fail on any non-zero status
|
||||
set -e
|
||||
|
||||
# install build tools in case wheels are not available
|
||||
BUILD_DEPS="
|
||||
build-essential=12.9
|
||||
python3-dev=3.11.2-1+b1
|
||||
zlib1g-dev=1:1.2.13.dfsg-1
|
||||
libjpeg-dev=1:2.1.5-2
|
||||
libfreetype-dev=2.12.1+dfsg-5+deb12u4
|
||||
libssl-dev=3.0.15-1~deb12u1
|
||||
libffi-dev=3.4.4-1
|
||||
cargo=0.66.0+ds1-1
|
||||
pkg-config=1.8.1-1
|
||||
"
|
||||
LIB_DEPS="
|
||||
libtiff6=4.5.0-6+deb12u1
|
||||
libopenjp2-7=2.5.0-2+deb12u1
|
||||
"
|
||||
if [ "$TARGETARCH$TARGETVARIANT" = "arm64" ]
|
||||
then
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends $BUILD_DEPS $LIB_DEPS
|
||||
fi
|
||||
|
||||
CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse CARGO_HOME=/root/.cargo
|
||||
pip3 install --break-system-packages --no-cache-dir -r /requirements.txt -r /requirements_optional.txt
|
||||
|
||||
if [ "$TARGETARCH$TARGETVARIANT" = "arm64" ]
|
||||
then
|
||||
apt-get remove -y --purge --auto-remove $BUILD_DEPS
|
||||
rm -rf /tmp/* /var/{cache,log}/* /var/lib/apt/lists/*
|
||||
fi
|
||||
END-OF-RUN
|
||||
|
||||
|
||||
COPY script/platformio_install_deps.py platformio.ini /
|
||||
RUN /platformio_install_deps.py /platformio.ini --libraries
|
||||
COPY requirements.txt requirements_optional.txt script/platformio_install_deps.py platformio.ini /
|
||||
RUN --mount=type=tmpfs,target=/root/.cargo if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
|
||||
export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
|
||||
fi; \
|
||||
CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse CARGO_HOME=/root/.cargo \
|
||||
pip3 install \
|
||||
--break-system-packages --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
|
||||
&& /platformio_install_deps.py /platformio.ini --libraries
|
||||
|
||||
# Avoid unsafe git error when container user and file config volume permissions don't match
|
||||
RUN git config --system --add safe.directory '*'
|
||||
@ -115,7 +110,11 @@ FROM base AS docker
|
||||
|
||||
# Copy esphome and install
|
||||
COPY . /esphome
|
||||
RUN pip3 install --break-system-packages --no-cache-dir -e /esphome
|
||||
RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
|
||||
export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
|
||||
fi; \
|
||||
pip3 install \
|
||||
--break-system-packages --no-cache-dir -e /esphome
|
||||
|
||||
# Settings for dashboard
|
||||
ENV USERNAME="" PASSWORD=""
|
||||
@ -139,18 +138,6 @@ ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD ["dashboard", "/config"]
|
||||
|
||||
|
||||
ARG BUILD_VERSION=dev
|
||||
|
||||
# Labels
|
||||
LABEL \
|
||||
org.opencontainers.image.authors="The ESPHome Authors" \
|
||||
org.opencontainers.image.title="ESPHome" \
|
||||
org.opencontainers.image.description="ESPHome is a system to configure your microcontrollers by simple yet powerful configuration files and control them remotely through Home Automation systems" \
|
||||
org.opencontainers.image.url="https://esphome.io/" \
|
||||
org.opencontainers.image.documentation="https://esphome.io/" \
|
||||
org.opencontainers.image.source="https://github.com/esphome/esphome" \
|
||||
org.opencontainers.image.licenses="ESPHome" \
|
||||
org.opencontainers.image.version=${BUILD_VERSION}
|
||||
|
||||
|
||||
# ======================= hassio-type image =======================
|
||||
@ -160,7 +147,7 @@ RUN \
|
||||
apt-get update \
|
||||
# Use pinned versions so that we get updates with build caching
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
nginx-light=1.22.1-9+deb12u1 \
|
||||
nginx-light=1.22.1-9 \
|
||||
&& rm -rf \
|
||||
/tmp/* \
|
||||
/var/{cache,log}/* \
|
||||
@ -173,12 +160,16 @@ COPY docker/ha-addon-rootfs/ /
|
||||
|
||||
# Copy esphome and install
|
||||
COPY . /esphome
|
||||
RUN pip3 install --break-system-packages --no-cache-dir -e /esphome
|
||||
RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
|
||||
export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
|
||||
fi; \
|
||||
pip3 install \
|
||||
--break-system-packages --no-cache-dir -e /esphome
|
||||
|
||||
# Labels
|
||||
LABEL \
|
||||
io.hass.name="ESPHome" \
|
||||
io.hass.description="ESPHome is a system to configure your microcontrollers by simple yet powerful configuration files and control them remotely through Home Automation systems" \
|
||||
io.hass.description="Manage and program ESP8266/ESP32 microcontrollers through YAML configuration files" \
|
||||
io.hass.type="addon" \
|
||||
io.hass.version="${BUILD_VERSION}"
|
||||
# io.hass.arch is inherited from addon-debian-base
|
||||
@ -193,25 +184,27 @@ ENV \
|
||||
PLATFORMIO_CORE_DIR=/esphome/.temp/platformio
|
||||
|
||||
RUN \
|
||||
curl -L https://apt.llvm.org/llvm-snapshot.gpg.key -o /etc/apt/trusted.gpg.d/apt.llvm.org.asc \
|
||||
&& echo "deb http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm-18 main" > /etc/apt/sources.list.d/llvm.sources.list \
|
||||
&& apt-get update \
|
||||
apt-get update \
|
||||
# Use pinned versions so that we get updates with build caching
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
clang-format-13=1:13.0.1-11+b2 \
|
||||
clang-tidy-14=1:14.0.6-12 \
|
||||
patch=2.7.6-7 \
|
||||
software-properties-common=0.99.30-4.1~deb12u1 \
|
||||
nano=7.2-1+deb12u1 \
|
||||
software-properties-common=0.99.30-4 \
|
||||
nano=7.2-1 \
|
||||
build-essential=12.9 \
|
||||
python3-dev=3.11.2-1+b1 \
|
||||
clang-tidy-18=1:18.1.8~++20240731024826+3b5b5c1ec4a3-1~exp1~20240731144843.145 \
|
||||
&& rm -rf \
|
||||
/tmp/* \
|
||||
/var/{cache,log}/* \
|
||||
/var/lib/apt/lists/*
|
||||
|
||||
COPY requirements_test.txt /
|
||||
RUN pip3 install --break-system-packages --no-cache-dir -r /requirements_test.txt
|
||||
RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
|
||||
export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
|
||||
fi; \
|
||||
pip3 install \
|
||||
--break-system-packages --no-cache-dir -r /requirements_test.txt
|
||||
|
||||
VOLUME ["/esphome"]
|
||||
WORKDIR /esphome
|
||||
|
@ -1,19 +1,22 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
from dataclasses import dataclass
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
import argparse
|
||||
from platform import machine
|
||||
import shlex
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
CHANNEL_DEV = "dev"
|
||||
CHANNEL_BETA = "beta"
|
||||
CHANNEL_RELEASE = "release"
|
||||
CHANNELS = [CHANNEL_DEV, CHANNEL_BETA, CHANNEL_RELEASE]
|
||||
|
||||
ARCH_AMD64 = "amd64"
|
||||
ARCH_ARMV7 = "armv7"
|
||||
ARCH_AARCH64 = "aarch64"
|
||||
ARCHS = [ARCH_AMD64, ARCH_AARCH64]
|
||||
ARCHS = [ARCH_AMD64, ARCH_ARMV7, ARCH_AARCH64]
|
||||
|
||||
TYPE_DOCKER = "docker"
|
||||
TYPE_HA_ADDON = "ha-addon"
|
||||
@ -73,6 +76,7 @@ class DockerParams:
|
||||
}[build_type]
|
||||
platform = {
|
||||
ARCH_AMD64: "linux/amd64",
|
||||
ARCH_ARMV7: "linux/arm/v7",
|
||||
ARCH_AARCH64: "linux/arm64",
|
||||
}[arch]
|
||||
target = {
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
|
||||
# If /cache is mounted, use that as PIO's coredir
|
||||
# otherwise use path in /config (so that PIO packages aren't downloaded on each compile)
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import re
|
||||
import argparse
|
||||
|
||||
CHANNEL_DEV = "dev"
|
||||
CHANNEL_BETA = "beta"
|
||||
|
@ -23,6 +23,10 @@ if bashio::config.true 'streamer_mode'; then
|
||||
export ESPHOME_STREAMER_MODE=true
|
||||
fi
|
||||
|
||||
if bashio::config.true 'status_use_ping'; then
|
||||
export ESPHOME_DASHBOARD_USE_PING=true
|
||||
fi
|
||||
|
||||
if bashio::config.has_value 'relative_url'; then
|
||||
export ESPHOME_DASHBOARD_RELATIVE_URL=$(bashio::config 'relative_url')
|
||||
fi
|
||||
|
@ -1,13 +1,12 @@
|
||||
# PYTHON_ARGCOMPLETE_OK
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
import functools
|
||||
import importlib
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
import argcomplete
|
||||
|
||||
@ -21,8 +20,6 @@ from esphome.const import (
|
||||
CONF_DEASSERT_RTS_DTR,
|
||||
CONF_DISABLED,
|
||||
CONF_ESPHOME,
|
||||
CONF_LEVEL,
|
||||
CONF_LOG_TOPIC,
|
||||
CONF_LOGGER,
|
||||
CONF_MDNS,
|
||||
CONF_MQTT,
|
||||
@ -33,7 +30,6 @@ from esphome.const import (
|
||||
CONF_PLATFORMIO_OPTIONS,
|
||||
CONF_PORT,
|
||||
CONF_SUBSTITUTIONS,
|
||||
CONF_TOPIC,
|
||||
PLATFORM_BK72XX,
|
||||
PLATFORM_ESP32,
|
||||
PLATFORM_ESP8266,
|
||||
@ -42,15 +38,15 @@ from esphome.const import (
|
||||
SECRETS_FILES,
|
||||
)
|
||||
from esphome.core import CORE, EsphomeError, coroutine
|
||||
from esphome.helpers import get_bool_env, indent, is_ip_address
|
||||
from esphome.log import Fore, color, setup_log
|
||||
from esphome.helpers import indent, is_ip_address
|
||||
from esphome.util import (
|
||||
get_serial_ports,
|
||||
list_yaml_files,
|
||||
run_external_command,
|
||||
run_external_process,
|
||||
safe_print,
|
||||
list_yaml_files,
|
||||
get_serial_ports,
|
||||
)
|
||||
from esphome.log import color, setup_log, Fore
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -67,7 +63,7 @@ def choose_prompt(options, purpose: str = None):
|
||||
return options[0][1]
|
||||
|
||||
safe_print(
|
||||
f"Found multiple options{f' for {purpose}' if purpose else ''}, please choose one:"
|
||||
f'Found multiple options{f" for {purpose}" if purpose else ""}, please choose one:'
|
||||
)
|
||||
for i, (desc, _) in enumerate(options):
|
||||
safe_print(f" [{i + 1}] {desc}")
|
||||
@ -99,12 +95,8 @@ def choose_upload_log_host(
|
||||
options.append((f"Over The Air ({CORE.address})", CORE.address))
|
||||
if default == "OTA":
|
||||
return CORE.address
|
||||
if (
|
||||
show_mqtt
|
||||
and (mqtt_config := CORE.config.get(CONF_MQTT))
|
||||
and mqtt_logging_enabled(mqtt_config)
|
||||
):
|
||||
options.append((f"MQTT ({mqtt_config[CONF_BROKER]})", "MQTT"))
|
||||
if show_mqtt and CONF_MQTT in CORE.config:
|
||||
options.append((f"MQTT ({CORE.config['mqtt'][CONF_BROKER]})", "MQTT"))
|
||||
if default == "OTA":
|
||||
return "MQTT"
|
||||
if default is not None:
|
||||
@ -114,17 +106,6 @@ def choose_upload_log_host(
|
||||
return choose_prompt(options, purpose=purpose)
|
||||
|
||||
|
||||
def mqtt_logging_enabled(mqtt_config):
|
||||
log_topic = mqtt_config[CONF_LOG_TOPIC]
|
||||
if log_topic is None:
|
||||
return False
|
||||
if CONF_TOPIC not in log_topic:
|
||||
return False
|
||||
if log_topic.get(CONF_LEVEL, None) == "NONE":
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def get_port_type(port):
|
||||
if port.startswith("/") or port.startswith("COM"):
|
||||
return "SERIAL"
|
||||
@ -133,9 +114,8 @@ def get_port_type(port):
|
||||
return "NETWORK"
|
||||
|
||||
|
||||
def run_miniterm(config, port, args):
|
||||
def run_miniterm(config, port):
|
||||
import serial
|
||||
|
||||
from esphome import platformio_api
|
||||
|
||||
if CONF_LOGGER not in config:
|
||||
@ -154,7 +134,7 @@ def run_miniterm(config, port, args):
|
||||
|
||||
# We can't set to False by default since it leads to toggling and hence
|
||||
# ESP32 resets on some platforms.
|
||||
if config["logger"][CONF_DEASSERT_RTS_DTR] or args.reset:
|
||||
if config["logger"][CONF_DEASSERT_RTS_DTR]:
|
||||
ser.dtr = False
|
||||
ser.rts = False
|
||||
|
||||
@ -244,11 +224,11 @@ def compile_program(args, config):
|
||||
return 0 if idedata is not None else 1
|
||||
|
||||
|
||||
def upload_using_esptool(config, port, file, speed):
|
||||
def upload_using_esptool(config, port, file):
|
||||
from esphome import platformio_api
|
||||
|
||||
first_baudrate = speed or config[CONF_ESPHOME][CONF_PLATFORMIO_OPTIONS].get(
|
||||
"upload_speed", os.getenv("ESPHOME_UPLOAD_SPEED", "460800")
|
||||
first_baudrate = config[CONF_ESPHOME][CONF_PLATFORMIO_OPTIONS].get(
|
||||
"upload_speed", 460800
|
||||
)
|
||||
|
||||
if file is not None:
|
||||
@ -337,18 +317,11 @@ def check_permissions(port):
|
||||
|
||||
|
||||
def upload_program(config, args, host):
|
||||
try:
|
||||
module = importlib.import_module("esphome.components." + CORE.target_platform)
|
||||
if getattr(module, "upload_program")(config, args, host):
|
||||
return 0
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if get_port_type(host) == "SERIAL":
|
||||
check_permissions(host)
|
||||
if CORE.target_platform in (PLATFORM_ESP32, PLATFORM_ESP8266):
|
||||
file = getattr(args, "file", None)
|
||||
return upload_using_esptool(config, host, file, args.upload_speed)
|
||||
return upload_using_esptool(config, host, file)
|
||||
|
||||
if CORE.target_platform in (PLATFORM_RP2040):
|
||||
return upload_using_platformio(config, args.device)
|
||||
@ -371,16 +344,14 @@ def upload_program(config, args, host):
|
||||
|
||||
from esphome import espota2
|
||||
|
||||
remote_port = int(ota_conf[CONF_PORT])
|
||||
remote_port = ota_conf[CONF_PORT]
|
||||
password = ota_conf.get(CONF_PASSWORD, "")
|
||||
|
||||
if (
|
||||
CONF_MQTT in config # pylint: disable=too-many-boolean-expressions
|
||||
not is_ip_address(CORE.address) # pylint: disable=too-many-boolean-expressions
|
||||
and (get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED])
|
||||
and CONF_MQTT in config
|
||||
and (not args.device or args.device in ("MQTT", "OTA"))
|
||||
and (
|
||||
((config[CONF_MDNS][CONF_DISABLED]) and not is_ip_address(CORE.address))
|
||||
or get_port_type(host) == "MQTT"
|
||||
)
|
||||
):
|
||||
from esphome import mqtt
|
||||
|
||||
@ -399,14 +370,14 @@ def show_logs(config, args, port):
|
||||
raise EsphomeError("Logger is not configured!")
|
||||
if get_port_type(port) == "SERIAL":
|
||||
check_permissions(port)
|
||||
return run_miniterm(config, port, args)
|
||||
return run_miniterm(config, port)
|
||||
if get_port_type(port) == "NETWORK" and "api" in config:
|
||||
if config[CONF_MDNS][CONF_DISABLED] and CONF_MQTT in config:
|
||||
from esphome import mqtt
|
||||
|
||||
port = mqtt.get_esphome_device_ip(
|
||||
config, args.username, args.password, args.client_id
|
||||
)[0]
|
||||
)
|
||||
|
||||
from esphome.components.api.client import run_logs
|
||||
|
||||
@ -625,9 +596,8 @@ def command_update_all(args):
|
||||
|
||||
|
||||
def command_idedata(args, config):
|
||||
import json
|
||||
|
||||
from esphome import platformio_api
|
||||
import json
|
||||
|
||||
logging.disable(logging.INFO)
|
||||
logging.disable(logging.WARNING)
|
||||
@ -725,8 +695,7 @@ def command_rename(args, config):
|
||||
os.remove(new_path)
|
||||
return 1
|
||||
|
||||
if CORE.config_path != new_path:
|
||||
os.remove(CORE.config_path)
|
||||
os.remove(CORE.config_path)
|
||||
|
||||
print(color(Fore.BOLD_GREEN, "SUCCESS"))
|
||||
print()
|
||||
@ -759,23 +728,11 @@ POST_CONFIG_ACTIONS = {
|
||||
def parse_args(argv):
|
||||
options_parser = argparse.ArgumentParser(add_help=False)
|
||||
options_parser.add_argument(
|
||||
"-v",
|
||||
"--verbose",
|
||||
help="Enable verbose ESPHome logs.",
|
||||
action="store_true",
|
||||
default=get_bool_env("ESPHOME_VERBOSE"),
|
||||
"-v", "--verbose", help="Enable verbose ESPHome logs.", action="store_true"
|
||||
)
|
||||
options_parser.add_argument(
|
||||
"-q", "--quiet", help="Disable all ESPHome logs.", action="store_true"
|
||||
)
|
||||
options_parser.add_argument(
|
||||
"-l",
|
||||
"--log-level",
|
||||
help="Set the log level.",
|
||||
default=os.getenv("ESPHOME_LOG_LEVEL", "INFO"),
|
||||
action="store",
|
||||
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
|
||||
)
|
||||
options_parser.add_argument(
|
||||
"--dashboard", help=argparse.SUPPRESS, action="store_true"
|
||||
)
|
||||
@ -789,14 +746,7 @@ def parse_args(argv):
|
||||
)
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=f"ESPHome {const.__version__}", parents=[options_parser]
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--version",
|
||||
action="version",
|
||||
version=f"Version: {const.__version__}",
|
||||
help="Print the ESPHome version and exit.",
|
||||
description=f"ESPHome v{const.__version__}", parents=[options_parser]
|
||||
)
|
||||
|
||||
mqtt_options = argparse.ArgumentParser(add_help=False)
|
||||
@ -844,10 +794,6 @@ def parse_args(argv):
|
||||
"--device",
|
||||
help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
|
||||
)
|
||||
parser_upload.add_argument(
|
||||
"--upload_speed",
|
||||
help="Override the default or configured upload speed.",
|
||||
)
|
||||
parser_upload.add_argument(
|
||||
"--file",
|
||||
help="Manually specify the binary file to upload.",
|
||||
@ -866,13 +812,6 @@ def parse_args(argv):
|
||||
"--device",
|
||||
help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
|
||||
)
|
||||
parser_logs.add_argument(
|
||||
"--reset",
|
||||
"-r",
|
||||
action="store_true",
|
||||
help="Reset the device before starting serial logs.",
|
||||
default=os.getenv("ESPHOME_SERIAL_LOGGING_RESET"),
|
||||
)
|
||||
|
||||
parser_discover = subparsers.add_parser(
|
||||
"discover",
|
||||
@ -895,20 +834,9 @@ def parse_args(argv):
|
||||
"--device",
|
||||
help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
|
||||
)
|
||||
parser_run.add_argument(
|
||||
"--upload_speed",
|
||||
help="Override the default or configured upload speed.",
|
||||
)
|
||||
parser_run.add_argument(
|
||||
"--no-logs", help="Disable starting logs.", action="store_true"
|
||||
)
|
||||
parser_run.add_argument(
|
||||
"--reset",
|
||||
"-r",
|
||||
action="store_true",
|
||||
help="Reset the device before starting serial logs.",
|
||||
default=os.getenv("ESPHOME_SERIAL_LOGGING_RESET"),
|
||||
)
|
||||
|
||||
parser_clean = subparsers.add_parser(
|
||||
"clean-mqtt",
|
||||
@ -1019,6 +947,67 @@ def parse_args(argv):
|
||||
# a deprecation warning).
|
||||
arguments = argv[1:]
|
||||
|
||||
# On Python 3.9+ we can simply set exit_on_error=False in the constructor
|
||||
def _raise(x):
|
||||
raise argparse.ArgumentError(None, x)
|
||||
|
||||
# First, try new-style parsing, but don't exit in case of failure
|
||||
try:
|
||||
# duplicate parser so that we can use the original one to raise errors later on
|
||||
current_parser = argparse.ArgumentParser(add_help=False, parents=[parser])
|
||||
current_parser.set_defaults(deprecated_argv_suggestion=None)
|
||||
current_parser.error = _raise
|
||||
return current_parser.parse_args(arguments)
|
||||
except argparse.ArgumentError:
|
||||
pass
|
||||
|
||||
# Second, try compat parsing and rearrange the command-line if it succeeds
|
||||
# Disable argparse's built-in help option and add it manually to prevent this
|
||||
# parser from printing the help messagefor the old format when invoked with -h.
|
||||
compat_parser = argparse.ArgumentParser(parents=[options_parser], add_help=False)
|
||||
compat_parser.add_argument("-h", "--help", action="store_true")
|
||||
compat_parser.add_argument("configuration", nargs="*")
|
||||
compat_parser.add_argument(
|
||||
"command",
|
||||
choices=[
|
||||
"config",
|
||||
"compile",
|
||||
"upload",
|
||||
"logs",
|
||||
"run",
|
||||
"clean-mqtt",
|
||||
"wizard",
|
||||
"mqtt-fingerprint",
|
||||
"version",
|
||||
"clean",
|
||||
"dashboard",
|
||||
"vscode",
|
||||
"update-all",
|
||||
],
|
||||
)
|
||||
|
||||
try:
|
||||
compat_parser.error = _raise
|
||||
result, unparsed = compat_parser.parse_known_args(argv[1:])
|
||||
last_option = len(arguments) - len(unparsed) - 1 - len(result.configuration)
|
||||
unparsed = [
|
||||
"--device" if arg in ("--upload-port", "--serial-port") else arg
|
||||
for arg in unparsed
|
||||
]
|
||||
arguments = (
|
||||
arguments[0:last_option]
|
||||
+ [result.command]
|
||||
+ result.configuration
|
||||
+ unparsed
|
||||
)
|
||||
deprecated_argv_suggestion = arguments
|
||||
except argparse.ArgumentError:
|
||||
# old-style parsing failed, don't suggest any argument
|
||||
deprecated_argv_suggestion = None
|
||||
|
||||
# Finally, run the new-style parser again with the possibly swapped arguments,
|
||||
# and let it error out if the command is unparsable.
|
||||
parser.set_defaults(deprecated_argv_suggestion=deprecated_argv_suggestion)
|
||||
argcomplete.autocomplete(parser)
|
||||
return parser.parse_args(arguments)
|
||||
|
||||
@ -1027,17 +1016,26 @@ def run_esphome(argv):
|
||||
args = parse_args(argv)
|
||||
CORE.dashboard = args.dashboard
|
||||
|
||||
# Override log level if verbose is set
|
||||
if args.verbose:
|
||||
args.log_level = "DEBUG"
|
||||
elif args.quiet:
|
||||
args.log_level = "CRITICAL"
|
||||
|
||||
setup_log(
|
||||
log_level=args.log_level,
|
||||
args.verbose,
|
||||
args.quiet,
|
||||
# Show timestamp for dashboard access logs
|
||||
include_timestamp=args.command == "dashboard",
|
||||
args.command == "dashboard",
|
||||
)
|
||||
if args.deprecated_argv_suggestion is not None and args.command != "vscode":
|
||||
_LOGGER.warning(
|
||||
"Calling ESPHome with the configuration before the command is deprecated "
|
||||
"and will be removed in the future. "
|
||||
)
|
||||
_LOGGER.warning("Please instead use:")
|
||||
_LOGGER.warning(" esphome %s", " ".join(args.deprecated_argv_suggestion))
|
||||
|
||||
if sys.version_info < (3, 8, 0):
|
||||
_LOGGER.error(
|
||||
"You're running ESPHome with Python <3.8. ESPHome is no longer compatible "
|
||||
"with this Python version. Please reinstall ESPHome with Python 3.8+"
|
||||
)
|
||||
return 1
|
||||
|
||||
if args.command in PRE_CONFIG_ACTIONS:
|
||||
try:
|
||||
|
@ -1,18 +1,16 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_ALL,
|
||||
CONF_ANY,
|
||||
CONF_AUTOMATION_ID,
|
||||
CONF_CONDITION,
|
||||
CONF_COUNT,
|
||||
CONF_ELSE,
|
||||
CONF_ID,
|
||||
CONF_THEN,
|
||||
CONF_TIME,
|
||||
CONF_TIMEOUT,
|
||||
CONF_TRIGGER_ID,
|
||||
CONF_TYPE_ID,
|
||||
CONF_TIME,
|
||||
CONF_UPDATE_INTERVAL,
|
||||
)
|
||||
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
|
||||
@ -75,13 +73,6 @@ def validate_potentially_and_condition(value):
|
||||
return validate_condition(value)
|
||||
|
||||
|
||||
def validate_potentially_or_condition(value):
|
||||
if isinstance(value, list):
|
||||
with cv.remove_prepend_path(["or"]):
|
||||
return validate_condition({"or": value})
|
||||
return validate_condition(value)
|
||||
|
||||
|
||||
DelayAction = cg.esphome_ns.class_("DelayAction", Action, cg.Component)
|
||||
LambdaAction = cg.esphome_ns.class_("LambdaAction", Action)
|
||||
IfAction = cg.esphome_ns.class_("IfAction", Action)
|
||||
@ -175,18 +166,6 @@ async def or_condition_to_code(config, condition_id, template_arg, args):
|
||||
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
||||
|
||||
|
||||
@register_condition("all", AndCondition, validate_condition_list)
|
||||
async def all_condition_to_code(config, condition_id, template_arg, args):
|
||||
conditions = await build_condition_list(config, template_arg, args)
|
||||
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
||||
|
||||
|
||||
@register_condition("any", OrCondition, validate_condition_list)
|
||||
async def any_condition_to_code(config, condition_id, template_arg, args):
|
||||
conditions = await build_condition_list(config, template_arg, args)
|
||||
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
||||
|
||||
|
||||
@register_condition("not", NotCondition, validate_potentially_and_condition)
|
||||
async def not_condition_to_code(config, condition_id, template_arg, args):
|
||||
condition = await build_condition(config, template_arg, args)
|
||||
@ -244,21 +223,15 @@ async def delay_action_to_code(config, action_id, template_arg, args):
|
||||
IfAction,
|
||||
cv.All(
|
||||
{
|
||||
cv.Exclusive(
|
||||
CONF_CONDITION, CONF_CONDITION
|
||||
): validate_potentially_and_condition,
|
||||
cv.Exclusive(CONF_ANY, CONF_CONDITION): validate_potentially_or_condition,
|
||||
cv.Exclusive(CONF_ALL, CONF_CONDITION): validate_potentially_and_condition,
|
||||
cv.Required(CONF_CONDITION): validate_potentially_and_condition,
|
||||
cv.Optional(CONF_THEN): validate_action_list,
|
||||
cv.Optional(CONF_ELSE): validate_action_list,
|
||||
},
|
||||
cv.has_at_least_one_key(CONF_THEN, CONF_ELSE),
|
||||
cv.has_at_least_one_key(CONF_CONDITION, CONF_ANY, CONF_ALL),
|
||||
),
|
||||
)
|
||||
async def if_action_to_code(config, action_id, template_arg, args):
|
||||
cond_conf = next(el for el in config if el in (CONF_ANY, CONF_ALL, CONF_CONDITION))
|
||||
conditions = await build_condition(config[cond_conf], template_arg, args)
|
||||
conditions = await build_condition(config[CONF_CONDITION], template_arg, args)
|
||||
var = cg.new_Pvariable(action_id, template_arg, conditions)
|
||||
if CONF_THEN in config:
|
||||
actions = await build_action_list(config[CONF_THEN], template_arg, args)
|
||||
|
@ -8,86 +8,85 @@
|
||||
# want to break suddenly due to a rename (this file will get backports for features).
|
||||
|
||||
# pylint: disable=unused-import
|
||||
from esphome.cpp_generator import ( # noqa: F401
|
||||
ArrayInitializer,
|
||||
from esphome.cpp_generator import ( # noqa
|
||||
Expression,
|
||||
LineComment,
|
||||
MockObj,
|
||||
MockObjClass,
|
||||
Pvariable,
|
||||
RawExpression,
|
||||
RawStatement,
|
||||
Statement,
|
||||
StructInitializer,
|
||||
TemplateArguments,
|
||||
StructInitializer,
|
||||
ArrayInitializer,
|
||||
safe_exp,
|
||||
Statement,
|
||||
LineComment,
|
||||
progmem_array,
|
||||
static_const_array,
|
||||
statement,
|
||||
variable,
|
||||
with_local_variable,
|
||||
new_variable,
|
||||
Pvariable,
|
||||
new_Pvariable,
|
||||
add,
|
||||
add_build_flag,
|
||||
add_define,
|
||||
add_global,
|
||||
add_library,
|
||||
add_build_flag,
|
||||
add_define,
|
||||
add_platformio_option,
|
||||
get_variable,
|
||||
get_variable_with_full_id,
|
||||
is_template,
|
||||
new_Pvariable,
|
||||
new_variable,
|
||||
process_lambda,
|
||||
progmem_array,
|
||||
safe_exp,
|
||||
statement,
|
||||
static_const_array,
|
||||
is_template,
|
||||
templatable,
|
||||
variable,
|
||||
with_local_variable,
|
||||
MockObj,
|
||||
MockObjClass,
|
||||
)
|
||||
from esphome.cpp_helpers import ( # noqa: F401
|
||||
from esphome.cpp_helpers import ( # noqa
|
||||
gpio_pin_expression,
|
||||
register_component,
|
||||
build_registry_entry,
|
||||
build_registry_list,
|
||||
extract_registry_entry_config,
|
||||
gpio_pin_expression,
|
||||
past_safe_mode,
|
||||
register_component,
|
||||
register_parented,
|
||||
past_safe_mode,
|
||||
)
|
||||
from esphome.cpp_types import ( # noqa: F401
|
||||
NAN,
|
||||
App,
|
||||
Application,
|
||||
Component,
|
||||
ComponentPtr,
|
||||
Controller,
|
||||
EntityBase,
|
||||
EntityCategory,
|
||||
ESPTime,
|
||||
GPIOPin,
|
||||
InternalGPIOPin,
|
||||
JsonObject,
|
||||
JsonObjectConst,
|
||||
Parented,
|
||||
PollingComponent,
|
||||
arduino_json_ns,
|
||||
bool_,
|
||||
const_char_ptr,
|
||||
double,
|
||||
esphome_ns,
|
||||
float_,
|
||||
from esphome.cpp_types import ( # noqa
|
||||
global_ns,
|
||||
gpio_Flags,
|
||||
int16,
|
||||
int32,
|
||||
int64,
|
||||
int_,
|
||||
void,
|
||||
nullptr,
|
||||
optional,
|
||||
size_t,
|
||||
float_,
|
||||
double,
|
||||
bool_,
|
||||
int_,
|
||||
std_ns,
|
||||
std_shared_ptr,
|
||||
std_string,
|
||||
std_string_ref,
|
||||
std_vector,
|
||||
uint8,
|
||||
uint16,
|
||||
uint32,
|
||||
uint64,
|
||||
void,
|
||||
int16,
|
||||
int32,
|
||||
int64,
|
||||
size_t,
|
||||
const_char_ptr,
|
||||
NAN,
|
||||
esphome_ns,
|
||||
App,
|
||||
EntityBase,
|
||||
Component,
|
||||
ComponentPtr,
|
||||
PollingComponent,
|
||||
Application,
|
||||
optional,
|
||||
arduino_json_ns,
|
||||
JsonObject,
|
||||
JsonObjectConst,
|
||||
Controller,
|
||||
GPIOPin,
|
||||
InternalGPIOPin,
|
||||
gpio_Flags,
|
||||
EntityCategory,
|
||||
Parented,
|
||||
ESPTime,
|
||||
)
|
||||
|
@ -1,10 +1,10 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import sensor, uart
|
||||
from esphome.const import (
|
||||
DEVICE_CLASS_DISTANCE,
|
||||
ICON_ARROW_EXPAND_VERTICAL,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_METER,
|
||||
ICON_ARROW_EXPAND_VERTICAL,
|
||||
DEVICE_CLASS_DISTANCE,
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@MrSuicideParrot"]
|
||||
|
@ -1,9 +1,9 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import sensor, uart
|
||||
from esphome.const import (
|
||||
DEVICE_CLASS_DISTANCE,
|
||||
ICON_ARROW_EXPAND_VERTICAL,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
ICON_ARROW_EXPAND_VERTICAL,
|
||||
DEVICE_CLASS_DISTANCE,
|
||||
UNIT_MILLIMETER,
|
||||
)
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
from esphome import pins
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import stepper
|
||||
import esphome.config_validation as cv
|
||||
import esphome.codegen as cg
|
||||
from esphome.const import CONF_DIR_PIN, CONF_ID, CONF_SLEEP_PIN, CONF_STEP_PIN
|
||||
|
||||
|
||||
a4988_ns = cg.esphome_ns.namespace("a4988")
|
||||
A4988 = a4988_ns.class_("A4988", stepper.Stepper, cg.Component)
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor
|
||||
from esphome.const import (
|
||||
CONF_EQUATION,
|
||||
CONF_HUMIDITY,
|
||||
CONF_TEMPERATURE,
|
||||
ICON_WATER,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
CONF_EQUATION,
|
||||
ICON_WATER,
|
||||
UNIT_GRAMS_PER_CUBIC_METER,
|
||||
)
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
from esphome import pins
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import output
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, CONF_METHOD, CONF_MIN_POWER
|
||||
from esphome import pins
|
||||
from esphome.components import output
|
||||
from esphome.const import CONF_ID, CONF_MIN_POWER, CONF_METHOD
|
||||
|
||||
CODEOWNERS = ["@glmnet"]
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import uart
|
||||
from esphome.components.light.effects import register_addressable_effect
|
||||
from esphome.components.light.types import AddressableLightEffect
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import uart
|
||||
from esphome.components.light.types import AddressableLightEffect
|
||||
from esphome.components.light.effects import register_addressable_effect
|
||||
from esphome.const import CONF_NAME, CONF_UART_ID
|
||||
|
||||
DEPENDENCIES = ["uart"]
|
||||
|
@ -1,6 +1,11 @@
|
||||
from esphome import pins
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import pins
|
||||
from esphome.const import CONF_ANALOG, CONF_INPUT, CONF_NUMBER
|
||||
|
||||
from esphome.core import CORE
|
||||
from esphome.components.esp32 import get_esp32_variant
|
||||
from esphome.const import PLATFORM_ESP8266
|
||||
from esphome.components.esp32.const import (
|
||||
VARIANT_ESP32,
|
||||
VARIANT_ESP32C2,
|
||||
@ -10,9 +15,6 @@ from esphome.components.esp32.const import (
|
||||
VARIANT_ESP32S2,
|
||||
VARIANT_ESP32S3,
|
||||
)
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ANALOG, CONF_INPUT, CONF_NUMBER, PLATFORM_ESP8266
|
||||
from esphome.core import CORE
|
||||
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
|
||||
@ -36,14 +38,6 @@ ATTENUATION_MODES = {
|
||||
"auto": "auto",
|
||||
}
|
||||
|
||||
sampling_mode = adc_ns.enum("SamplingMode", is_class=True)
|
||||
|
||||
SAMPLING_MODES = {
|
||||
"avg": sampling_mode.AVG,
|
||||
"min": sampling_mode.MIN,
|
||||
"max": sampling_mode.MAX,
|
||||
}
|
||||
|
||||
adc1_channel_t = cg.global_ns.enum("adc1_channel_t")
|
||||
adc2_channel_t = cg.global_ns.enum("adc2_channel_t")
|
||||
|
||||
@ -108,11 +102,11 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
|
||||
6: adc1_channel_t.ADC1_CHANNEL_6,
|
||||
},
|
||||
VARIANT_ESP32H2: {
|
||||
1: adc1_channel_t.ADC1_CHANNEL_0,
|
||||
2: adc1_channel_t.ADC1_CHANNEL_1,
|
||||
3: adc1_channel_t.ADC1_CHANNEL_2,
|
||||
4: adc1_channel_t.ADC1_CHANNEL_3,
|
||||
5: adc1_channel_t.ADC1_CHANNEL_4,
|
||||
0: adc1_channel_t.ADC1_CHANNEL_0,
|
||||
1: adc1_channel_t.ADC1_CHANNEL_1,
|
||||
2: adc1_channel_t.ADC1_CHANNEL_2,
|
||||
3: adc1_channel_t.ADC1_CHANNEL_3,
|
||||
4: adc1_channel_t.ADC1_CHANNEL_4,
|
||||
},
|
||||
}
|
||||
|
||||
|
332
esphome/components/adc/adc_sensor.cpp
Normal file
332
esphome/components/adc/adc_sensor.cpp
Normal file
@ -0,0 +1,332 @@
|
||||
#include "adc_sensor.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#ifdef USE_ESP8266
|
||||
#ifdef USE_ADC_SENSOR_VCC
|
||||
#include <Esp.h>
|
||||
ADC_MODE(ADC_VCC)
|
||||
#else
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_RP2040
|
||||
#ifdef CYW43_USES_VSYS_PIN
|
||||
#include "pico/cyw43_arch.h"
|
||||
#endif
|
||||
#include <hardware/adc.h>
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
|
||||
static const char *const TAG = "adc";
|
||||
|
||||
// 13-bit for S2, 12-bit for all other ESP32 variants
|
||||
#ifdef USE_ESP32
|
||||
static const adc_bits_width_t ADC_WIDTH_MAX_SOC_BITS = static_cast<adc_bits_width_t>(ADC_WIDTH_MAX - 1);
|
||||
|
||||
#ifndef SOC_ADC_RTC_MAX_BITWIDTH
|
||||
#if USE_ESP32_VARIANT_ESP32S2
|
||||
static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 13;
|
||||
#else
|
||||
static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 12;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1; // 4095 (12 bit) or 8191 (13 bit)
|
||||
static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1; // 2048 (12 bit) or 4096 (13 bit)
|
||||
#endif
|
||||
|
||||
#ifdef USE_RP2040
|
||||
extern "C"
|
||||
#endif
|
||||
void
|
||||
ADCSensor::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
|
||||
#if !defined(USE_ADC_SENSOR_VCC) && !defined(USE_RP2040)
|
||||
this->pin_->setup();
|
||||
#endif
|
||||
|
||||
#ifdef USE_ESP32
|
||||
if (this->channel1_ != ADC1_CHANNEL_MAX) {
|
||||
adc1_config_width(ADC_WIDTH_MAX_SOC_BITS);
|
||||
if (!this->autorange_) {
|
||||
adc1_config_channel_atten(this->channel1_, this->attenuation_);
|
||||
}
|
||||
} else if (this->channel2_ != ADC2_CHANNEL_MAX) {
|
||||
if (!this->autorange_) {
|
||||
adc2_config_channel_atten(this->channel2_, this->attenuation_);
|
||||
}
|
||||
}
|
||||
|
||||
// load characteristics for each attenuation
|
||||
for (int32_t i = 0; i <= ADC_ATTEN_DB_12_COMPAT; i++) {
|
||||
auto adc_unit = this->channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2;
|
||||
auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS,
|
||||
1100, // default vref
|
||||
&this->cal_characteristics_[i]);
|
||||
switch (cal_value) {
|
||||
case ESP_ADC_CAL_VAL_EFUSE_VREF:
|
||||
ESP_LOGV(TAG, "Using eFuse Vref for calibration");
|
||||
break;
|
||||
case ESP_ADC_CAL_VAL_EFUSE_TP:
|
||||
ESP_LOGV(TAG, "Using two-point eFuse Vref for calibration");
|
||||
break;
|
||||
case ESP_ADC_CAL_VAL_DEFAULT_VREF:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // USE_ESP32
|
||||
|
||||
#ifdef USE_RP2040
|
||||
static bool initialized = false;
|
||||
if (!initialized) {
|
||||
adc_init();
|
||||
initialized = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
ESP_LOGCONFIG(TAG, "ADC '%s' setup finished!", this->get_name().c_str());
|
||||
}
|
||||
|
||||
void ADCSensor::dump_config() {
|
||||
LOG_SENSOR("", "ADC Sensor", this);
|
||||
#if defined(USE_ESP8266) || defined(USE_LIBRETINY)
|
||||
#ifdef USE_ADC_SENSOR_VCC
|
||||
ESP_LOGCONFIG(TAG, " Pin: VCC");
|
||||
#else
|
||||
LOG_PIN(" Pin: ", this->pin_);
|
||||
#endif
|
||||
#endif // USE_ESP8266 || USE_LIBRETINY
|
||||
|
||||
#ifdef USE_ESP32
|
||||
LOG_PIN(" Pin: ", this->pin_);
|
||||
if (this->autorange_) {
|
||||
ESP_LOGCONFIG(TAG, " Attenuation: auto");
|
||||
} else {
|
||||
switch (this->attenuation_) {
|
||||
case ADC_ATTEN_DB_0:
|
||||
ESP_LOGCONFIG(TAG, " Attenuation: 0db");
|
||||
break;
|
||||
case ADC_ATTEN_DB_2_5:
|
||||
ESP_LOGCONFIG(TAG, " Attenuation: 2.5db");
|
||||
break;
|
||||
case ADC_ATTEN_DB_6:
|
||||
ESP_LOGCONFIG(TAG, " Attenuation: 6db");
|
||||
break;
|
||||
case ADC_ATTEN_DB_12_COMPAT:
|
||||
ESP_LOGCONFIG(TAG, " Attenuation: 12db");
|
||||
break;
|
||||
default: // This is to satisfy the unused ADC_ATTEN_MAX
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // USE_ESP32
|
||||
|
||||
#ifdef USE_RP2040
|
||||
if (this->is_temperature_) {
|
||||
ESP_LOGCONFIG(TAG, " Pin: Temperature");
|
||||
} else {
|
||||
#ifdef USE_ADC_SENSOR_VCC
|
||||
ESP_LOGCONFIG(TAG, " Pin: VCC");
|
||||
#else
|
||||
LOG_PIN(" Pin: ", this->pin_);
|
||||
#endif // USE_ADC_SENSOR_VCC
|
||||
}
|
||||
#endif // USE_RP2040
|
||||
ESP_LOGCONFIG(TAG, " Samples: %i", this->sample_count_);
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
float ADCSensor::get_setup_priority() const { return setup_priority::DATA; }
|
||||
void ADCSensor::update() {
|
||||
float value_v = this->sample();
|
||||
ESP_LOGV(TAG, "'%s': Got voltage=%.4fV", this->get_name().c_str(), value_v);
|
||||
this->publish_state(value_v);
|
||||
}
|
||||
|
||||
void ADCSensor::set_sample_count(uint8_t sample_count) {
|
||||
if (sample_count != 0) {
|
||||
this->sample_count_ = sample_count;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_ESP8266
|
||||
float ADCSensor::sample() {
|
||||
uint32_t raw = 0;
|
||||
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
||||
#ifdef USE_ADC_SENSOR_VCC
|
||||
raw += ESP.getVcc(); // NOLINT(readability-static-accessed-through-instance)
|
||||
#else
|
||||
raw += analogRead(this->pin_->get_pin()); // NOLINT
|
||||
#endif
|
||||
}
|
||||
raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero)
|
||||
if (this->output_raw_) {
|
||||
return raw;
|
||||
}
|
||||
return raw / 1024.0f;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_ESP32
|
||||
float ADCSensor::sample() {
|
||||
if (!this->autorange_) {
|
||||
uint32_t sum = 0;
|
||||
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
||||
int raw = -1;
|
||||
if (this->channel1_ != ADC1_CHANNEL_MAX) {
|
||||
raw = adc1_get_raw(this->channel1_);
|
||||
} else if (this->channel2_ != ADC2_CHANNEL_MAX) {
|
||||
adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw);
|
||||
}
|
||||
if (raw == -1) {
|
||||
return NAN;
|
||||
}
|
||||
sum += raw;
|
||||
}
|
||||
sum = (sum + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero)
|
||||
if (this->output_raw_) {
|
||||
return sum;
|
||||
}
|
||||
uint32_t mv = esp_adc_cal_raw_to_voltage(sum, &this->cal_characteristics_[(int32_t) this->attenuation_]);
|
||||
return mv / 1000.0f;
|
||||
}
|
||||
|
||||
int raw12 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX;
|
||||
|
||||
if (this->channel1_ != ADC1_CHANNEL_MAX) {
|
||||
adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_12_COMPAT);
|
||||
raw12 = adc1_get_raw(this->channel1_);
|
||||
if (raw12 < ADC_MAX) {
|
||||
adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_6);
|
||||
raw6 = adc1_get_raw(this->channel1_);
|
||||
if (raw6 < ADC_MAX) {
|
||||
adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_2_5);
|
||||
raw2 = adc1_get_raw(this->channel1_);
|
||||
if (raw2 < ADC_MAX) {
|
||||
adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_0);
|
||||
raw0 = adc1_get_raw(this->channel1_);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (this->channel2_ != ADC2_CHANNEL_MAX) {
|
||||
adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_12_COMPAT);
|
||||
adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw12);
|
||||
if (raw12 < ADC_MAX) {
|
||||
adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_6);
|
||||
adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6);
|
||||
if (raw6 < ADC_MAX) {
|
||||
adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_2_5);
|
||||
adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw2);
|
||||
if (raw2 < ADC_MAX) {
|
||||
adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_0);
|
||||
adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (raw0 == -1 || raw2 == -1 || raw6 == -1 || raw12 == -1) {
|
||||
return NAN;
|
||||
}
|
||||
|
||||
uint32_t mv12 = esp_adc_cal_raw_to_voltage(raw12, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_12_COMPAT]);
|
||||
uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_6]);
|
||||
uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]);
|
||||
uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]);
|
||||
|
||||
// Contribution of each value, in range 0-2048 (12 bit ADC) or 0-4096 (13 bit ADC)
|
||||
uint32_t c12 = std::min(raw12, ADC_HALF);
|
||||
uint32_t c6 = ADC_HALF - std::abs(raw6 - ADC_HALF);
|
||||
uint32_t c2 = ADC_HALF - std::abs(raw2 - ADC_HALF);
|
||||
uint32_t c0 = std::min(ADC_MAX - raw0, ADC_HALF);
|
||||
// max theoretical csum value is 4096*4 = 16384
|
||||
uint32_t csum = c12 + c6 + c2 + c0;
|
||||
|
||||
// each mv is max 3900; so max value is 3900*4096*4, fits in unsigned32
|
||||
uint32_t mv_scaled = (mv12 * c12) + (mv6 * c6) + (mv2 * c2) + (mv0 * c0);
|
||||
return mv_scaled / (float) (csum * 1000U);
|
||||
}
|
||||
#endif // USE_ESP32
|
||||
|
||||
#ifdef USE_RP2040
|
||||
float ADCSensor::sample() {
|
||||
if (this->is_temperature_) {
|
||||
adc_set_temp_sensor_enabled(true);
|
||||
delay(1);
|
||||
adc_select_input(4);
|
||||
uint32_t raw = 0;
|
||||
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
||||
raw += adc_read();
|
||||
}
|
||||
raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero)
|
||||
adc_set_temp_sensor_enabled(false);
|
||||
if (this->output_raw_) {
|
||||
return raw;
|
||||
}
|
||||
return raw * 3.3f / 4096.0f;
|
||||
} else {
|
||||
uint8_t pin = this->pin_->get_pin();
|
||||
#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
|
||||
cyw43_thread_enter();
|
||||
}
|
||||
#endif // CYW43_USES_VSYS_PIN
|
||||
|
||||
adc_gpio_init(pin);
|
||||
adc_select_input(pin - 26);
|
||||
|
||||
uint32_t raw = 0;
|
||||
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
||||
raw += adc_read();
|
||||
}
|
||||
raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero)
|
||||
|
||||
#ifdef CYW43_USES_VSYS_PIN
|
||||
if (pin == PICO_VSYS_PIN) {
|
||||
cyw43_thread_exit();
|
||||
}
|
||||
#endif // CYW43_USES_VSYS_PIN
|
||||
|
||||
if (this->output_raw_) {
|
||||
return raw;
|
||||
}
|
||||
float coeff = pin == PICO_VSYS_PIN ? 3.0 : 1.0;
|
||||
return raw * 3.3f / 4096.0f * coeff;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIBRETINY
|
||||
float ADCSensor::sample() {
|
||||
uint32_t raw = 0;
|
||||
if (this->output_raw_) {
|
||||
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
||||
raw += analogRead(this->pin_->get_pin()); // NOLINT
|
||||
}
|
||||
raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero)
|
||||
return raw;
|
||||
}
|
||||
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
||||
raw += analogReadVoltage(this->pin_->get_pin()); // NOLINT
|
||||
}
|
||||
raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_; // NOLINT(clang-analyzer-core.DivideZero)
|
||||
return raw / 1000.0f;
|
||||
}
|
||||
#endif // USE_LIBRETINY
|
||||
|
||||
#ifdef USE_ESP8266
|
||||
std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; }
|
||||
#endif
|
||||
|
||||
} // namespace adc
|
||||
} // namespace esphome
|
@ -3,12 +3,13 @@
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/components/voltage_sampler/voltage_sampler.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
#ifdef USE_ESP32
|
||||
#include <esp_adc_cal.h>
|
||||
#include "driver/adc.h"
|
||||
#endif // USE_ESP32
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
@ -28,21 +29,6 @@ static const adc_atten_t ADC_ATTEN_DB_12_COMPAT = ADC_ATTEN_DB_11;
|
||||
#endif
|
||||
#endif // USE_ESP32
|
||||
|
||||
enum class SamplingMode : uint8_t { AVG = 0, MIN = 1, MAX = 2 };
|
||||
const LogString *sampling_mode_to_str(SamplingMode mode);
|
||||
|
||||
class Aggregator {
|
||||
public:
|
||||
void add_sample(uint32_t value);
|
||||
uint32_t aggregate();
|
||||
Aggregator(SamplingMode mode);
|
||||
|
||||
protected:
|
||||
SamplingMode mode_{SamplingMode::AVG};
|
||||
uint32_t aggr_{0};
|
||||
uint32_t samples_{0};
|
||||
};
|
||||
|
||||
class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler {
|
||||
public:
|
||||
#ifdef USE_ESP32
|
||||
@ -57,7 +43,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
|
||||
this->channel1_ = ADC1_CHANNEL_MAX;
|
||||
}
|
||||
void set_autorange(bool autorange) { this->autorange_ = autorange; }
|
||||
#endif // USE_ESP32
|
||||
#endif
|
||||
|
||||
/// Update ADC values
|
||||
void update() override;
|
||||
@ -69,26 +55,24 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
|
||||
void set_pin(InternalGPIOPin *pin) { this->pin_ = pin; }
|
||||
void set_output_raw(bool output_raw) { this->output_raw_ = output_raw; }
|
||||
void set_sample_count(uint8_t sample_count);
|
||||
void set_sampling_mode(SamplingMode sampling_mode);
|
||||
float sample() override;
|
||||
|
||||
#ifdef USE_ESP8266
|
||||
std::string unique_id() override;
|
||||
#endif // USE_ESP8266
|
||||
#endif
|
||||
|
||||
#ifdef USE_RP2040
|
||||
void set_is_temperature() { this->is_temperature_ = true; }
|
||||
#endif // USE_RP2040
|
||||
#endif
|
||||
|
||||
protected:
|
||||
InternalGPIOPin *pin_;
|
||||
bool output_raw_{false};
|
||||
uint8_t sample_count_{1};
|
||||
SamplingMode sampling_mode_{SamplingMode::AVG};
|
||||
|
||||
#ifdef USE_RP2040
|
||||
bool is_temperature_{false};
|
||||
#endif // USE_RP2040
|
||||
#endif
|
||||
|
||||
#ifdef USE_ESP32
|
||||
adc_atten_t attenuation_{ADC_ATTEN_DB_0};
|
||||
@ -99,8 +83,8 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
|
||||
esp_adc_cal_characteristics_t cal_characteristics_[SOC_ADC_ATTEN_NUM] = {};
|
||||
#else
|
||||
esp_adc_cal_characteristics_t cal_characteristics_[ADC_ATTEN_MAX] = {};
|
||||
#endif // ESP_IDF_VERSION_MAJOR
|
||||
#endif // USE_ESP32
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace adc
|
||||
|
@ -1,79 +0,0 @@
|
||||
#include "adc_sensor.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
|
||||
static const char *const TAG = "adc.common";
|
||||
|
||||
const LogString *sampling_mode_to_str(SamplingMode mode) {
|
||||
switch (mode) {
|
||||
case SamplingMode::AVG:
|
||||
return LOG_STR("average");
|
||||
case SamplingMode::MIN:
|
||||
return LOG_STR("minimum");
|
||||
case SamplingMode::MAX:
|
||||
return LOG_STR("maximum");
|
||||
}
|
||||
return LOG_STR("unknown");
|
||||
}
|
||||
|
||||
Aggregator::Aggregator(SamplingMode mode) {
|
||||
this->mode_ = mode;
|
||||
// set to max uint if mode is "min"
|
||||
if (mode == SamplingMode::MIN) {
|
||||
this->aggr_ = UINT32_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
void Aggregator::add_sample(uint32_t value) {
|
||||
this->samples_ += 1;
|
||||
|
||||
switch (this->mode_) {
|
||||
case SamplingMode::AVG:
|
||||
this->aggr_ += value;
|
||||
break;
|
||||
|
||||
case SamplingMode::MIN:
|
||||
if (value < this->aggr_) {
|
||||
this->aggr_ = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case SamplingMode::MAX:
|
||||
if (value > this->aggr_) {
|
||||
this->aggr_ = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Aggregator::aggregate() {
|
||||
if (this->mode_ == SamplingMode::AVG) {
|
||||
if (this->samples_ == 0) {
|
||||
return this->aggr_;
|
||||
}
|
||||
|
||||
return (this->aggr_ + (this->samples_ >> 1)) / this->samples_; // NOLINT(clang-analyzer-core.DivideZero)
|
||||
}
|
||||
|
||||
return this->aggr_;
|
||||
}
|
||||
|
||||
void ADCSensor::update() {
|
||||
float value_v = this->sample();
|
||||
ESP_LOGV(TAG, "'%s': Got voltage=%.4fV", this->get_name().c_str(), value_v);
|
||||
this->publish_state(value_v);
|
||||
}
|
||||
|
||||
void ADCSensor::set_sample_count(uint8_t sample_count) {
|
||||
if (sample_count != 0) {
|
||||
this->sample_count_ = sample_count;
|
||||
}
|
||||
}
|
||||
|
||||
void ADCSensor::set_sampling_mode(SamplingMode sampling_mode) { this->sampling_mode_ = sampling_mode; }
|
||||
|
||||
float ADCSensor::get_setup_priority() const { return setup_priority::DATA; }
|
||||
|
||||
} // namespace adc
|
||||
} // namespace esphome
|
@ -1,166 +0,0 @@
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "adc_sensor.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
|
||||
static const char *const TAG = "adc.esp32";
|
||||
|
||||
static const adc_bits_width_t ADC_WIDTH_MAX_SOC_BITS = static_cast<adc_bits_width_t>(ADC_WIDTH_MAX - 1);
|
||||
|
||||
#ifndef SOC_ADC_RTC_MAX_BITWIDTH
|
||||
#if USE_ESP32_VARIANT_ESP32S2
|
||||
static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 13;
|
||||
#else
|
||||
static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 12;
|
||||
#endif // USE_ESP32_VARIANT_ESP32S2
|
||||
#endif // SOC_ADC_RTC_MAX_BITWIDTH
|
||||
|
||||
static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1;
|
||||
static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1;
|
||||
|
||||
void ADCSensor::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
|
||||
|
||||
if (this->channel1_ != ADC1_CHANNEL_MAX) {
|
||||
adc1_config_width(ADC_WIDTH_MAX_SOC_BITS);
|
||||
if (!this->autorange_) {
|
||||
adc1_config_channel_atten(this->channel1_, this->attenuation_);
|
||||
}
|
||||
} else if (this->channel2_ != ADC2_CHANNEL_MAX) {
|
||||
if (!this->autorange_) {
|
||||
adc2_config_channel_atten(this->channel2_, this->attenuation_);
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i <= ADC_ATTEN_DB_12_COMPAT; i++) {
|
||||
auto adc_unit = this->channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2;
|
||||
auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS,
|
||||
1100, // default vref
|
||||
&this->cal_characteristics_[i]);
|
||||
switch (cal_value) {
|
||||
case ESP_ADC_CAL_VAL_EFUSE_VREF:
|
||||
ESP_LOGV(TAG, "Using eFuse Vref for calibration");
|
||||
break;
|
||||
case ESP_ADC_CAL_VAL_EFUSE_TP:
|
||||
ESP_LOGV(TAG, "Using two-point eFuse Vref for calibration");
|
||||
break;
|
||||
case ESP_ADC_CAL_VAL_DEFAULT_VREF:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ADCSensor::dump_config() {
|
||||
LOG_SENSOR("", "ADC Sensor", this);
|
||||
LOG_PIN(" Pin: ", this->pin_);
|
||||
if (this->autorange_) {
|
||||
ESP_LOGCONFIG(TAG, " Attenuation: auto");
|
||||
} else {
|
||||
switch (this->attenuation_) {
|
||||
case ADC_ATTEN_DB_0:
|
||||
ESP_LOGCONFIG(TAG, " Attenuation: 0db");
|
||||
break;
|
||||
case ADC_ATTEN_DB_2_5:
|
||||
ESP_LOGCONFIG(TAG, " Attenuation: 2.5db");
|
||||
break;
|
||||
case ADC_ATTEN_DB_6:
|
||||
ESP_LOGCONFIG(TAG, " Attenuation: 6db");
|
||||
break;
|
||||
case ADC_ATTEN_DB_12_COMPAT:
|
||||
ESP_LOGCONFIG(TAG, " Attenuation: 12db");
|
||||
break;
|
||||
default: // This is to satisfy the unused ADC_ATTEN_MAX
|
||||
break;
|
||||
}
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, " Samples: %i", this->sample_count_);
|
||||
ESP_LOGCONFIG(TAG, " Sampling mode: %s", LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_)));
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
float ADCSensor::sample() {
|
||||
if (!this->autorange_) {
|
||||
auto aggr = Aggregator(this->sampling_mode_);
|
||||
|
||||
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
||||
int raw = -1;
|
||||
if (this->channel1_ != ADC1_CHANNEL_MAX) {
|
||||
raw = adc1_get_raw(this->channel1_);
|
||||
} else if (this->channel2_ != ADC2_CHANNEL_MAX) {
|
||||
adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw);
|
||||
}
|
||||
if (raw == -1) {
|
||||
return NAN;
|
||||
}
|
||||
|
||||
aggr.add_sample(raw);
|
||||
}
|
||||
if (this->output_raw_) {
|
||||
return aggr.aggregate();
|
||||
}
|
||||
uint32_t mv =
|
||||
esp_adc_cal_raw_to_voltage(aggr.aggregate(), &this->cal_characteristics_[(int32_t) this->attenuation_]);
|
||||
return mv / 1000.0f;
|
||||
}
|
||||
|
||||
int raw12 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX;
|
||||
|
||||
if (this->channel1_ != ADC1_CHANNEL_MAX) {
|
||||
adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_12_COMPAT);
|
||||
raw12 = adc1_get_raw(this->channel1_);
|
||||
if (raw12 < ADC_MAX) {
|
||||
adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_6);
|
||||
raw6 = adc1_get_raw(this->channel1_);
|
||||
if (raw6 < ADC_MAX) {
|
||||
adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_2_5);
|
||||
raw2 = adc1_get_raw(this->channel1_);
|
||||
if (raw2 < ADC_MAX) {
|
||||
adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_0);
|
||||
raw0 = adc1_get_raw(this->channel1_);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (this->channel2_ != ADC2_CHANNEL_MAX) {
|
||||
adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_12_COMPAT);
|
||||
adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw12);
|
||||
if (raw12 < ADC_MAX) {
|
||||
adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_6);
|
||||
adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6);
|
||||
if (raw6 < ADC_MAX) {
|
||||
adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_2_5);
|
||||
adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw2);
|
||||
if (raw2 < ADC_MAX) {
|
||||
adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_0);
|
||||
adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (raw0 == -1 || raw2 == -1 || raw6 == -1 || raw12 == -1) {
|
||||
return NAN;
|
||||
}
|
||||
|
||||
uint32_t mv12 = esp_adc_cal_raw_to_voltage(raw12, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_12_COMPAT]);
|
||||
uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_6]);
|
||||
uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]);
|
||||
uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]);
|
||||
|
||||
uint32_t c12 = std::min(raw12, ADC_HALF);
|
||||
uint32_t c6 = ADC_HALF - std::abs(raw6 - ADC_HALF);
|
||||
uint32_t c2 = ADC_HALF - std::abs(raw2 - ADC_HALF);
|
||||
uint32_t c0 = std::min(ADC_MAX - raw0, ADC_HALF);
|
||||
uint32_t csum = c12 + c6 + c2 + c0;
|
||||
|
||||
uint32_t mv_scaled = (mv12 * c12) + (mv6 * c6) + (mv2 * c2) + (mv0 * c0);
|
||||
return mv_scaled / (float) (csum * 1000U);
|
||||
}
|
||||
|
||||
} // namespace adc
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ESP32
|
@ -1,62 +0,0 @@
|
||||
#ifdef USE_ESP8266
|
||||
|
||||
#include "adc_sensor.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#ifdef USE_ADC_SENSOR_VCC
|
||||
#include <Esp.h>
|
||||
ADC_MODE(ADC_VCC)
|
||||
#else
|
||||
#include <Arduino.h>
|
||||
#endif // USE_ADC_SENSOR_VCC
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
|
||||
static const char *const TAG = "adc.esp8266";
|
||||
|
||||
void ADCSensor::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
|
||||
#ifndef USE_ADC_SENSOR_VCC
|
||||
this->pin_->setup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ADCSensor::dump_config() {
|
||||
LOG_SENSOR("", "ADC Sensor", this);
|
||||
#ifdef USE_ADC_SENSOR_VCC
|
||||
ESP_LOGCONFIG(TAG, " Pin: VCC");
|
||||
#else
|
||||
LOG_PIN(" Pin: ", this->pin_);
|
||||
#endif // USE_ADC_SENSOR_VCC
|
||||
ESP_LOGCONFIG(TAG, " Samples: %i", this->sample_count_);
|
||||
ESP_LOGCONFIG(TAG, " Sampling mode: %s", LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_)));
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
float ADCSensor::sample() {
|
||||
auto aggr = Aggregator(this->sampling_mode_);
|
||||
|
||||
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
||||
uint32_t raw = 0;
|
||||
#ifdef USE_ADC_SENSOR_VCC
|
||||
raw = ESP.getVcc(); // NOLINT(readability-static-accessed-through-instance)
|
||||
#else
|
||||
raw = analogRead(this->pin_->get_pin()); // NOLINT
|
||||
#endif // USE_ADC_SENSOR_VCC
|
||||
aggr.add_sample(raw);
|
||||
}
|
||||
|
||||
if (this->output_raw_) {
|
||||
return aggr.aggregate();
|
||||
}
|
||||
return aggr.aggregate() / 1024.0f;
|
||||
}
|
||||
|
||||
std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; }
|
||||
|
||||
} // namespace adc
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ESP8266
|
@ -1,53 +0,0 @@
|
||||
#ifdef USE_LIBRETINY
|
||||
|
||||
#include "adc_sensor.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
|
||||
static const char *const TAG = "adc.libretiny";
|
||||
|
||||
void ADCSensor::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
|
||||
#ifndef USE_ADC_SENSOR_VCC
|
||||
this->pin_->setup();
|
||||
#endif // !USE_ADC_SENSOR_VCC
|
||||
}
|
||||
|
||||
void ADCSensor::dump_config() {
|
||||
LOG_SENSOR("", "ADC Sensor", this);
|
||||
#ifdef USE_ADC_SENSOR_VCC
|
||||
ESP_LOGCONFIG(TAG, " Pin: VCC");
|
||||
#else // USE_ADC_SENSOR_VCC
|
||||
LOG_PIN(" Pin: ", this->pin_);
|
||||
#endif // USE_ADC_SENSOR_VCC
|
||||
ESP_LOGCONFIG(TAG, " Samples: %i", this->sample_count_);
|
||||
ESP_LOGCONFIG(TAG, " Sampling mode: %s", LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_)));
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
float ADCSensor::sample() {
|
||||
uint32_t raw = 0;
|
||||
auto aggr = Aggregator(this->sampling_mode_);
|
||||
|
||||
if (this->output_raw_) {
|
||||
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
||||
raw = analogRead(this->pin_->get_pin()); // NOLINT
|
||||
aggr.add_sample(raw);
|
||||
}
|
||||
return aggr.aggregate();
|
||||
}
|
||||
|
||||
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
||||
raw = analogReadVoltage(this->pin_->get_pin()); // NOLINT
|
||||
aggr.add_sample(raw);
|
||||
}
|
||||
|
||||
return aggr.aggregate() / 1000.0f;
|
||||
}
|
||||
|
||||
} // namespace adc
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_LIBRETINY
|
@ -1,96 +0,0 @@
|
||||
#ifdef USE_RP2040
|
||||
|
||||
#include "adc_sensor.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#ifdef CYW43_USES_VSYS_PIN
|
||||
#include "pico/cyw43_arch.h"
|
||||
#endif // CYW43_USES_VSYS_PIN
|
||||
#include <hardware/adc.h>
|
||||
|
||||
namespace esphome {
|
||||
namespace adc {
|
||||
|
||||
static const char *const TAG = "adc.rp2040";
|
||||
|
||||
void ADCSensor::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
|
||||
static bool initialized = false;
|
||||
if (!initialized) {
|
||||
adc_init();
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ADCSensor::dump_config() {
|
||||
LOG_SENSOR("", "ADC Sensor", this);
|
||||
if (this->is_temperature_) {
|
||||
ESP_LOGCONFIG(TAG, " Pin: Temperature");
|
||||
} else {
|
||||
#ifdef USE_ADC_SENSOR_VCC
|
||||
ESP_LOGCONFIG(TAG, " Pin: VCC");
|
||||
#else
|
||||
LOG_PIN(" Pin: ", this->pin_);
|
||||
#endif // USE_ADC_SENSOR_VCC
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, " Samples: %i", this->sample_count_);
|
||||
ESP_LOGCONFIG(TAG, " Sampling mode: %s", LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_)));
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
float ADCSensor::sample() {
|
||||
uint32_t raw = 0;
|
||||
auto aggr = Aggregator(this->sampling_mode_);
|
||||
|
||||
if (this->is_temperature_) {
|
||||
adc_set_temp_sensor_enabled(true);
|
||||
delay(1);
|
||||
adc_select_input(4);
|
||||
|
||||
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
||||
raw = adc_read();
|
||||
aggr.add_sample(raw);
|
||||
}
|
||||
adc_set_temp_sensor_enabled(false);
|
||||
if (this->output_raw_) {
|
||||
return aggr.aggregate();
|
||||
}
|
||||
return aggr.aggregate() * 3.3f / 4096.0f;
|
||||
}
|
||||
|
||||
uint8_t pin = this->pin_->get_pin();
|
||||
#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
|
||||
cyw43_thread_enter();
|
||||
}
|
||||
#endif // CYW43_USES_VSYS_PIN
|
||||
|
||||
adc_gpio_init(pin);
|
||||
adc_select_input(pin - 26);
|
||||
|
||||
for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
|
||||
raw = adc_read();
|
||||
aggr.add_sample(raw);
|
||||
}
|
||||
|
||||
#ifdef CYW43_USES_VSYS_PIN
|
||||
if (pin == PICO_VSYS_PIN) {
|
||||
cyw43_thread_exit();
|
||||
}
|
||||
#endif // CYW43_USES_VSYS_PIN
|
||||
|
||||
if (this->output_raw_) {
|
||||
return aggr.aggregate();
|
||||
}
|
||||
float coeff = pin == PICO_VSYS_PIN ? 3.0f : 1.0f;
|
||||
return aggr.aggregate() * 3.3f / 4096.0f * coeff;
|
||||
}
|
||||
|
||||
} // namespace adc
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_RP2040
|
@ -1,9 +1,11 @@
|
||||
import logging
|
||||
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
import esphome.final_validate as fv
|
||||
from esphome.core import CORE
|
||||
from esphome.components import sensor, voltage_sampler
|
||||
from esphome.components.esp32 import get_esp32_variant
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_ATTENUATION,
|
||||
CONF_ID,
|
||||
@ -15,14 +17,10 @@ from esphome.const import (
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_VOLT,
|
||||
)
|
||||
from esphome.core import CORE
|
||||
import esphome.final_validate as fv
|
||||
|
||||
from . import (
|
||||
ATTENUATION_MODES,
|
||||
ESP32_VARIANT_ADC1_PIN_TO_CHANNEL,
|
||||
ESP32_VARIANT_ADC2_PIN_TO_CHANNEL,
|
||||
SAMPLING_MODES,
|
||||
adc_ns,
|
||||
validate_adc_pin,
|
||||
)
|
||||
@ -32,11 +30,9 @@ _LOGGER = logging.getLogger(__name__)
|
||||
AUTO_LOAD = ["voltage_sampler"]
|
||||
|
||||
CONF_SAMPLES = "samples"
|
||||
CONF_SAMPLING_MODE = "sampling_mode"
|
||||
|
||||
|
||||
_attenuation = cv.enum(ATTENUATION_MODES, lower=True)
|
||||
_sampling_mode = cv.enum(SAMPLING_MODES, lower=True)
|
||||
|
||||
|
||||
def validate_config(config):
|
||||
@ -92,7 +88,6 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.only_on_esp32, _attenuation
|
||||
),
|
||||
cv.Optional(CONF_SAMPLES, default=1): cv.int_range(min=1, max=255),
|
||||
cv.Optional(CONF_SAMPLING_MODE, default="avg"): _sampling_mode,
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("60s")),
|
||||
@ -117,7 +112,6 @@ async def to_code(config):
|
||||
|
||||
cg.add(var.set_output_raw(config[CONF_RAW]))
|
||||
cg.add(var.set_sample_count(config[CONF_SAMPLES]))
|
||||
cg.add(var.set_sampling_mode(config[CONF_SAMPLING_MODE]))
|
||||
|
||||
if attenuation := config.get(CONF_ATTENUATION):
|
||||
if attenuation == "auto":
|
||||
|
@ -1,6 +1,6 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import spi
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import spi
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
DEPENDENCIES = ["spi"]
|
||||
|
@ -1,9 +1,9 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import sensor, voltage_sampler
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_CHANNEL, CONF_ID
|
||||
from esphome.components import sensor, voltage_sampler
|
||||
from esphome.const import CONF_ID, CONF_CHANNEL
|
||||
|
||||
from .. import ADC128S102, adc128s102_ns
|
||||
from .. import adc128s102_ns, ADC128S102
|
||||
|
||||
AUTO_LOAD = ["voltage_sampler"]
|
||||
DEPENDENCIES = ["adc128s102"]
|
||||
|
@ -1,15 +1,15 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import display, light
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import display, light
|
||||
from esphome.const import (
|
||||
CONF_ADDRESSABLE_LIGHT_ID,
|
||||
CONF_HEIGHT,
|
||||
CONF_ID,
|
||||
CONF_LAMBDA,
|
||||
CONF_PAGES,
|
||||
CONF_PIXEL_MAPPER,
|
||||
CONF_UPDATE_INTERVAL,
|
||||
CONF_ADDRESSABLE_LIGHT_ID,
|
||||
CONF_HEIGHT,
|
||||
CONF_WIDTH,
|
||||
CONF_UPDATE_INTERVAL,
|
||||
CONF_PIXEL_MAPPER,
|
||||
)
|
||||
|
||||
CODEOWNERS = ["@justfalter"]
|
||||
|
@ -1,7 +1,7 @@
|
||||
from esphome import pins
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import i2c, sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor, i2c
|
||||
from esphome import pins
|
||||
from esphome.const import (
|
||||
CONF_ACTIVE_POWER,
|
||||
CONF_APPARENT_POWER,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import esphome.config_validation as cv
|
||||
|
||||
CONFIG_SCHEMA = cv.invalid(
|
||||
CONFIG_SCHEMA = CONFIG_SCHEMA = cv.invalid(
|
||||
"The ade7953 sensor component has been renamed to ade7953_i2c."
|
||||
)
|
||||
|
@ -1,27 +1,27 @@
|
||||
from esphome import pins
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor
|
||||
from esphome import pins
|
||||
from esphome.const import (
|
||||
CONF_FREQUENCY,
|
||||
CONF_IRQ_PIN,
|
||||
CONF_VOLTAGE,
|
||||
CONF_FREQUENCY,
|
||||
CONF_VOLTAGE_GAIN,
|
||||
DEVICE_CLASS_APPARENT_POWER,
|
||||
DEVICE_CLASS_CURRENT,
|
||||
DEVICE_CLASS_FREQUENCY,
|
||||
DEVICE_CLASS_APPARENT_POWER,
|
||||
DEVICE_CLASS_POWER,
|
||||
DEVICE_CLASS_POWER_FACTOR,
|
||||
DEVICE_CLASS_REACTIVE_POWER,
|
||||
DEVICE_CLASS_POWER_FACTOR,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
DEVICE_CLASS_FREQUENCY,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_AMPERE,
|
||||
UNIT_HERTZ,
|
||||
UNIT_PERCENT,
|
||||
UNIT_VOLT,
|
||||
UNIT_HERTZ,
|
||||
UNIT_AMPERE,
|
||||
UNIT_VOLT_AMPS,
|
||||
UNIT_VOLT_AMPS_REACTIVE,
|
||||
UNIT_WATT,
|
||||
UNIT_VOLT_AMPS_REACTIVE,
|
||||
UNIT_PERCENT,
|
||||
)
|
||||
|
||||
CONF_CURRENT_A = "current_a"
|
||||
|
@ -1,8 +1,9 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import ade7953_base, i2c
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c, ade7953_base
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
|
||||
DEPENDENCIES = ["i2c"]
|
||||
AUTO_LOAD = ["ade7953_base"]
|
||||
|
||||
|
@ -60,7 +60,7 @@ bool AdE7953Spi::ade_read_16(uint16_t reg, uint16_t *value) {
|
||||
this->write_byte16(reg);
|
||||
this->transfer_byte(0x80);
|
||||
uint8_t recv[2];
|
||||
this->read_array(recv, 2);
|
||||
this->read_array(recv, 4);
|
||||
*value = encode_uint16(recv[0], recv[1]);
|
||||
this->disable();
|
||||
return false;
|
||||
|
@ -1,8 +1,9 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import ade7953_base, spi
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import spi, ade7953_base
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
|
||||
DEPENDENCIES = ["spi"]
|
||||
AUTO_LOAD = ["ade7953_base"]
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import i2c
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
DEPENDENCIES = ["i2c"]
|
||||
|
@ -9,6 +9,8 @@ static const char *const TAG = "ads1115";
|
||||
static const uint8_t ADS1115_REGISTER_CONVERSION = 0x00;
|
||||
static const uint8_t ADS1115_REGISTER_CONFIG = 0x01;
|
||||
|
||||
static const uint8_t ADS1115_DATA_RATE_860_SPS = 0b111; // 3300_SPS for ADS1015
|
||||
|
||||
void ADS1115Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up ADS1115...");
|
||||
uint16_t value;
|
||||
@ -41,9 +43,9 @@ void ADS1115Component::setup() {
|
||||
config |= 0b0000000100000000;
|
||||
}
|
||||
|
||||
// Set data rate - 860 samples per second
|
||||
// Set data rate - 860 samples per second (we're in singleshot mode)
|
||||
// 0bxxxxxxxx100xxxxx
|
||||
config |= ADS1115_860SPS << 5;
|
||||
config |= ADS1115_DATA_RATE_860_SPS << 5;
|
||||
|
||||
// Set comparator mode - hysteresis
|
||||
// 0bxxxxxxxxxxx0xxxx
|
||||
@ -75,7 +77,7 @@ void ADS1115Component::dump_config() {
|
||||
}
|
||||
}
|
||||
float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain,
|
||||
ADS1115Resolution resolution, ADS1115Samplerate samplerate) {
|
||||
ADS1115Resolution resolution) {
|
||||
uint16_t config = this->prev_config_;
|
||||
// Multiplexer
|
||||
// 0bxBBBxxxxxxxxxxxx
|
||||
@ -87,11 +89,6 @@ float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1
|
||||
config &= 0b1111000111111111;
|
||||
config |= (gain & 0b111) << 9;
|
||||
|
||||
// Sample rate
|
||||
// 0bxxxxxxxxBBBxxxxx
|
||||
config &= 0b1111111100011111;
|
||||
config |= (samplerate & 0b111) << 5;
|
||||
|
||||
if (!this->continuous_mode_) {
|
||||
// Start conversion
|
||||
config |= 0b1000000000000000;
|
||||
@ -104,54 +101,8 @@ float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1
|
||||
}
|
||||
this->prev_config_ = config;
|
||||
|
||||
// Delay calculated as: ceil((1000/SPS)+.5)
|
||||
if (resolution == ADS1015_12_BITS) {
|
||||
switch (samplerate) {
|
||||
case ADS1115_8SPS:
|
||||
delay(9);
|
||||
break;
|
||||
case ADS1115_16SPS:
|
||||
delay(5);
|
||||
break;
|
||||
case ADS1115_32SPS:
|
||||
delay(3);
|
||||
break;
|
||||
case ADS1115_64SPS:
|
||||
case ADS1115_128SPS:
|
||||
delay(2);
|
||||
break;
|
||||
default:
|
||||
delay(1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (samplerate) {
|
||||
case ADS1115_8SPS:
|
||||
delay(126); // NOLINT
|
||||
break;
|
||||
case ADS1115_16SPS:
|
||||
delay(63); // NOLINT
|
||||
break;
|
||||
case ADS1115_32SPS:
|
||||
delay(32);
|
||||
break;
|
||||
case ADS1115_64SPS:
|
||||
delay(17);
|
||||
break;
|
||||
case ADS1115_128SPS:
|
||||
delay(9);
|
||||
break;
|
||||
case ADS1115_250SPS:
|
||||
delay(5);
|
||||
break;
|
||||
case ADS1115_475SPS:
|
||||
delay(3);
|
||||
break;
|
||||
case ADS1115_860SPS:
|
||||
delay(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// about 1.2 ms with 860 samples per second
|
||||
delay(2);
|
||||
|
||||
// in continuous mode, conversion will always be running, rely on the delay
|
||||
// to ensure conversion is taking place with the correct settings
|
||||
|
@ -33,17 +33,6 @@ enum ADS1115Resolution {
|
||||
ADS1015_12_BITS = 12,
|
||||
};
|
||||
|
||||
enum ADS1115Samplerate {
|
||||
ADS1115_8SPS = 0b000,
|
||||
ADS1115_16SPS = 0b001,
|
||||
ADS1115_32SPS = 0b010,
|
||||
ADS1115_64SPS = 0b011,
|
||||
ADS1115_128SPS = 0b100,
|
||||
ADS1115_250SPS = 0b101,
|
||||
ADS1115_475SPS = 0b110,
|
||||
ADS1115_860SPS = 0b111
|
||||
};
|
||||
|
||||
class ADS1115Component : public Component, public i2c::I2CDevice {
|
||||
public:
|
||||
void setup() override;
|
||||
@ -53,8 +42,7 @@ class ADS1115Component : public Component, public i2c::I2CDevice {
|
||||
void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; }
|
||||
|
||||
/// Helper method to request a measurement from a sensor.
|
||||
float request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution,
|
||||
ADS1115Samplerate samplerate);
|
||||
float request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution);
|
||||
|
||||
protected:
|
||||
uint16_t prev_config_{0};
|
||||
|
@ -1,18 +1,16 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import sensor, voltage_sampler
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor, voltage_sampler
|
||||
from esphome.const import (
|
||||
CONF_GAIN,
|
||||
CONF_ID,
|
||||
CONF_MULTIPLEXER,
|
||||
CONF_RESOLUTION,
|
||||
CONF_SAMPLE_RATE,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_VOLT,
|
||||
CONF_ID,
|
||||
)
|
||||
|
||||
from .. import CONF_ADS1115_ID, ADS1115Component, ads1115_ns
|
||||
from .. import ads1115_ns, ADS1115Component, CONF_ADS1115_ID
|
||||
|
||||
AUTO_LOAD = ["voltage_sampler"]
|
||||
DEPENDENCIES = ["ads1115"]
|
||||
@ -45,17 +43,6 @@ RESOLUTION = {
|
||||
"12_BITS": ADS1115Resolution.ADS1015_12_BITS,
|
||||
}
|
||||
|
||||
ADS1115Samplerate = ads1115_ns.enum("ADS1115Samplerate")
|
||||
SAMPLERATE = {
|
||||
"8": ADS1115Samplerate.ADS1115_8SPS,
|
||||
"16": ADS1115Samplerate.ADS1115_16SPS,
|
||||
"32": ADS1115Samplerate.ADS1115_32SPS,
|
||||
"64": ADS1115Samplerate.ADS1115_64SPS,
|
||||
"128": ADS1115Samplerate.ADS1115_128SPS,
|
||||
"250": ADS1115Samplerate.ADS1115_250SPS,
|
||||
"475": ADS1115Samplerate.ADS1115_475SPS,
|
||||
"860": ADS1115Samplerate.ADS1115_860SPS,
|
||||
}
|
||||
|
||||
ADS1115Sensor = ads1115_ns.class_(
|
||||
"ADS1115Sensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler
|
||||
@ -77,9 +64,6 @@ CONFIG_SCHEMA = (
|
||||
cv.Optional(CONF_RESOLUTION, default="16_BITS"): cv.enum(
|
||||
RESOLUTION, upper=True, space="_"
|
||||
),
|
||||
cv.Optional(CONF_SAMPLE_RATE, default="860"): cv.enum(
|
||||
SAMPLERATE, string=True
|
||||
),
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("60s"))
|
||||
@ -95,4 +79,3 @@ async def to_code(config):
|
||||
cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER]))
|
||||
cg.add(var.set_gain(config[CONF_GAIN]))
|
||||
cg.add(var.set_resolution(config[CONF_RESOLUTION]))
|
||||
cg.add(var.set_samplerate(config[CONF_SAMPLE_RATE]))
|
||||
|
@ -8,7 +8,7 @@ namespace ads1115 {
|
||||
static const char *const TAG = "ads1115.sensor";
|
||||
|
||||
float ADS1115Sensor::sample() {
|
||||
return this->parent_->request_measurement(this->multiplexer_, this->gain_, this->resolution_, this->samplerate_);
|
||||
return this->parent_->request_measurement(this->multiplexer_, this->gain_, this->resolution_);
|
||||
}
|
||||
|
||||
void ADS1115Sensor::update() {
|
||||
@ -24,7 +24,6 @@ void ADS1115Sensor::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, " Multiplexer: %u", this->multiplexer_);
|
||||
ESP_LOGCONFIG(TAG, " Gain: %u", this->gain_);
|
||||
ESP_LOGCONFIG(TAG, " Resolution: %u", this->resolution_);
|
||||
ESP_LOGCONFIG(TAG, " Sample rate: %u", this->samplerate_);
|
||||
}
|
||||
|
||||
} // namespace ads1115
|
||||
|
@ -21,7 +21,6 @@ class ADS1115Sensor : public sensor::Sensor,
|
||||
void set_multiplexer(ADS1115Multiplexer multiplexer) { this->multiplexer_ = multiplexer; }
|
||||
void set_gain(ADS1115Gain gain) { this->gain_ = gain; }
|
||||
void set_resolution(ADS1115Resolution resolution) { this->resolution_ = resolution; }
|
||||
void set_samplerate(ADS1115Samplerate samplerate) { this->samplerate_ = samplerate; }
|
||||
float sample() override;
|
||||
|
||||
void dump_config() override;
|
||||
@ -30,7 +29,6 @@ class ADS1115Sensor : public sensor::Sensor,
|
||||
ADS1115Multiplexer multiplexer_;
|
||||
ADS1115Gain gain_;
|
||||
ADS1115Resolution resolution_;
|
||||
ADS1115Samplerate samplerate_;
|
||||
};
|
||||
|
||||
} // namespace ads1115
|
||||
|
@ -1,6 +1,6 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import spi
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import spi
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
CODEOWNERS = ["@solomondg1"]
|
||||
|
@ -1,18 +1,17 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import sensor, voltage_sampler
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor, voltage_sampler
|
||||
from esphome.const import (
|
||||
CONF_GAIN,
|
||||
CONF_MULTIPLEXER,
|
||||
CONF_TYPE,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_CELSIUS,
|
||||
UNIT_VOLT,
|
||||
CONF_TYPE,
|
||||
)
|
||||
|
||||
from .. import ADS1118, CONF_ADS1118_ID, ads1118_ns
|
||||
from .. import ads1118_ns, ADS1118, CONF_ADS1118_ID
|
||||
|
||||
AUTO_LOAD = ["voltage_sampler"]
|
||||
DEPENDENCIES = ["ads1118"]
|
||||
|
@ -1,21 +1,21 @@
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import i2c, sensor
|
||||
from esphome import automation
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c, sensor
|
||||
from esphome.const import (
|
||||
CONF_ADDRESS,
|
||||
CONF_ID,
|
||||
CONF_MODE,
|
||||
CONF_TVOC,
|
||||
CONF_VALUE,
|
||||
CONF_VERSION,
|
||||
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
ENTITY_CATEGORY_DIAGNOSTIC,
|
||||
ICON_RADIATOR,
|
||||
ICON_RESTART,
|
||||
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
ENTITY_CATEGORY_DIAGNOSTIC,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_OHM,
|
||||
UNIT_PARTS_PER_BILLION,
|
||||
CONF_ADDRESS,
|
||||
CONF_TVOC,
|
||||
CONF_VERSION,
|
||||
CONF_MODE,
|
||||
CONF_VALUE,
|
||||
)
|
||||
|
||||
CONF_RESISTANCE = "resistance"
|
||||
|
@ -93,9 +93,8 @@ void AHT10Component::restart_read_() {
|
||||
|
||||
void AHT10Component::read_data_() {
|
||||
uint8_t data[6];
|
||||
if (this->read_count_ > 1) {
|
||||
if (this->read_count_ > 1)
|
||||
ESP_LOGD(TAG, "Read attempt %d at %ums", this->read_count_, (unsigned) (millis() - this->start_time_));
|
||||
}
|
||||
if (this->read(data, 6) != i2c::ERROR_OK) {
|
||||
this->status_set_warning("AHT10 read failed, retrying soon");
|
||||
this->restart_read_();
|
||||
@ -120,9 +119,8 @@ void AHT10Component::read_data_() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (this->read_count_ > 1) {
|
||||
if (this->read_count_ > 1)
|
||||
ESP_LOGD(TAG, "Success at %ums", (unsigned) (millis() - this->start_time_));
|
||||
}
|
||||
uint32_t raw_temperature = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5];
|
||||
uint32_t raw_humidity = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4;
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import i2c, sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c, sensor
|
||||
from esphome.const import (
|
||||
CONF_HUMIDITY,
|
||||
CONF_ID,
|
||||
CONF_TEMPERATURE,
|
||||
CONF_VARIANT,
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_CELSIUS,
|
||||
UNIT_PERCENT,
|
||||
CONF_VARIANT,
|
||||
)
|
||||
|
||||
DEPENDENCIES = ["i2c"]
|
||||
|
@ -1,173 +0,0 @@
|
||||
#include "aic3204.h"
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace aic3204 {
|
||||
|
||||
static const char *const TAG = "aic3204";
|
||||
|
||||
#define ERROR_CHECK(err, msg) \
|
||||
if (!(err)) { \
|
||||
ESP_LOGE(TAG, msg); \
|
||||
this->mark_failed(); \
|
||||
return; \
|
||||
}
|
||||
|
||||
void AIC3204::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up AIC3204...");
|
||||
|
||||
// Set register page to 0
|
||||
ERROR_CHECK(this->write_byte(AIC3204_PAGE_CTRL, 0x00), "Set page 0 failed");
|
||||
// Initiate SW reset (PLL is powered off as part of reset)
|
||||
ERROR_CHECK(this->write_byte(AIC3204_SW_RST, 0x01), "Software reset failed");
|
||||
// *** Program clock settings ***
|
||||
// Default is CODEC_CLKIN is from MCLK pin. Don't need to change this.
|
||||
// MDAC*NDAC*FOSR*48Khz = mClk (24.576 MHz when the XMOS is expecting 48kHz audio)
|
||||
// (See page 51 of https://www.ti.com/lit/ml/slaa557/slaa557.pdf)
|
||||
// We do need MDAC*DOSR/32 >= the resource compute level for the processing block
|
||||
// So here 2*128/32 = 8, which is equal to processing block 1 's resource compute
|
||||
// See page 5 of https://www.ti.com/lit/an/slaa404c/slaa404c.pdf for the workflow
|
||||
// for determining these settings.
|
||||
|
||||
// Power up NDAC and set to 2
|
||||
ERROR_CHECK(this->write_byte(AIC3204_NDAC, 0x82), "Set NDAC failed");
|
||||
// Power up MDAC and set to 2
|
||||
ERROR_CHECK(this->write_byte(AIC3204_MDAC, 0x82), "Set MDAC failed");
|
||||
// Program DOSR = 128
|
||||
ERROR_CHECK(this->write_byte(AIC3204_DOSR, 0x80), "Set DOSR failed");
|
||||
// Set Audio Interface Config: I2S, 32 bits, DOUT always driving
|
||||
ERROR_CHECK(this->write_byte(AIC3204_CODEC_IF, 0x30), "Set CODEC_IF failed");
|
||||
// For I2S Firmware only, set SCLK/MFP3 pin as Audio Data In
|
||||
ERROR_CHECK(this->write_byte(AIC3204_SCLK_MFP3, 0x02), "Set SCLK/MFP3 failed");
|
||||
ERROR_CHECK(this->write_byte(AIC3204_AUDIO_IF_4, 0x01), "Set AUDIO_IF_4 failed");
|
||||
ERROR_CHECK(this->write_byte(AIC3204_AUDIO_IF_5, 0x01), "Set AUDIO_IF_5 failed");
|
||||
// Program the DAC processing block to be used - PRB_P1
|
||||
ERROR_CHECK(this->write_byte(AIC3204_DAC_SIG_PROC, 0x01), "Set DAC_SIG_PROC failed");
|
||||
|
||||
// *** Select Page 1 ***
|
||||
ERROR_CHECK(this->write_byte(AIC3204_PAGE_CTRL, 0x01), "Set page 1 failed");
|
||||
// Enable the internal AVDD_LDO:
|
||||
ERROR_CHECK(this->write_byte(AIC3204_LDO_CTRL, 0x09), "Set LDO_CTRL failed");
|
||||
// *** Program Analog Blocks ***
|
||||
// Disable Internal Crude AVdd in presence of external AVdd supply or before powering up internal AVdd LDO
|
||||
ERROR_CHECK(this->write_byte(AIC3204_PWR_CFG, 0x08), "Set PWR_CFG failed");
|
||||
// Enable Master Analog Power Control
|
||||
ERROR_CHECK(this->write_byte(AIC3204_LDO_CTRL, 0x01), "Set LDO_CTRL failed");
|
||||
// Page 125: Common mode control register, set d6 to 1 to make the full chip common mode = 0.75 v
|
||||
// We are using the internal AVdd regulator with a nominal output of 1.72 V (see LDO_CTRL_REGISTER on page 123)
|
||||
// Page 86 says to only set the common mode voltage to 0.9 v if AVdd >= 1.8... but it isn't on our hardware
|
||||
// We also adjust the HPL and HPR gains to -2dB gian later in this config flow compensate (see page 47)
|
||||
// (All pages refer to the TLV320AIC3204 Application Reference Guide)
|
||||
ERROR_CHECK(this->write_byte(AIC3204_CM_CTRL, 0x40), "Set CM_CTRL failed");
|
||||
// *** Set PowerTune Modes ***
|
||||
// Set the Left & Right DAC PowerTune mode to PTM_P3/4. Use Class-AB driver.
|
||||
ERROR_CHECK(this->write_byte(AIC3204_PLAY_CFG1, 0x00), "Set PLAY_CFG1 failed");
|
||||
ERROR_CHECK(this->write_byte(AIC3204_PLAY_CFG2, 0x00), "Set PLAY_CFG2 failed");
|
||||
// Set the REF charging time to 40ms
|
||||
ERROR_CHECK(this->write_byte(AIC3204_REF_STARTUP, 0x01), "Set REF_STARTUP failed");
|
||||
// HP soft stepping settings for optimal pop performance at power up
|
||||
// Rpop used is 6k with N = 6 and soft step = 20usec. This should work with 47uF coupling
|
||||
// capacitor. Can try N=5,6 or 7 time constants as well. Trade-off delay vs “pop” sound.
|
||||
ERROR_CHECK(this->write_byte(AIC3204_HP_START, 0x25), "Set HP_START failed");
|
||||
// Route Left DAC to HPL
|
||||
ERROR_CHECK(this->write_byte(AIC3204_HPL_ROUTE, 0x08), "Set HPL_ROUTE failed");
|
||||
// Route Right DAC to HPR
|
||||
ERROR_CHECK(this->write_byte(AIC3204_HPR_ROUTE, 0x08), "Set HPR_ROUTE failed");
|
||||
// Route Left DAC to LOL
|
||||
ERROR_CHECK(this->write_byte(AIC3204_LOL_ROUTE, 0x08), "Set LOL_ROUTE failed");
|
||||
// Route Right DAC to LOR
|
||||
ERROR_CHECK(this->write_byte(AIC3204_LOR_ROUTE, 0x08), "Set LOR_ROUTE failed");
|
||||
|
||||
// Unmute HPL and set gain to -2dB (see comment before configuring the AIC3204_CM_CTRL register)
|
||||
ERROR_CHECK(this->write_byte(AIC3204_HPL_GAIN, 0x3e), "Set HPL_GAIN failed");
|
||||
// Unmute HPR and set gain to -2dB (see comment before configuring the AIC3204_CM_CTRL register)
|
||||
ERROR_CHECK(this->write_byte(AIC3204_HPR_GAIN, 0x3e), "Set HPR_GAIN failed");
|
||||
// Unmute LOL and set gain to 0dB
|
||||
ERROR_CHECK(this->write_byte(AIC3204_LOL_DRV_GAIN, 0x00), "Set LOL_DRV_GAIN failed");
|
||||
// Unmute LOR and set gain to 0dB
|
||||
ERROR_CHECK(this->write_byte(AIC3204_LOR_DRV_GAIN, 0x00), "Set LOR_DRV_GAIN failed");
|
||||
|
||||
// Power up HPL and HPR, LOL and LOR drivers
|
||||
ERROR_CHECK(this->write_byte(AIC3204_OP_PWR_CTRL, 0x3C), "Set OP_PWR_CTRL failed");
|
||||
|
||||
// Wait for 2.5 sec for soft stepping to take effect before attempting power-up
|
||||
this->set_timeout(2500, [this]() {
|
||||
// *** Power Up DAC ***
|
||||
// Select Page 0
|
||||
ERROR_CHECK(this->write_byte(AIC3204_PAGE_CTRL, 0x00), "Set PAGE_CTRL failed");
|
||||
// Power up the Left and Right DAC Channels. Route Left data to Left DAC and Right data to Right DAC.
|
||||
// DAC Vol control soft step 1 step per DAC word clock.
|
||||
ERROR_CHECK(this->write_byte(AIC3204_DAC_CH_SET1, 0xd4), "Set DAC_CH_SET1 failed");
|
||||
// Set left and right DAC digital volume control
|
||||
ERROR_CHECK(this->write_volume_(), "Set volume failed");
|
||||
// Unmute left and right channels
|
||||
ERROR_CHECK(this->write_mute_(), "Set mute failed");
|
||||
});
|
||||
}
|
||||
|
||||
void AIC3204::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "AIC3204:");
|
||||
LOG_I2C_DEVICE(this);
|
||||
|
||||
if (this->is_failed()) {
|
||||
ESP_LOGE(TAG, "Communication with AIC3204 failed");
|
||||
}
|
||||
}
|
||||
|
||||
bool AIC3204::set_mute_off() {
|
||||
this->is_muted_ = false;
|
||||
return this->write_mute_();
|
||||
}
|
||||
|
||||
bool AIC3204::set_mute_on() {
|
||||
this->is_muted_ = true;
|
||||
return this->write_mute_();
|
||||
}
|
||||
|
||||
bool AIC3204::set_auto_mute_mode(uint8_t auto_mute_mode) {
|
||||
this->auto_mute_mode_ = auto_mute_mode & 0x07;
|
||||
ESP_LOGVV(TAG, "Setting auto_mute_mode to 0x%.2x", this->auto_mute_mode_);
|
||||
return this->write_mute_();
|
||||
}
|
||||
|
||||
bool AIC3204::set_volume(float volume) {
|
||||
this->volume_ = clamp<float>(volume, 0.0, 1.0);
|
||||
return this->write_volume_();
|
||||
}
|
||||
|
||||
bool AIC3204::is_muted() { return this->is_muted_; }
|
||||
|
||||
float AIC3204::volume() { return this->volume_; }
|
||||
|
||||
bool AIC3204::write_mute_() {
|
||||
uint8_t mute_mode_byte = this->auto_mute_mode_ << 4; // auto-mute control is bits 4-6
|
||||
mute_mode_byte |= this->is_muted_ ? 0x0c : 0x00; // mute bits are 2-3
|
||||
if (!this->write_byte(AIC3204_PAGE_CTRL, 0x00) || !this->write_byte(AIC3204_DAC_CH_SET2, mute_mode_byte)) {
|
||||
ESP_LOGE(TAG, "Writing mute modes failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AIC3204::write_volume_() {
|
||||
const int8_t dvc_min_byte = -127;
|
||||
const int8_t dvc_max_byte = 48;
|
||||
|
||||
int8_t volume_byte = dvc_min_byte + (this->volume_ * (dvc_max_byte - dvc_min_byte));
|
||||
volume_byte = clamp<int8_t>(volume_byte, dvc_min_byte, dvc_max_byte);
|
||||
|
||||
ESP_LOGVV(TAG, "Setting volume to 0x%.2x", volume_byte & 0xFF);
|
||||
|
||||
if ((!this->write_byte(AIC3204_PAGE_CTRL, 0x00)) || (!this->write_byte(AIC3204_DACL_VOL_D, volume_byte)) ||
|
||||
(!this->write_byte(AIC3204_DACR_VOL_D, volume_byte))) {
|
||||
ESP_LOGE(TAG, "Writing volume failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace aic3204
|
||||
} // namespace esphome
|
@ -1,88 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/components/audio_dac/audio_dac.h"
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace aic3204 {
|
||||
|
||||
// TLV320AIC3204 Register Addresses
|
||||
// Page 0
|
||||
static const uint8_t AIC3204_PAGE_CTRL = 0x00; // Register 0 - Page Control
|
||||
static const uint8_t AIC3204_SW_RST = 0x01; // Register 1 - Software Reset
|
||||
static const uint8_t AIC3204_CLK_PLL1 = 0x04; // Register 4 - Clock Setting Register 1, Multiplexers
|
||||
static const uint8_t AIC3204_CLK_PLL2 = 0x05; // Register 5 - Clock Setting Register 2, P and R values
|
||||
static const uint8_t AIC3204_CLK_PLL3 = 0x06; // Register 6 - Clock Setting Register 3, J values
|
||||
static const uint8_t AIC3204_NDAC = 0x0B; // Register 11 - NDAC Divider Value
|
||||
static const uint8_t AIC3204_MDAC = 0x0C; // Register 12 - MDAC Divider Value
|
||||
static const uint8_t AIC3204_DOSR = 0x0E; // Register 14 - DOSR Divider Value (LS Byte)
|
||||
static const uint8_t AIC3204_NADC = 0x12; // Register 18 - NADC Divider Value
|
||||
static const uint8_t AIC3204_MADC = 0x13; // Register 19 - MADC Divider Value
|
||||
static const uint8_t AIC3204_AOSR = 0x14; // Register 20 - AOSR Divider Value
|
||||
static const uint8_t AIC3204_CODEC_IF = 0x1B; // Register 27 - CODEC Interface Control
|
||||
static const uint8_t AIC3204_AUDIO_IF_4 = 0x1F; // Register 31 - Audio Interface Setting Register 4
|
||||
static const uint8_t AIC3204_AUDIO_IF_5 = 0x20; // Register 32 - Audio Interface Setting Register 5
|
||||
static const uint8_t AIC3204_SCLK_MFP3 = 0x38; // Register 56 - SCLK/MFP3 Function Control
|
||||
static const uint8_t AIC3204_DAC_SIG_PROC = 0x3C; // Register 60 - DAC Sig Processing Block Control
|
||||
static const uint8_t AIC3204_ADC_SIG_PROC = 0x3D; // Register 61 - ADC Sig Processing Block Control
|
||||
static const uint8_t AIC3204_DAC_CH_SET1 = 0x3F; // Register 63 - DAC Channel Setup 1
|
||||
static const uint8_t AIC3204_DAC_CH_SET2 = 0x40; // Register 64 - DAC Channel Setup 2
|
||||
static const uint8_t AIC3204_DACL_VOL_D = 0x41; // Register 65 - DAC Left Digital Vol Control
|
||||
static const uint8_t AIC3204_DACR_VOL_D = 0x42; // Register 66 - DAC Right Digital Vol Control
|
||||
static const uint8_t AIC3204_DRC_ENABLE = 0x44;
|
||||
static const uint8_t AIC3204_ADC_CH_SET = 0x51; // Register 81 - ADC Channel Setup
|
||||
static const uint8_t AIC3204_ADC_FGA_MUTE = 0x52; // Register 82 - ADC Fine Gain Adjust/Mute
|
||||
|
||||
// Page 1
|
||||
static const uint8_t AIC3204_PWR_CFG = 0x01; // Register 1 - Power Config
|
||||
static const uint8_t AIC3204_LDO_CTRL = 0x02; // Register 2 - LDO Control
|
||||
static const uint8_t AIC3204_PLAY_CFG1 = 0x03; // Register 3 - Playback Config 1
|
||||
static const uint8_t AIC3204_PLAY_CFG2 = 0x04; // Register 4 - Playback Config 2
|
||||
static const uint8_t AIC3204_OP_PWR_CTRL = 0x09; // Register 9 - Output Driver Power Control
|
||||
static const uint8_t AIC3204_CM_CTRL = 0x0A; // Register 10 - Common Mode Control
|
||||
static const uint8_t AIC3204_HPL_ROUTE = 0x0C; // Register 12 - HPL Routing Select
|
||||
static const uint8_t AIC3204_HPR_ROUTE = 0x0D; // Register 13 - HPR Routing Select
|
||||
static const uint8_t AIC3204_LOL_ROUTE = 0x0E; // Register 14 - LOL Routing Selection
|
||||
static const uint8_t AIC3204_LOR_ROUTE = 0x0F; // Register 15 - LOR Routing Selection
|
||||
static const uint8_t AIC3204_HPL_GAIN = 0x10; // Register 16 - HPL Driver Gain
|
||||
static const uint8_t AIC3204_HPR_GAIN = 0x11; // Register 17 - HPR Driver Gain
|
||||
static const uint8_t AIC3204_LOL_DRV_GAIN = 0x12; // Register 18 - LOL Driver Gain Setting
|
||||
static const uint8_t AIC3204_LOR_DRV_GAIN = 0x13; // Register 19 - LOR Driver Gain Setting
|
||||
static const uint8_t AIC3204_HP_START = 0x14; // Register 20 - Headphone Driver Startup
|
||||
static const uint8_t AIC3204_LPGA_P_ROUTE = 0x34; // Register 52 - Left PGA Positive Input Route
|
||||
static const uint8_t AIC3204_LPGA_N_ROUTE = 0x36; // Register 54 - Left PGA Negative Input Route
|
||||
static const uint8_t AIC3204_RPGA_P_ROUTE = 0x37; // Register 55 - Right PGA Positive Input Route
|
||||
static const uint8_t AIC3204_RPGA_N_ROUTE = 0x39; // Register 57 - Right PGA Negative Input Route
|
||||
static const uint8_t AIC3204_LPGA_VOL = 0x3B; // Register 59 - Left PGA Volume
|
||||
static const uint8_t AIC3204_RPGA_VOL = 0x3C; // Register 60 - Right PGA Volume
|
||||
static const uint8_t AIC3204_ADC_PTM = 0x3D; // Register 61 - ADC Power Tune Config
|
||||
static const uint8_t AIC3204_AN_IN_CHRG = 0x47; // Register 71 - Analog Input Quick Charging Config
|
||||
static const uint8_t AIC3204_REF_STARTUP = 0x7B; // Register 123 - Reference Power Up Config
|
||||
|
||||
class AIC3204 : public audio_dac::AudioDac, public Component, public i2c::I2CDevice {
|
||||
public:
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||
|
||||
bool set_mute_off() override;
|
||||
bool set_mute_on() override;
|
||||
bool set_auto_mute_mode(uint8_t auto_mute_mode);
|
||||
bool set_volume(float volume) override;
|
||||
|
||||
bool is_muted() override;
|
||||
float volume() override;
|
||||
|
||||
protected:
|
||||
bool write_mute_();
|
||||
bool write_volume_();
|
||||
|
||||
uint8_t auto_mute_mode_{0};
|
||||
float volume_{0};
|
||||
};
|
||||
|
||||
} // namespace aic3204
|
||||
} // namespace esphome
|
@ -1,52 +0,0 @@
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import i2c
|
||||
from esphome.components.audio_dac import AudioDac
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, CONF_MODE
|
||||
|
||||
CODEOWNERS = ["@kbx81"]
|
||||
DEPENDENCIES = ["i2c"]
|
||||
|
||||
aic3204_ns = cg.esphome_ns.namespace("aic3204")
|
||||
AIC3204 = aic3204_ns.class_("AIC3204", AudioDac, cg.Component, i2c.I2CDevice)
|
||||
|
||||
SetAutoMuteAction = aic3204_ns.class_("SetAutoMuteAction", automation.Action)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(AIC3204),
|
||||
}
|
||||
)
|
||||
.extend(cv.COMPONENT_SCHEMA)
|
||||
.extend(i2c.i2c_device_schema(0x18))
|
||||
)
|
||||
|
||||
|
||||
SET_AUTO_MUTE_ACTION_SCHEMA = cv.maybe_simple_value(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(AIC3204),
|
||||
cv.Required(CONF_MODE): cv.templatable(cv.int_range(max=7, min=0)),
|
||||
},
|
||||
key=CONF_MODE,
|
||||
)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"aic3204.set_auto_mute_mode", SetAutoMuteAction, SET_AUTO_MUTE_ACTION_SCHEMA
|
||||
)
|
||||
async def aic3204_set_volume_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
template_ = await cg.templatable(config.get(CONF_MODE), args, int)
|
||||
cg.add(var.set_auto_mute_mode(template_))
|
||||
|
||||
return var
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "aic3204.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace aic3204 {
|
||||
|
||||
template<typename... Ts> class SetAutoMuteAction : public Action<Ts...> {
|
||||
public:
|
||||
explicit SetAutoMuteAction(AIC3204 *aic3204) : aic3204_(aic3204) {}
|
||||
|
||||
TEMPLATABLE_VALUE(uint8_t, auto_mute_mode)
|
||||
|
||||
void play(Ts... x) override { this->aic3204_->set_auto_mute_mode(this->auto_mute_mode_.value(x...)); }
|
||||
|
||||
protected:
|
||||
AIC3204 *aic3204_;
|
||||
};
|
||||
|
||||
} // namespace aic3204
|
||||
} // namespace esphome
|
@ -1,6 +1,6 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import esp32_ble_tracker
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import esp32_ble_tracker
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
DEPENDENCIES = ["esp32_ble_tracker"]
|
||||
|
@ -1,17 +1,18 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import ble_client, sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor, ble_client
|
||||
|
||||
from esphome.const import (
|
||||
CONF_BATTERY_VOLTAGE,
|
||||
CONF_HUMIDITY,
|
||||
CONF_PRESSURE,
|
||||
CONF_TEMPERATURE,
|
||||
CONF_TVOC,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
DEVICE_CLASS_HUMIDITY,
|
||||
DEVICE_CLASS_PRESSURE,
|
||||
DEVICE_CLASS_TEMPERATURE,
|
||||
DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
DEVICE_CLASS_VOLTAGE,
|
||||
ENTITY_CATEGORY_DIAGNOSTIC,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_CELSIUS,
|
||||
|
@ -1,7 +1,10 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import airthings_wave_base
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID
|
||||
from esphome.components import airthings_wave_base
|
||||
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
)
|
||||
|
||||
DEPENDENCIES = airthings_wave_base.DEPENDENCIES
|
||||
|
||||
|
@ -14,6 +14,8 @@ void AirthingsWavePlus::read_sensors(uint8_t *raw_value, uint16_t value_len) {
|
||||
ESP_LOGD(TAG, "version = %d", value->version);
|
||||
|
||||
if (value->version == 1) {
|
||||
ESP_LOGD(TAG, "ambient light = %d", value->ambientLight);
|
||||
|
||||
if (this->humidity_sensor_ != nullptr) {
|
||||
this->humidity_sensor_->publish_state(value->humidity / 2.0f);
|
||||
}
|
||||
@ -41,10 +43,6 @@ void AirthingsWavePlus::read_sensors(uint8_t *raw_value, uint16_t value_len) {
|
||||
if ((this->tvoc_sensor_ != nullptr) && this->is_valid_voc_value_(value->voc)) {
|
||||
this->tvoc_sensor_->publish_state(value->voc);
|
||||
}
|
||||
|
||||
if (this->illuminance_sensor_ != nullptr) {
|
||||
this->illuminance_sensor_->publish_state(value->ambientLight);
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid payload version (%d != 1, newer version or not a Wave Plus?)", value->version);
|
||||
}
|
||||
@ -70,7 +68,6 @@ void AirthingsWavePlus::dump_config() {
|
||||
LOG_SENSOR(" ", "Radon", this->radon_sensor_);
|
||||
LOG_SENSOR(" ", "Radon Long Term", this->radon_long_term_sensor_);
|
||||
LOG_SENSOR(" ", "CO2", this->co2_sensor_);
|
||||
LOG_SENSOR(" ", "Illuminance", this->illuminance_sensor_);
|
||||
}
|
||||
|
||||
AirthingsWavePlus::AirthingsWavePlus() {
|
||||
|
@ -22,7 +22,6 @@ class AirthingsWavePlus : public airthings_wave_base::AirthingsWaveBase {
|
||||
void set_radon(sensor::Sensor *radon) { radon_sensor_ = radon; }
|
||||
void set_radon_long_term(sensor::Sensor *radon_long_term) { radon_long_term_sensor_ = radon_long_term; }
|
||||
void set_co2(sensor::Sensor *co2) { co2_sensor_ = co2; }
|
||||
void set_illuminance(sensor::Sensor *illuminance) { illuminance_sensor_ = illuminance; }
|
||||
|
||||
protected:
|
||||
bool is_valid_radon_value_(uint16_t radon);
|
||||
@ -33,7 +32,6 @@ class AirthingsWavePlus : public airthings_wave_base::AirthingsWaveBase {
|
||||
sensor::Sensor *radon_sensor_{nullptr};
|
||||
sensor::Sensor *radon_long_term_sensor_{nullptr};
|
||||
sensor::Sensor *co2_sensor_{nullptr};
|
||||
sensor::Sensor *illuminance_sensor_{nullptr};
|
||||
|
||||
struct WavePlusReadings {
|
||||
uint8_t version;
|
||||
|
@ -1,18 +1,16 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import airthings_wave_base, sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor, airthings_wave_base
|
||||
|
||||
from esphome.const import (
|
||||
CONF_CO2,
|
||||
DEVICE_CLASS_CARBON_DIOXIDE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
ICON_RADIOACTIVE,
|
||||
CONF_ID,
|
||||
CONF_ILLUMINANCE,
|
||||
CONF_RADON,
|
||||
CONF_RADON_LONG_TERM,
|
||||
DEVICE_CLASS_CARBON_DIOXIDE,
|
||||
DEVICE_CLASS_ILLUMINANCE,
|
||||
ICON_RADIOACTIVE,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
CONF_CO2,
|
||||
UNIT_BECQUEREL_PER_CUBIC_METER,
|
||||
UNIT_LUX,
|
||||
UNIT_PARTS_PER_MILLION,
|
||||
)
|
||||
|
||||
@ -47,12 +45,6 @@ CONFIG_SCHEMA = airthings_wave_base.BASE_SCHEMA.extend(
|
||||
device_class=DEVICE_CLASS_CARBON_DIOXIDE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_ILLUMINANCE): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_LUX,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_ILLUMINANCE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
@ -70,6 +62,3 @@ async def to_code(config):
|
||||
if config_co2 := config.get(CONF_CO2):
|
||||
sens = await sensor.new_sensor(config_co2)
|
||||
cg.add(var.set_co2(sens))
|
||||
if config_illuminance := config.get(CONF_ILLUMINANCE):
|
||||
sens = await sensor.new_sensor(config_illuminance)
|
||||
cg.add(var.set_illuminance(sens))
|
||||
|
@ -1,17 +1,16 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import web_server
|
||||
from esphome import automation
|
||||
from esphome.automation import maybe_simple_id
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import mqtt, web_server
|
||||
import esphome.config_validation as cv
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.const import (
|
||||
CONF_CODE,
|
||||
CONF_ID,
|
||||
CONF_MQTT_ID,
|
||||
CONF_ON_STATE,
|
||||
CONF_TRIGGER_ID,
|
||||
CONF_WEB_SERVER,
|
||||
CONF_CODE,
|
||||
CONF_WEB_SERVER_ID,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
from esphome.cpp_helpers import setup_entity
|
||||
|
||||
CODEOWNERS = ["@grahambrown11", "@hwstar"]
|
||||
@ -78,72 +77,67 @@ AlarmControlPanelCondition = alarm_control_panel_ns.class_(
|
||||
"AlarmControlPanelCondition", automation.Condition
|
||||
)
|
||||
|
||||
ALARM_CONTROL_PANEL_SCHEMA = (
|
||||
cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
|
||||
.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
|
||||
.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(AlarmControlPanel),
|
||||
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(
|
||||
mqtt.MQTTAlarmControlPanelComponent
|
||||
),
|
||||
cv.Optional(CONF_ON_STATE): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_TRIGGERED): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TriggeredTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_ARMING): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmingTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_PENDING): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PendingTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_ARMED_HOME): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedHomeTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_ARMED_NIGHT): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedNightTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_ARMED_AWAY): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedAwayTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_DISARMED): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DisarmedTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_CLEARED): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClearedTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_CHIME): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ChimeTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_READY): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ReadyTrigger),
|
||||
}
|
||||
),
|
||||
}
|
||||
)
|
||||
ALARM_CONTROL_PANEL_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
|
||||
web_server.WEBSERVER_SORTING_SCHEMA
|
||||
).extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(AlarmControlPanel),
|
||||
cv.Optional(CONF_ON_STATE): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_TRIGGERED): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TriggeredTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_ARMING): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmingTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_PENDING): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PendingTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_ARMED_HOME): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedHomeTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_ARMED_NIGHT): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedNightTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_ARMED_AWAY): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ArmedAwayTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_DISARMED): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DisarmedTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_CLEARED): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClearedTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_CHIME): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ChimeTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_READY): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ReadyTrigger),
|
||||
}
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
ALARM_CONTROL_PANEL_ACTION_SCHEMA = maybe_simple_id(
|
||||
@ -195,11 +189,9 @@ async def setup_alarm_control_panel_core_(var, config):
|
||||
for conf in config.get(CONF_ON_READY, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
if web_server_config := config.get(CONF_WEB_SERVER):
|
||||
await web_server.add_entity_config(var, web_server_config)
|
||||
if mqtt_id := config.get(CONF_MQTT_ID):
|
||||
mqtt_ = cg.new_Pvariable(mqtt_id, var)
|
||||
await mqtt.register_mqtt_component(mqtt_, config)
|
||||
if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
|
||||
web_server_ = await cg.get_variable(webserver_id)
|
||||
web_server.add_entity_to_sorting_list(web_server_, var, config)
|
||||
|
||||
|
||||
async def register_alarm_control_panel(var, config):
|
||||
|
@ -72,9 +72,10 @@ void AlarmControlPanelCall::validate_() {
|
||||
this->state_.reset();
|
||||
return;
|
||||
}
|
||||
if (state == ACP_STATE_DISARMED && !this->parent_->is_state_armed(this->parent_->get_state()) &&
|
||||
this->parent_->get_state() != ACP_STATE_PENDING && this->parent_->get_state() != ACP_STATE_ARMING &&
|
||||
this->parent_->get_state() != ACP_STATE_TRIGGERED) {
|
||||
if (state == ACP_STATE_DISARMED &&
|
||||
!(this->parent_->is_state_armed(this->parent_->get_state()) ||
|
||||
this->parent_->get_state() == ACP_STATE_PENDING || this->parent_->get_state() == ACP_STATE_ARMING ||
|
||||
this->parent_->get_state() == ACP_STATE_TRIGGERED)) {
|
||||
ESP_LOGW(TAG, "Cannot disarm when not armed");
|
||||
this->state_.reset();
|
||||
return;
|
||||
|
@ -1,20 +1,20 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import ble_client, sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor, ble_client
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_CURRENT,
|
||||
CONF_FLOW,
|
||||
CONF_HEAD,
|
||||
CONF_ID,
|
||||
CONF_POWER,
|
||||
CONF_SPEED,
|
||||
CONF_VOLTAGE,
|
||||
UNIT_AMPERE,
|
||||
UNIT_CUBIC_METER_PER_HOUR,
|
||||
UNIT_METER,
|
||||
UNIT_REVOLUTIONS_PER_MINUTE,
|
||||
UNIT_VOLT,
|
||||
UNIT_WATT,
|
||||
UNIT_METER,
|
||||
UNIT_CUBIC_METER_PER_HOUR,
|
||||
UNIT_REVOLUTIONS_PER_MINUTE,
|
||||
)
|
||||
|
||||
alpha3_ns = cg.esphome_ns.namespace("alpha3")
|
||||
|
@ -128,7 +128,7 @@ void AM2315C::update() {
|
||||
data[2] = 0x00;
|
||||
if (this->write(data, 3) != i2c::ERROR_OK) {
|
||||
ESP_LOGE(TAG, "Write failed!");
|
||||
this->status_set_warning();
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -138,12 +138,12 @@ void AM2315C::update() {
|
||||
uint8_t status = 0;
|
||||
if (this->read(&status, 1) != i2c::ERROR_OK) {
|
||||
ESP_LOGE(TAG, "Read failed!");
|
||||
this->status_set_warning();
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
if ((status & 0x80) == 0x80) {
|
||||
ESP_LOGE(TAG, "HW still busy!");
|
||||
this->status_set_warning();
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -151,7 +151,7 @@ void AM2315C::update() {
|
||||
uint8_t data[7];
|
||||
if (this->read(data, 7) != i2c::ERROR_OK) {
|
||||
ESP_LOGE(TAG, "Read failed!");
|
||||
this->status_set_warning();
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import i2c, sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c, sensor
|
||||
from esphome.const import (
|
||||
CONF_HUMIDITY,
|
||||
CONF_ID,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import i2c, sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c, sensor
|
||||
from esphome.const import (
|
||||
CONF_HUMIDITY,
|
||||
CONF_ID,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import ble_client, cover
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import cover, ble_client
|
||||
from esphome.const import CONF_ID, CONF_PIN
|
||||
|
||||
CODEOWNERS = ["@buxtronix"]
|
||||
|
@ -1,12 +1,12 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import ble_client, sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor, ble_client
|
||||
from esphome.const import (
|
||||
CONF_BATTERY_LEVEL,
|
||||
CONF_ID,
|
||||
CONF_ILLUMINANCE,
|
||||
CONF_BATTERY_LEVEL,
|
||||
DEVICE_CLASS_BATTERY,
|
||||
ENTITY_CATEGORY_DIAGNOSTIC,
|
||||
CONF_ILLUMINANCE,
|
||||
ICON_BRIGHTNESS_5,
|
||||
UNIT_PERCENT,
|
||||
)
|
||||
|
@ -14,8 +14,7 @@ void AnalogThresholdBinarySensor::setup() {
|
||||
if (std::isnan(sensor_value)) {
|
||||
this->publish_initial_state(false);
|
||||
} else {
|
||||
this->publish_initial_state(sensor_value >=
|
||||
(this->lower_threshold_.value() + this->upper_threshold_.value()) / 2.0f);
|
||||
this->publish_initial_state(sensor_value >= (this->lower_threshold_ + this->upper_threshold_) / 2.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,8 +24,7 @@ void AnalogThresholdBinarySensor::set_sensor(sensor::Sensor *analog_sensor) {
|
||||
this->sensor_->add_on_state_callback([this](float sensor_value) {
|
||||
// if there is an invalid sensor reading, ignore the change and keep the current state
|
||||
if (!std::isnan(sensor_value)) {
|
||||
this->publish_state(sensor_value >=
|
||||
(this->state ? this->lower_threshold_.value() : this->upper_threshold_.value()));
|
||||
this->publish_state(sensor_value >= (this->state ? this->lower_threshold_ : this->upper_threshold_));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -34,8 +32,8 @@ void AnalogThresholdBinarySensor::set_sensor(sensor::Sensor *analog_sensor) {
|
||||
void AnalogThresholdBinarySensor::dump_config() {
|
||||
LOG_BINARY_SENSOR("", "Analog Threshold Binary Sensor", this);
|
||||
LOG_SENSOR(" ", "Sensor", this->sensor_);
|
||||
ESP_LOGCONFIG(TAG, " Upper threshold: %.11f", this->upper_threshold_.value());
|
||||
ESP_LOGCONFIG(TAG, " Lower threshold: %.11f", this->lower_threshold_.value());
|
||||
ESP_LOGCONFIG(TAG, " Upper threshold: %.11f", this->upper_threshold_);
|
||||
ESP_LOGCONFIG(TAG, " Lower threshold: %.11f", this->lower_threshold_);
|
||||
}
|
||||
|
||||
} // namespace analog_threshold
|
||||
|
@ -15,13 +15,14 @@ class AnalogThresholdBinarySensor : public Component, public binary_sensor::Bina
|
||||
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||
|
||||
void set_sensor(sensor::Sensor *analog_sensor);
|
||||
template<typename T> void set_upper_threshold(T upper_threshold) { this->upper_threshold_ = upper_threshold; }
|
||||
template<typename T> void set_lower_threshold(T lower_threshold) { this->lower_threshold_ = lower_threshold; }
|
||||
void set_upper_threshold(float threshold) { this->upper_threshold_ = threshold; }
|
||||
void set_lower_threshold(float threshold) { this->lower_threshold_ = threshold; }
|
||||
|
||||
protected:
|
||||
sensor::Sensor *sensor_{nullptr};
|
||||
TemplatableValue<float> upper_threshold_{};
|
||||
TemplatableValue<float> lower_threshold_{};
|
||||
|
||||
float upper_threshold_;
|
||||
float lower_threshold_;
|
||||
};
|
||||
|
||||
} // namespace analog_threshold
|
||||
|
@ -1,7 +1,10 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import binary_sensor, sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_SENSOR_ID, CONF_THRESHOLD
|
||||
from esphome.components import binary_sensor, sensor
|
||||
from esphome.const import (
|
||||
CONF_SENSOR_ID,
|
||||
CONF_THRESHOLD,
|
||||
)
|
||||
|
||||
analog_threshold_ns = cg.esphome_ns.namespace("analog_threshold")
|
||||
|
||||
@ -18,11 +21,11 @@ CONFIG_SCHEMA = (
|
||||
{
|
||||
cv.Required(CONF_SENSOR_ID): cv.use_id(sensor.Sensor),
|
||||
cv.Required(CONF_THRESHOLD): cv.Any(
|
||||
cv.templatable(cv.float_),
|
||||
cv.float_,
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_UPPER): cv.templatable(cv.float_),
|
||||
cv.Required(CONF_LOWER): cv.templatable(cv.float_),
|
||||
cv.Required(CONF_UPPER): cv.float_,
|
||||
cv.Required(CONF_LOWER): cv.float_,
|
||||
}
|
||||
),
|
||||
),
|
||||
@ -39,11 +42,9 @@ async def to_code(config):
|
||||
sens = await cg.get_variable(config[CONF_SENSOR_ID])
|
||||
cg.add(var.set_sensor(sens))
|
||||
|
||||
if isinstance(config[CONF_THRESHOLD], dict):
|
||||
lower = await cg.templatable(config[CONF_THRESHOLD][CONF_LOWER], [], float)
|
||||
upper = await cg.templatable(config[CONF_THRESHOLD][CONF_UPPER], [], float)
|
||||
if isinstance(config[CONF_THRESHOLD], float):
|
||||
cg.add(var.set_upper_threshold(config[CONF_THRESHOLD]))
|
||||
cg.add(var.set_lower_threshold(config[CONF_THRESHOLD]))
|
||||
else:
|
||||
lower = await cg.templatable(config[CONF_THRESHOLD], [], float)
|
||||
upper = lower
|
||||
cg.add(var.set_upper_threshold(upper))
|
||||
cg.add(var.set_lower_threshold(lower))
|
||||
cg.add(var.set_upper_threshold(config[CONF_THRESHOLD][CONF_UPPER]))
|
||||
cg.add(var.set_lower_threshold(config[CONF_THRESHOLD][CONF_LOWER]))
|
||||
|
@ -1,10 +1,29 @@
|
||||
import logging
|
||||
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
from esphome import automation, core
|
||||
from esphome.components import font
|
||||
import esphome.components.image as espImage
|
||||
from esphome.components.image import (
|
||||
CONF_USE_TRANSPARENCY,
|
||||
LOCAL_SCHEMA,
|
||||
WEB_SCHEMA,
|
||||
SOURCE_WEB,
|
||||
SOURCE_LOCAL,
|
||||
)
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, CONF_REPEAT
|
||||
import esphome.codegen as cg
|
||||
from esphome.const import (
|
||||
CONF_FILE,
|
||||
CONF_ID,
|
||||
CONF_RAW_DATA_ID,
|
||||
CONF_REPEAT,
|
||||
CONF_RESIZE,
|
||||
CONF_TYPE,
|
||||
CONF_SOURCE,
|
||||
CONF_PATH,
|
||||
CONF_URL,
|
||||
)
|
||||
from esphome.core import CORE, HexInt
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -12,7 +31,6 @@ AUTO_LOAD = ["image"]
|
||||
CODEOWNERS = ["@syndlex"]
|
||||
DEPENDENCIES = ["display"]
|
||||
MULTI_CONF = True
|
||||
MULTI_CONF_NO_DEFAULT = True
|
||||
|
||||
CONF_LOOP = "loop"
|
||||
CONF_START_FRAME = "start_frame"
|
||||
@ -34,20 +52,87 @@ SetFrameAction = animation_ns.class_(
|
||||
"AnimationSetFrameAction", automation.Action, cg.Parented.template(Animation_)
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = espImage.IMAGE_SCHEMA.extend(
|
||||
TYPED_FILE_SCHEMA = cv.typed_schema(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.declare_id(Animation_),
|
||||
cv.Optional(CONF_LOOP): cv.All(
|
||||
{
|
||||
cv.Optional(CONF_START_FRAME, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_END_FRAME): cv.positive_int,
|
||||
cv.Optional(CONF_REPEAT): cv.positive_int,
|
||||
}
|
||||
),
|
||||
SOURCE_LOCAL: LOCAL_SCHEMA,
|
||||
SOURCE_WEB: WEB_SCHEMA,
|
||||
},
|
||||
key=CONF_SOURCE,
|
||||
)
|
||||
|
||||
|
||||
def _file_schema(value):
|
||||
if isinstance(value, str):
|
||||
return validate_file_shorthand(value)
|
||||
return TYPED_FILE_SCHEMA(value)
|
||||
|
||||
|
||||
FILE_SCHEMA = cv.Schema(_file_schema)
|
||||
|
||||
|
||||
def validate_file_shorthand(value):
|
||||
value = cv.string_strict(value)
|
||||
if value.startswith("http://") or value.startswith("https://"):
|
||||
return FILE_SCHEMA(
|
||||
{
|
||||
CONF_SOURCE: SOURCE_WEB,
|
||||
CONF_URL: value,
|
||||
}
|
||||
)
|
||||
return FILE_SCHEMA(
|
||||
{
|
||||
CONF_SOURCE: SOURCE_LOCAL,
|
||||
CONF_PATH: value,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def validate_cross_dependencies(config):
|
||||
"""
|
||||
Validate fields whose possible values depend on other fields.
|
||||
For example, validate that explicitly transparent image types
|
||||
have "use_transparency" set to True.
|
||||
Also set the default value for those kind of dependent fields.
|
||||
"""
|
||||
image_type = config[CONF_TYPE]
|
||||
is_transparent_type = image_type in ["TRANSPARENT_BINARY", "RGBA"]
|
||||
# If the use_transparency option was not specified, set the default depending on the image type
|
||||
if CONF_USE_TRANSPARENCY not in config:
|
||||
config[CONF_USE_TRANSPARENCY] = is_transparent_type
|
||||
|
||||
if is_transparent_type and not config[CONF_USE_TRANSPARENCY]:
|
||||
raise cv.Invalid(f"Image type {image_type} must always be transparent.")
|
||||
|
||||
return config
|
||||
|
||||
|
||||
ANIMATION_SCHEMA = cv.Schema(
|
||||
cv.All(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.declare_id(Animation_),
|
||||
cv.Required(CONF_FILE): FILE_SCHEMA,
|
||||
cv.Optional(CONF_RESIZE): cv.dimensions,
|
||||
cv.Optional(CONF_TYPE, default="BINARY"): cv.enum(
|
||||
espImage.IMAGE_TYPE, upper=True
|
||||
),
|
||||
# Not setting default here on purpose; the default depends on the image type,
|
||||
# and thus will be set in the "validate_cross_dependencies" validator.
|
||||
cv.Optional(CONF_USE_TRANSPARENCY): cv.boolean,
|
||||
cv.Optional(CONF_LOOP): cv.All(
|
||||
{
|
||||
cv.Optional(CONF_START_FRAME, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_END_FRAME): cv.positive_int,
|
||||
cv.Optional(CONF_REPEAT): cv.positive_int,
|
||||
}
|
||||
),
|
||||
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
|
||||
},
|
||||
validate_cross_dependencies,
|
||||
)
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, ANIMATION_SCHEMA)
|
||||
|
||||
NEXT_FRAME_SCHEMA = automation.maybe_simple_id(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(Animation_),
|
||||
@ -80,26 +165,179 @@ async def animation_action_to_code(config, action_id, template_arg, args):
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
(
|
||||
prog_arr,
|
||||
width,
|
||||
height,
|
||||
image_type,
|
||||
trans_value,
|
||||
frame_count,
|
||||
) = await espImage.write_image(config, all_frames=True)
|
||||
from PIL import Image
|
||||
|
||||
conf_file = config[CONF_FILE]
|
||||
if conf_file[CONF_SOURCE] == SOURCE_LOCAL:
|
||||
path = CORE.relative_config_path(conf_file[CONF_PATH])
|
||||
elif conf_file[CONF_SOURCE] == SOURCE_WEB:
|
||||
path = espImage.compute_local_image_path(conf_file).as_posix()
|
||||
try:
|
||||
image = Image.open(path)
|
||||
except Exception as e:
|
||||
raise core.EsphomeError(f"Could not load image file {path}: {e}")
|
||||
|
||||
width, height = image.size
|
||||
frames = image.n_frames
|
||||
if CONF_RESIZE in config:
|
||||
new_width_max, new_height_max = config[CONF_RESIZE]
|
||||
ratio = min(new_width_max / width, new_height_max / height)
|
||||
width, height = int(width * ratio), int(height * ratio)
|
||||
else:
|
||||
if width > 500 or height > 500:
|
||||
_LOGGER.warning(
|
||||
'The image "%s" you requested is very big. Please consider'
|
||||
" using the resize parameter.",
|
||||
path,
|
||||
)
|
||||
|
||||
transparent = config[CONF_USE_TRANSPARENCY]
|
||||
|
||||
if config[CONF_TYPE] == "GRAYSCALE":
|
||||
data = [0 for _ in range(height * width * frames)]
|
||||
pos = 0
|
||||
for frameIndex in range(frames):
|
||||
image.seek(frameIndex)
|
||||
frame = image.convert("LA", dither=Image.Dither.NONE)
|
||||
if CONF_RESIZE in config:
|
||||
frame = frame.resize([width, height])
|
||||
pixels = list(frame.getdata())
|
||||
if len(pixels) != height * width:
|
||||
raise core.EsphomeError(
|
||||
f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})"
|
||||
)
|
||||
for pix, a in pixels:
|
||||
if transparent:
|
||||
if pix == 1:
|
||||
pix = 0
|
||||
if a < 0x80:
|
||||
pix = 1
|
||||
|
||||
data[pos] = pix
|
||||
pos += 1
|
||||
|
||||
elif config[CONF_TYPE] == "RGBA":
|
||||
data = [0 for _ in range(height * width * 4 * frames)]
|
||||
pos = 0
|
||||
for frameIndex in range(frames):
|
||||
image.seek(frameIndex)
|
||||
frame = image.convert("RGBA")
|
||||
if CONF_RESIZE in config:
|
||||
frame = frame.resize([width, height])
|
||||
pixels = list(frame.getdata())
|
||||
if len(pixels) != height * width:
|
||||
raise core.EsphomeError(
|
||||
f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})"
|
||||
)
|
||||
for pix in pixels:
|
||||
data[pos] = pix[0]
|
||||
pos += 1
|
||||
data[pos] = pix[1]
|
||||
pos += 1
|
||||
data[pos] = pix[2]
|
||||
pos += 1
|
||||
data[pos] = pix[3]
|
||||
pos += 1
|
||||
|
||||
elif config[CONF_TYPE] == "RGB24":
|
||||
data = [0 for _ in range(height * width * 3 * frames)]
|
||||
pos = 0
|
||||
for frameIndex in range(frames):
|
||||
image.seek(frameIndex)
|
||||
frame = image.convert("RGBA")
|
||||
if CONF_RESIZE in config:
|
||||
frame = frame.resize([width, height])
|
||||
pixels = list(frame.getdata())
|
||||
if len(pixels) != height * width:
|
||||
raise core.EsphomeError(
|
||||
f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})"
|
||||
)
|
||||
for r, g, b, a in pixels:
|
||||
if transparent:
|
||||
if r == 0 and g == 0 and b == 1:
|
||||
b = 0
|
||||
if a < 0x80:
|
||||
r = 0
|
||||
g = 0
|
||||
b = 1
|
||||
|
||||
data[pos] = r
|
||||
pos += 1
|
||||
data[pos] = g
|
||||
pos += 1
|
||||
data[pos] = b
|
||||
pos += 1
|
||||
|
||||
elif config[CONF_TYPE] in ["RGB565", "TRANSPARENT_IMAGE"]:
|
||||
data = [0 for _ in range(height * width * 2 * frames)]
|
||||
pos = 0
|
||||
for frameIndex in range(frames):
|
||||
image.seek(frameIndex)
|
||||
frame = image.convert("RGBA")
|
||||
if CONF_RESIZE in config:
|
||||
frame = frame.resize([width, height])
|
||||
pixels = list(frame.getdata())
|
||||
if len(pixels) != height * width:
|
||||
raise core.EsphomeError(
|
||||
f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})"
|
||||
)
|
||||
for r, g, b, a in pixels:
|
||||
R = r >> 3
|
||||
G = g >> 2
|
||||
B = b >> 3
|
||||
rgb = (R << 11) | (G << 5) | B
|
||||
|
||||
if transparent:
|
||||
if rgb == 0x0020:
|
||||
rgb = 0
|
||||
if a < 0x80:
|
||||
rgb = 0x0020
|
||||
|
||||
data[pos] = rgb >> 8
|
||||
pos += 1
|
||||
data[pos] = rgb & 0xFF
|
||||
pos += 1
|
||||
|
||||
elif config[CONF_TYPE] in ["BINARY", "TRANSPARENT_BINARY"]:
|
||||
width8 = ((width + 7) // 8) * 8
|
||||
data = [0 for _ in range((height * width8 // 8) * frames)]
|
||||
for frameIndex in range(frames):
|
||||
image.seek(frameIndex)
|
||||
if transparent:
|
||||
alpha = image.split()[-1]
|
||||
has_alpha = alpha.getextrema()[0] < 0xFF
|
||||
frame = image.convert("1", dither=Image.Dither.NONE)
|
||||
if CONF_RESIZE in config:
|
||||
frame = frame.resize([width, height])
|
||||
if transparent:
|
||||
alpha = alpha.resize([width, height])
|
||||
for x, y in [(i, j) for i in range(width) for j in range(height)]:
|
||||
if transparent and has_alpha:
|
||||
if not alpha.getpixel((x, y)):
|
||||
continue
|
||||
elif frame.getpixel((x, y)):
|
||||
continue
|
||||
|
||||
pos = x + y * width8 + (height * width8 * frameIndex)
|
||||
data[pos // 8] |= 0x80 >> (pos % 8)
|
||||
else:
|
||||
raise core.EsphomeError(
|
||||
f"Animation f{config[CONF_ID]} has not supported type {config[CONF_TYPE]}."
|
||||
)
|
||||
|
||||
rhs = [HexInt(x) for x in data]
|
||||
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
||||
var = cg.new_Pvariable(
|
||||
config[CONF_ID],
|
||||
prog_arr,
|
||||
width,
|
||||
height,
|
||||
frame_count,
|
||||
image_type,
|
||||
trans_value,
|
||||
frames,
|
||||
espImage.IMAGE_TYPE[config[CONF_TYPE]],
|
||||
)
|
||||
cg.add(var.set_transparency(transparent))
|
||||
if loop_config := config.get(CONF_LOOP):
|
||||
start = loop_config[CONF_START_FRAME]
|
||||
end = loop_config.get(CONF_END_FRAME, frame_count)
|
||||
end = loop_config.get(CONF_END_FRAME, frames)
|
||||
count = loop_config.get(CONF_REPEAT, -1)
|
||||
cg.add(var.set_loop(start, end, count))
|
||||
|
@ -6,8 +6,8 @@ namespace esphome {
|
||||
namespace animation {
|
||||
|
||||
Animation::Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count,
|
||||
image::ImageType type, image::Transparency transparent)
|
||||
: Image(data_start, width, height, type, transparent),
|
||||
image::ImageType type)
|
||||
: Image(data_start, width, height, type),
|
||||
animation_data_start_(data_start),
|
||||
current_frame_(0),
|
||||
animation_frame_count_(animation_frame_count),
|
||||
@ -62,7 +62,7 @@ void Animation::set_frame(int frame) {
|
||||
}
|
||||
|
||||
void Animation::update_data_start_() {
|
||||
const uint32_t image_size = this->get_width_stride() * this->height_;
|
||||
const uint32_t image_size = image_type_to_width_stride(this->width_, this->type_) * this->height_;
|
||||
this->data_start_ = this->animation_data_start_ + image_size * this->current_frame_;
|
||||
}
|
||||
|
||||
|
@ -8,8 +8,7 @@ namespace animation {
|
||||
|
||||
class Animation : public image::Image {
|
||||
public:
|
||||
Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, image::ImageType type,
|
||||
image::Transparency transparent);
|
||||
Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, image::ImageType type);
|
||||
|
||||
uint32_t get_animation_frame_count() const;
|
||||
int get_current_frame() const;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import ble_client, climate
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import climate, ble_client
|
||||
from esphome.const import CONF_ID, CONF_UNIT_OF_MEASUREMENT
|
||||
|
||||
UNITS = {
|
||||
|
@ -1,4 +0,0 @@
|
||||
# Based on this datasheet:
|
||||
# https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf
|
||||
|
||||
CODEOWNERS = ["@aodrenah"]
|
@ -1,152 +0,0 @@
|
||||
// Based on this datasheet:
|
||||
// https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf
|
||||
|
||||
#include "apds9306.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace apds9306 {
|
||||
|
||||
static const char *const TAG = "apds9306";
|
||||
|
||||
enum { // APDS9306 registers
|
||||
APDS9306_MAIN_CTRL = 0x00,
|
||||
APDS9306_ALS_MEAS_RATE = 0x04,
|
||||
APDS9306_ALS_GAIN = 0x05,
|
||||
APDS9306_PART_ID = 0x06,
|
||||
APDS9306_MAIN_STATUS = 0x07,
|
||||
APDS9306_CLEAR_DATA_0 = 0x0A, // LSB
|
||||
APDS9306_CLEAR_DATA_1 = 0x0B,
|
||||
APDS9306_CLEAR_DATA_2 = 0x0C, // MSB
|
||||
APDS9306_ALS_DATA_0 = 0x0D, // LSB
|
||||
APDS9306_ALS_DATA_1 = 0x0E,
|
||||
APDS9306_ALS_DATA_2 = 0x0F, // MSB
|
||||
APDS9306_INT_CFG = 0x19,
|
||||
APDS9306_INT_PERSISTENCE = 0x1A,
|
||||
APDS9306_ALS_THRES_UP_0 = 0x21, // LSB
|
||||
APDS9306_ALS_THRES_UP_1 = 0x22,
|
||||
APDS9306_ALS_THRES_UP_2 = 0x23, // MSB
|
||||
APDS9306_ALS_THRES_LOW_0 = 0x24, // LSB
|
||||
APDS9306_ALS_THRES_LOW_1 = 0x25,
|
||||
APDS9306_ALS_THRES_LOW_2 = 0x26, // MSB
|
||||
APDS9306_ALS_THRES_VAR = 0x27
|
||||
};
|
||||
|
||||
#define APDS9306_ERROR_CHECK(func, error) \
|
||||
if (!(func)) { \
|
||||
ESP_LOGE(TAG, error); \
|
||||
this->mark_failed(); \
|
||||
return; \
|
||||
}
|
||||
#define APDS9306_WARNING_CHECK(func, warning) \
|
||||
if (!(func)) { \
|
||||
ESP_LOGW(TAG, warning); \
|
||||
this->status_set_warning(); \
|
||||
return; \
|
||||
}
|
||||
#define APDS9306_WRITE_BYTE(reg, value) \
|
||||
ESP_LOGV(TAG, "Writing 0x%02x to 0x%02x", value, reg); \
|
||||
if (!this->write_byte(reg, value)) { \
|
||||
ESP_LOGE(TAG, "Failed writing 0x%02x to 0x%02x", value, reg); \
|
||||
this->mark_failed(); \
|
||||
return; \
|
||||
}
|
||||
|
||||
void APDS9306::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up APDS9306...");
|
||||
|
||||
uint8_t id;
|
||||
if (!this->read_byte(APDS9306_PART_ID, &id)) { // Part ID register
|
||||
this->error_code_ = COMMUNICATION_FAILED;
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (id != 0xB1 && id != 0xB3) { // 0xB1 for APDS9306 0xB3 for APDS9306-065
|
||||
this->error_code_ = WRONG_ID;
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
// ALS resolution and measurement, see datasheet or init.py for options
|
||||
uint8_t als_meas_rate = ((this->bit_width_ & 0x07) << 4) | (this->measurement_rate_ & 0x07);
|
||||
APDS9306_WRITE_BYTE(APDS9306_ALS_MEAS_RATE, als_meas_rate);
|
||||
|
||||
// ALS gain, see datasheet or init.py for options
|
||||
uint8_t als_gain = (this->gain_ & 0x07);
|
||||
APDS9306_WRITE_BYTE(APDS9306_ALS_GAIN, als_gain);
|
||||
|
||||
// Set to standby mode
|
||||
APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x00);
|
||||
|
||||
// Check for data, clear main status
|
||||
uint8_t status;
|
||||
APDS9306_WARNING_CHECK(this->read_byte(APDS9306_MAIN_STATUS, &status), "Reading MAIN STATUS failed.");
|
||||
|
||||
// Set to active mode
|
||||
APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x02);
|
||||
|
||||
ESP_LOGCONFIG(TAG, "APDS9306 setup complete");
|
||||
}
|
||||
|
||||
void APDS9306::dump_config() {
|
||||
LOG_SENSOR("", "APDS9306", this);
|
||||
LOG_I2C_DEVICE(this);
|
||||
|
||||
if (this->is_failed()) {
|
||||
switch (this->error_code_) {
|
||||
case COMMUNICATION_FAILED:
|
||||
ESP_LOGE(TAG, "Communication with APDS9306 failed!");
|
||||
break;
|
||||
case WRONG_ID:
|
||||
ESP_LOGE(TAG, "APDS9306 has invalid id!");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Setting up APDS9306 registers failed!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGCONFIG(TAG, " Gain: %u", AMBIENT_LIGHT_GAIN_VALUES[this->gain_]);
|
||||
ESP_LOGCONFIG(TAG, " Measurement rate: %u", MEASUREMENT_RATE_VALUES[this->measurement_rate_]);
|
||||
ESP_LOGCONFIG(TAG, " Measurement Resolution/Bit width: %d", MEASUREMENT_BIT_WIDTH_VALUES[this->bit_width_]);
|
||||
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
void APDS9306::update() {
|
||||
// Check for new data
|
||||
uint8_t status;
|
||||
APDS9306_WARNING_CHECK(this->read_byte(APDS9306_MAIN_STATUS, &status), "Reading MAIN STATUS failed.");
|
||||
|
||||
this->status_clear_warning();
|
||||
|
||||
status &= 0b00001000;
|
||||
if (!status) { // No new data
|
||||
return;
|
||||
}
|
||||
|
||||
// Set to standby mode
|
||||
APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x00);
|
||||
|
||||
// Clear MAIN STATUS
|
||||
APDS9306_WARNING_CHECK(this->read_byte(APDS9306_MAIN_STATUS, &status), "Reading MAIN STATUS failed.");
|
||||
|
||||
uint8_t als_data[3];
|
||||
APDS9306_WARNING_CHECK(this->read_bytes(APDS9306_ALS_DATA_0, als_data, 3), "Reading ALS data has failed.");
|
||||
|
||||
// Set to active mode
|
||||
APDS9306_WRITE_BYTE(APDS9306_MAIN_CTRL, 0x02);
|
||||
|
||||
uint32_t light_level = 0x00 | encode_uint24(als_data[2], als_data[1], als_data[0]);
|
||||
|
||||
float lux = ((float) light_level / AMBIENT_LIGHT_GAIN_VALUES[this->gain_]) *
|
||||
(100.0f / MEASUREMENT_RATE_VALUES[this->measurement_rate_]);
|
||||
|
||||
ESP_LOGD(TAG, "Got illuminance=%.1flx from", lux);
|
||||
this->publish_state(lux);
|
||||
}
|
||||
|
||||
} // namespace apds9306
|
||||
} // namespace esphome
|
@ -1,66 +0,0 @@
|
||||
// Based on this datasheet:
|
||||
// https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esphome/components/i2c/i2c.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#include "esphome/core/component.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace apds9306 {
|
||||
|
||||
enum MeasurementBitWidth : uint8_t {
|
||||
MEASUREMENT_BIT_WIDTH_20 = 0,
|
||||
MEASUREMENT_BIT_WIDTH_19 = 1,
|
||||
MEASUREMENT_BIT_WIDTH_18 = 2,
|
||||
MEASUREMENT_BIT_WIDTH_17 = 3,
|
||||
MEASUREMENT_BIT_WIDTH_16 = 4,
|
||||
MEASUREMENT_BIT_WIDTH_13 = 5,
|
||||
};
|
||||
static const uint8_t MEASUREMENT_BIT_WIDTH_VALUES[] = {20, 19, 18, 17, 16, 13};
|
||||
|
||||
enum MeasurementRate : uint8_t {
|
||||
MEASUREMENT_RATE_25 = 0,
|
||||
MEASUREMENT_RATE_50 = 1,
|
||||
MEASUREMENT_RATE_100 = 2,
|
||||
MEASUREMENT_RATE_200 = 3,
|
||||
MEASUREMENT_RATE_500 = 4,
|
||||
MEASUREMENT_RATE_1000 = 5,
|
||||
MEASUREMENT_RATE_2000 = 6,
|
||||
};
|
||||
static const uint16_t MEASUREMENT_RATE_VALUES[] = {25, 50, 100, 200, 500, 1000, 2000};
|
||||
|
||||
enum AmbientLightGain : uint8_t {
|
||||
AMBIENT_LIGHT_GAIN_1 = 0,
|
||||
AMBIENT_LIGHT_GAIN_3 = 1,
|
||||
AMBIENT_LIGHT_GAIN_6 = 2,
|
||||
AMBIENT_LIGHT_GAIN_9 = 3,
|
||||
AMBIENT_LIGHT_GAIN_18 = 4,
|
||||
};
|
||||
static const uint8_t AMBIENT_LIGHT_GAIN_VALUES[] = {1, 3, 6, 9, 18};
|
||||
|
||||
class APDS9306 : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice {
|
||||
public:
|
||||
void setup() override;
|
||||
float get_setup_priority() const override { return setup_priority::BUS; }
|
||||
void dump_config() override;
|
||||
void update() override;
|
||||
void set_bit_width(MeasurementBitWidth bit_width) { this->bit_width_ = bit_width; }
|
||||
void set_measurement_rate(MeasurementRate measurement_rate) { this->measurement_rate_ = measurement_rate; }
|
||||
void set_ambient_light_gain(AmbientLightGain gain) { this->gain_ = gain; }
|
||||
|
||||
protected:
|
||||
enum ErrorCode {
|
||||
NONE = 0,
|
||||
COMMUNICATION_FAILED,
|
||||
WRONG_ID,
|
||||
} error_code_{NONE};
|
||||
|
||||
MeasurementBitWidth bit_width_;
|
||||
MeasurementRate measurement_rate_;
|
||||
AmbientLightGain gain_;
|
||||
};
|
||||
|
||||
} // namespace apds9306
|
||||
} // namespace esphome
|
@ -1,95 +0,0 @@
|
||||
# Based on this datasheet:
|
||||
# https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import i2c, sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_GAIN,
|
||||
DEVICE_CLASS_ILLUMINANCE,
|
||||
ICON_LIGHTBULB,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_LUX,
|
||||
)
|
||||
|
||||
DEPENDENCIES = ["i2c"]
|
||||
|
||||
CONF_APDS9306_ID = "apds9306_id"
|
||||
CONF_BIT_WIDTH = "bit_width"
|
||||
CONF_MEASUREMENT_RATE = "measurement_rate"
|
||||
|
||||
apds9306_ns = cg.esphome_ns.namespace("apds9306")
|
||||
APDS9306 = apds9306_ns.class_(
|
||||
"APDS9306", sensor.Sensor, cg.PollingComponent, i2c.I2CDevice
|
||||
)
|
||||
|
||||
MeasurementBitWidth = apds9306_ns.enum("MeasurementBitWidth")
|
||||
MeasurementRate = apds9306_ns.enum("MeasurementRate")
|
||||
AmbientLightGain = apds9306_ns.enum("AmbientLightGain")
|
||||
|
||||
MEASUREMENT_BIT_WIDTHS = {
|
||||
20: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_20,
|
||||
19: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_19,
|
||||
18: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_18,
|
||||
17: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_17,
|
||||
16: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_16,
|
||||
13: MeasurementBitWidth.MEASUREMENT_BIT_WIDTH_13,
|
||||
}
|
||||
|
||||
MEASUREMENT_RATES = {
|
||||
25: MeasurementRate.MEASUREMENT_RATE_25,
|
||||
50: MeasurementRate.MEASUREMENT_RATE_50,
|
||||
100: MeasurementRate.MEASUREMENT_RATE_100,
|
||||
200: MeasurementRate.MEASUREMENT_RATE_200,
|
||||
500: MeasurementRate.MEASUREMENT_RATE_500,
|
||||
1000: MeasurementRate.MEASUREMENT_RATE_1000,
|
||||
2000: MeasurementRate.MEASUREMENT_RATE_2000,
|
||||
}
|
||||
|
||||
AMBIENT_LIGHT_GAINS = {
|
||||
1: AmbientLightGain.AMBIENT_LIGHT_GAIN_1,
|
||||
3: AmbientLightGain.AMBIENT_LIGHT_GAIN_3,
|
||||
6: AmbientLightGain.AMBIENT_LIGHT_GAIN_6,
|
||||
9: AmbientLightGain.AMBIENT_LIGHT_GAIN_9,
|
||||
18: AmbientLightGain.AMBIENT_LIGHT_GAIN_18,
|
||||
}
|
||||
|
||||
|
||||
def _validate_measurement_rate(value):
|
||||
value = cv.positive_time_period_milliseconds(value)
|
||||
return cv.enum(MEASUREMENT_RATES, int=True)(value.total_milliseconds)
|
||||
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
sensor.sensor_schema(
|
||||
APDS9306,
|
||||
unit_of_measurement=UNIT_LUX,
|
||||
accuracy_decimals=1,
|
||||
device_class=DEVICE_CLASS_ILLUMINANCE,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
icon=ICON_LIGHTBULB,
|
||||
)
|
||||
.extend(
|
||||
{
|
||||
cv.Optional(CONF_GAIN, default="1"): cv.enum(AMBIENT_LIGHT_GAINS, int=True),
|
||||
cv.Optional(CONF_BIT_WIDTH, default="18"): cv.enum(
|
||||
MEASUREMENT_BIT_WIDTHS, int=True
|
||||
),
|
||||
cv.Optional(
|
||||
CONF_MEASUREMENT_RATE, default="100ms"
|
||||
): _validate_measurement_rate,
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("60s"))
|
||||
.extend(i2c.i2c_device_schema(0x52))
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = await sensor.new_sensor(config)
|
||||
await cg.register_component(var, config)
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
cg.add(var.set_bit_width(config[CONF_BIT_WIDTH]))
|
||||
cg.add(var.set_measurement_rate(config[CONF_MEASUREMENT_RATE]))
|
||||
cg.add(var.set_ambient_light_gain(config[CONF_GAIN]))
|
@ -1,6 +1,6 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import i2c
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import i2c
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
DEPENDENCIES = ["i2c"]
|
||||
|
@ -1,8 +1,7 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import binary_sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import binary_sensor
|
||||
from esphome.const import CONF_DIRECTION, DEVICE_CLASS_MOVING
|
||||
|
||||
from . import APDS9960, CONF_APDS9960_ID
|
||||
|
||||
DEPENDENCIES = ["apds9960"]
|
||||
|
@ -1,13 +1,12 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import sensor
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor
|
||||
from esphome.const import (
|
||||
CONF_TYPE,
|
||||
ICON_LIGHTBULB,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_PERCENT,
|
||||
ICON_LIGHTBULB,
|
||||
)
|
||||
|
||||
from . import APDS9960, CONF_APDS9960_ID
|
||||
|
||||
DEPENDENCIES = ["apds9960"]
|
||||
|
@ -1,27 +1,25 @@
|
||||
import base64
|
||||
|
||||
from esphome import automation
|
||||
from esphome.automation import Condition
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome import automation
|
||||
from esphome.automation import Condition
|
||||
from esphome.const import (
|
||||
CONF_ACTION,
|
||||
CONF_ACTIONS,
|
||||
CONF_DATA,
|
||||
CONF_DATA_TEMPLATE,
|
||||
CONF_EVENT,
|
||||
CONF_ID,
|
||||
CONF_KEY,
|
||||
CONF_ON_CLIENT_CONNECTED,
|
||||
CONF_ON_CLIENT_DISCONNECTED,
|
||||
CONF_PASSWORD,
|
||||
CONF_PORT,
|
||||
CONF_REBOOT_TIMEOUT,
|
||||
CONF_SERVICE,
|
||||
CONF_SERVICES,
|
||||
CONF_TAG,
|
||||
CONF_TRIGGER_ID,
|
||||
CONF_VARIABLES,
|
||||
CONF_SERVICES,
|
||||
CONF_TRIGGER_ID,
|
||||
CONF_EVENT,
|
||||
CONF_TAG,
|
||||
CONF_ON_CLIENT_CONNECTED,
|
||||
CONF_ON_CLIENT_DISCONNECTED,
|
||||
)
|
||||
from esphome.core import coroutine_with_priority
|
||||
|
||||
@ -65,60 +63,40 @@ def validate_encryption_key(value):
|
||||
return value
|
||||
|
||||
|
||||
ACTIONS_SCHEMA = automation.validate_automation(
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(UserServiceTrigger),
|
||||
cv.Exclusive(CONF_SERVICE, group_of_exclusion=CONF_ACTION): cv.valid_name,
|
||||
cv.Exclusive(CONF_ACTION, group_of_exclusion=CONF_ACTION): cv.valid_name,
|
||||
cv.Optional(CONF_VARIABLES, default={}): cv.Schema(
|
||||
cv.GenerateID(): cv.declare_id(APIServer),
|
||||
cv.Optional(CONF_PORT, default=6053): cv.port,
|
||||
cv.Optional(CONF_PASSWORD, default=""): cv.string_strict,
|
||||
cv.Optional(
|
||||
CONF_REBOOT_TIMEOUT, default="15min"
|
||||
): cv.positive_time_period_milliseconds,
|
||||
cv.Optional(CONF_SERVICES): automation.validate_automation(
|
||||
{
|
||||
cv.validate_id_name: cv.one_of(*SERVICE_ARG_NATIVE_TYPES, lower=True),
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(UserServiceTrigger),
|
||||
cv.Required(CONF_SERVICE): cv.valid_name,
|
||||
cv.Optional(CONF_VARIABLES, default={}): cv.Schema(
|
||||
{
|
||||
cv.validate_id_name: cv.one_of(
|
||||
*SERVICE_ARG_NATIVE_TYPES, lower=True
|
||||
),
|
||||
}
|
||||
),
|
||||
}
|
||||
),
|
||||
},
|
||||
cv.All(
|
||||
cv.has_exactly_one_key(CONF_SERVICE, CONF_ACTION),
|
||||
cv.rename_key(CONF_SERVICE, CONF_ACTION),
|
||||
),
|
||||
)
|
||||
|
||||
ENCRYPTION_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_KEY): validate_encryption_key,
|
||||
cv.Optional(CONF_ENCRYPTION): cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_KEY): validate_encryption_key,
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation(
|
||||
single=True
|
||||
),
|
||||
cv.Optional(CONF_ON_CLIENT_DISCONNECTED): automation.validate_automation(
|
||||
single=True
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _encryption_schema(config):
|
||||
if config is None:
|
||||
config = {}
|
||||
return ENCRYPTION_SCHEMA(config)
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(APIServer),
|
||||
cv.Optional(CONF_PORT, default=6053): cv.port,
|
||||
cv.Optional(CONF_PASSWORD, default=""): cv.string_strict,
|
||||
cv.Optional(
|
||||
CONF_REBOOT_TIMEOUT, default="15min"
|
||||
): cv.positive_time_period_milliseconds,
|
||||
cv.Exclusive(
|
||||
CONF_SERVICES, group_of_exclusion=CONF_ACTIONS
|
||||
): ACTIONS_SCHEMA,
|
||||
cv.Exclusive(CONF_ACTIONS, group_of_exclusion=CONF_ACTIONS): ACTIONS_SCHEMA,
|
||||
cv.Optional(CONF_ENCRYPTION): _encryption_schema,
|
||||
cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation(
|
||||
single=True
|
||||
),
|
||||
cv.Optional(CONF_ON_CLIENT_DISCONNECTED): automation.validate_automation(
|
||||
single=True
|
||||
),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
cv.rename_key(CONF_SERVICES, CONF_ACTIONS),
|
||||
)
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
@coroutine_with_priority(40.0)
|
||||
@ -130,7 +108,7 @@ async def to_code(config):
|
||||
cg.add(var.set_password(config[CONF_PASSWORD]))
|
||||
cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
|
||||
|
||||
for conf in config.get(CONF_ACTIONS, []):
|
||||
for conf in config.get(CONF_SERVICES, []):
|
||||
template_args = []
|
||||
func_args = []
|
||||
service_arg_names = []
|
||||
@ -141,7 +119,7 @@ async def to_code(config):
|
||||
service_arg_names.append(name)
|
||||
templ = cg.TemplateArguments(*template_args)
|
||||
trigger = cg.new_Pvariable(
|
||||
conf[CONF_TRIGGER_ID], templ, conf[CONF_ACTION], service_arg_names
|
||||
conf[CONF_TRIGGER_ID], templ, conf[CONF_SERVICE], service_arg_names
|
||||
)
|
||||
cg.add(var.register_user_service(trigger))
|
||||
await automation.build_automation(trigger, func_args, conf)
|
||||
@ -160,19 +138,11 @@ async def to_code(config):
|
||||
config[CONF_ON_CLIENT_DISCONNECTED],
|
||||
)
|
||||
|
||||
if (encryption_config := config.get(CONF_ENCRYPTION, None)) is not None:
|
||||
if key := encryption_config.get(CONF_KEY):
|
||||
decoded = base64.b64decode(key)
|
||||
cg.add(var.set_noise_psk(list(decoded)))
|
||||
else:
|
||||
# No key provided, but encryption desired
|
||||
# This will allow a plaintext client to provide a noise key,
|
||||
# send it to the device, and then switch to noise.
|
||||
# The key will be saved in flash and used for future connections
|
||||
# and plaintext disabled. Only a factory reset can remove it.
|
||||
cg.add_define("USE_API_PLAINTEXT")
|
||||
if encryption_config := config.get(CONF_ENCRYPTION):
|
||||
decoded = base64.b64decode(encryption_config[CONF_KEY])
|
||||
cg.add(var.set_noise_psk(list(decoded)))
|
||||
cg.add_define("USE_API_NOISE")
|
||||
cg.add_library("esphome/noise-c", "0.1.6")
|
||||
cg.add_library("esphome/noise-c", "0.1.4")
|
||||
else:
|
||||
cg.add_define("USE_API_PLAINTEXT")
|
||||
|
||||
@ -182,43 +152,28 @@ async def to_code(config):
|
||||
|
||||
KEY_VALUE_SCHEMA = cv.Schema({cv.string: cv.templatable(cv.string_strict)})
|
||||
|
||||
|
||||
HOMEASSISTANT_ACTION_ACTION_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(APIServer),
|
||||
cv.Exclusive(CONF_SERVICE, group_of_exclusion=CONF_ACTION): cv.templatable(
|
||||
cv.string
|
||||
),
|
||||
cv.Exclusive(CONF_ACTION, group_of_exclusion=CONF_ACTION): cv.templatable(
|
||||
cv.string
|
||||
),
|
||||
cv.Optional(CONF_DATA, default={}): KEY_VALUE_SCHEMA,
|
||||
cv.Optional(CONF_DATA_TEMPLATE, default={}): KEY_VALUE_SCHEMA,
|
||||
cv.Optional(CONF_VARIABLES, default={}): cv.Schema(
|
||||
{cv.string: cv.returning_lambda}
|
||||
),
|
||||
}
|
||||
),
|
||||
cv.has_exactly_one_key(CONF_SERVICE, CONF_ACTION),
|
||||
cv.rename_key(CONF_SERVICE, CONF_ACTION),
|
||||
HOMEASSISTANT_SERVICE_ACTION_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(APIServer),
|
||||
cv.Required(CONF_SERVICE): cv.templatable(cv.string),
|
||||
cv.Optional(CONF_DATA, default={}): KEY_VALUE_SCHEMA,
|
||||
cv.Optional(CONF_DATA_TEMPLATE, default={}): KEY_VALUE_SCHEMA,
|
||||
cv.Optional(CONF_VARIABLES, default={}): cv.Schema(
|
||||
{cv.string: cv.returning_lambda}
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"homeassistant.action",
|
||||
HomeAssistantServiceCallAction,
|
||||
HOMEASSISTANT_ACTION_ACTION_SCHEMA,
|
||||
)
|
||||
@automation.register_action(
|
||||
"homeassistant.service",
|
||||
HomeAssistantServiceCallAction,
|
||||
HOMEASSISTANT_ACTION_ACTION_SCHEMA,
|
||||
HOMEASSISTANT_SERVICE_ACTION_SCHEMA,
|
||||
)
|
||||
async def homeassistant_service_to_code(config, action_id, template_arg, args):
|
||||
serv = await cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, serv, False)
|
||||
templ = await cg.templatable(config[CONF_ACTION], args, None)
|
||||
templ = await cg.templatable(config[CONF_SERVICE], args, None)
|
||||
cg.add(var.set_service(templ))
|
||||
for key, value in config[CONF_DATA].items():
|
||||
templ = await cg.templatable(value, args, None)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user