mirror of
https://github.com/esphome/esphome.git
synced 2025-03-15 07:08:20 +00:00
Merge branch 'dev' into vornado-ir
This commit is contained in:
commit
5257da28c1
30
.clang-tidy
30
.clang-tidy
@ -7,28 +7,39 @@ Checks: >-
|
|||||||
-boost-*,
|
-boost-*,
|
||||||
-bugprone-easily-swappable-parameters,
|
-bugprone-easily-swappable-parameters,
|
||||||
-bugprone-implicit-widening-of-multiplication-result,
|
-bugprone-implicit-widening-of-multiplication-result,
|
||||||
|
-bugprone-multi-level-implicit-pointer-conversion,
|
||||||
-bugprone-narrowing-conversions,
|
-bugprone-narrowing-conversions,
|
||||||
-bugprone-signed-char-misuse,
|
-bugprone-signed-char-misuse,
|
||||||
|
-bugprone-switch-missing-default-case,
|
||||||
-cert-dcl50-cpp,
|
-cert-dcl50-cpp,
|
||||||
-cert-err33-c,
|
-cert-err33-c,
|
||||||
-cert-err58-cpp,
|
-cert-err58-cpp,
|
||||||
-cert-oop57-cpp,
|
-cert-oop57-cpp,
|
||||||
-cert-str34-c,
|
-cert-str34-c,
|
||||||
|
-clang-analyzer-optin.core.EnumCastOutOfRange,
|
||||||
-clang-analyzer-optin.cplusplus.UninitializedObject,
|
-clang-analyzer-optin.cplusplus.UninitializedObject,
|
||||||
-clang-analyzer-osx.*,
|
-clang-analyzer-osx.*,
|
||||||
-clang-diagnostic-delete-abstract-non-virtual-dtor,
|
-clang-diagnostic-delete-abstract-non-virtual-dtor,
|
||||||
-clang-diagnostic-delete-non-abstract-non-virtual-dtor,
|
-clang-diagnostic-delete-non-abstract-non-virtual-dtor,
|
||||||
|
-clang-diagnostic-deprecated-declarations,
|
||||||
-clang-diagnostic-ignored-optimization-argument,
|
-clang-diagnostic-ignored-optimization-argument,
|
||||||
|
-clang-diagnostic-missing-field-initializers,
|
||||||
-clang-diagnostic-shadow-field,
|
-clang-diagnostic-shadow-field,
|
||||||
-clang-diagnostic-unused-const-variable,
|
-clang-diagnostic-unused-const-variable,
|
||||||
-clang-diagnostic-unused-parameter,
|
-clang-diagnostic-unused-parameter,
|
||||||
|
-clang-diagnostic-vla-cxx-extension,
|
||||||
-concurrency-*,
|
-concurrency-*,
|
||||||
-cppcoreguidelines-avoid-c-arrays,
|
-cppcoreguidelines-avoid-c-arrays,
|
||||||
|
-cppcoreguidelines-avoid-const-or-ref-data-members,
|
||||||
|
-cppcoreguidelines-avoid-do-while,
|
||||||
-cppcoreguidelines-avoid-magic-numbers,
|
-cppcoreguidelines-avoid-magic-numbers,
|
||||||
-cppcoreguidelines-init-variables,
|
-cppcoreguidelines-init-variables,
|
||||||
|
-cppcoreguidelines-macro-to-enum,
|
||||||
-cppcoreguidelines-macro-usage,
|
-cppcoreguidelines-macro-usage,
|
||||||
|
-cppcoreguidelines-missing-std-forward,
|
||||||
-cppcoreguidelines-narrowing-conversions,
|
-cppcoreguidelines-narrowing-conversions,
|
||||||
-cppcoreguidelines-non-private-member-variables-in-classes,
|
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||||
|
-cppcoreguidelines-owning-memory,
|
||||||
-cppcoreguidelines-prefer-member-initializer,
|
-cppcoreguidelines-prefer-member-initializer,
|
||||||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||||
-cppcoreguidelines-pro-bounds-constant-array-index,
|
-cppcoreguidelines-pro-bounds-constant-array-index,
|
||||||
@ -40,7 +51,9 @@ Checks: >-
|
|||||||
-cppcoreguidelines-pro-type-static-cast-downcast,
|
-cppcoreguidelines-pro-type-static-cast-downcast,
|
||||||
-cppcoreguidelines-pro-type-union-access,
|
-cppcoreguidelines-pro-type-union-access,
|
||||||
-cppcoreguidelines-pro-type-vararg,
|
-cppcoreguidelines-pro-type-vararg,
|
||||||
|
-cppcoreguidelines-rvalue-reference-param-not-moved,
|
||||||
-cppcoreguidelines-special-member-functions,
|
-cppcoreguidelines-special-member-functions,
|
||||||
|
-cppcoreguidelines-use-default-member-init,
|
||||||
-cppcoreguidelines-virtual-class-destructor,
|
-cppcoreguidelines-virtual-class-destructor,
|
||||||
-fuchsia-multiple-inheritance,
|
-fuchsia-multiple-inheritance,
|
||||||
-fuchsia-overloaded-operator,
|
-fuchsia-overloaded-operator,
|
||||||
@ -60,21 +73,32 @@ Checks: >-
|
|||||||
-llvm-include-order,
|
-llvm-include-order,
|
||||||
-llvm-qualified-auto,
|
-llvm-qualified-auto,
|
||||||
-llvmlibc-*,
|
-llvmlibc-*,
|
||||||
-misc-non-private-member-variables-in-classes,
|
-misc-const-correctness,
|
||||||
|
-misc-include-cleaner,
|
||||||
-misc-no-recursion,
|
-misc-no-recursion,
|
||||||
|
-misc-non-private-member-variables-in-classes,
|
||||||
-misc-unused-parameters,
|
-misc-unused-parameters,
|
||||||
|
-misc-use-anonymous-namespace,
|
||||||
-modernize-avoid-bind,
|
-modernize-avoid-bind,
|
||||||
-modernize-avoid-c-arrays,
|
-modernize-avoid-c-arrays,
|
||||||
-modernize-concat-nested-namespaces,
|
-modernize-concat-nested-namespaces,
|
||||||
|
-modernize-macro-to-enum,
|
||||||
-modernize-return-braced-init-list,
|
-modernize-return-braced-init-list,
|
||||||
|
-modernize-type-traits,
|
||||||
-modernize-use-auto,
|
-modernize-use-auto,
|
||||||
|
-modernize-use-constraints,
|
||||||
-modernize-use-default-member-init,
|
-modernize-use-default-member-init,
|
||||||
-modernize-use-equals-default,
|
-modernize-use-equals-default,
|
||||||
-modernize-use-nodiscard,
|
-modernize-use-nodiscard,
|
||||||
-modernize-use-nullptr,
|
-modernize-use-nullptr,
|
||||||
|
-modernize-use-nodiscard,
|
||||||
|
-modernize-use-nullptr,
|
||||||
-modernize-use-trailing-return-type,
|
-modernize-use-trailing-return-type,
|
||||||
-mpi-*,
|
-mpi-*,
|
||||||
-objc-*,
|
-objc-*,
|
||||||
|
-performance-enum-size,
|
||||||
|
-readability-avoid-nested-conditional-operator,
|
||||||
|
-readability-container-contains,
|
||||||
-readability-container-data-pointer,
|
-readability-container-data-pointer,
|
||||||
-readability-convert-member-functions-to-static,
|
-readability-convert-member-functions-to-static,
|
||||||
-readability-else-after-return,
|
-readability-else-after-return,
|
||||||
@ -84,11 +108,13 @@ Checks: >-
|
|||||||
-readability-magic-numbers,
|
-readability-magic-numbers,
|
||||||
-readability-make-member-function-const,
|
-readability-make-member-function-const,
|
||||||
-readability-named-parameter,
|
-readability-named-parameter,
|
||||||
|
-readability-redundant-casting,
|
||||||
|
-readability-redundant-inline-specifier,
|
||||||
|
-readability-redundant-member-init,
|
||||||
-readability-redundant-string-init,
|
-readability-redundant-string-init,
|
||||||
-readability-uppercase-literal-suffix,
|
-readability-uppercase-literal-suffix,
|
||||||
-readability-use-anyofallof,
|
-readability-use-anyofallof,
|
||||||
WarningsAsErrors: '*'
|
WarningsAsErrors: '*'
|
||||||
AnalyzeTemporaryDtors: false
|
|
||||||
FormatStyle: google
|
FormatStyle: google
|
||||||
CheckOptions:
|
CheckOptions:
|
||||||
- key: google-readability-function-size.StatementThreshold
|
- key: google-readability-function-size.StatementThreshold
|
||||||
|
2
.github/actions/restore-python/action.yml
vendored
2
.github/actions/restore-python/action.yml
vendored
@ -22,7 +22,7 @@ runs:
|
|||||||
python-version: ${{ inputs.python-version }}
|
python-version: ${{ inputs.python-version }}
|
||||||
- name: Restore Python virtual environment
|
- name: Restore Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache/restore@v4.1.2
|
uses: actions/cache/restore@v4.2.0
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
# yamllint disable-line rule:line-length
|
# yamllint disable-line rule:line-length
|
||||||
|
37
.github/workflows/ci.yml
vendored
37
.github/workflows/ci.yml
vendored
@ -30,7 +30,7 @@ concurrency:
|
|||||||
jobs:
|
jobs:
|
||||||
common:
|
common:
|
||||||
name: Create common environment
|
name: Create common environment
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
outputs:
|
outputs:
|
||||||
cache-key: ${{ steps.cache-key.outputs.key }}
|
cache-key: ${{ steps.cache-key.outputs.key }}
|
||||||
steps:
|
steps:
|
||||||
@ -46,7 +46,7 @@ jobs:
|
|||||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||||
- name: Restore Python virtual environment
|
- name: Restore Python virtual environment
|
||||||
id: cache-venv
|
id: cache-venv
|
||||||
uses: actions/cache@v4.1.2
|
uses: actions/cache@v4.2.0
|
||||||
with:
|
with:
|
||||||
path: venv
|
path: venv
|
||||||
# yamllint disable-line rule:line-length
|
# yamllint disable-line rule:line-length
|
||||||
@ -62,7 +62,7 @@ jobs:
|
|||||||
|
|
||||||
black:
|
black:
|
||||||
name: Check black
|
name: Check black
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
- common
|
- common
|
||||||
steps:
|
steps:
|
||||||
@ -83,7 +83,7 @@ jobs:
|
|||||||
|
|
||||||
flake8:
|
flake8:
|
||||||
name: Check flake8
|
name: Check flake8
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
- common
|
- common
|
||||||
steps:
|
steps:
|
||||||
@ -104,7 +104,7 @@ jobs:
|
|||||||
|
|
||||||
pylint:
|
pylint:
|
||||||
name: Check pylint
|
name: Check pylint
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
- common
|
- common
|
||||||
steps:
|
steps:
|
||||||
@ -125,7 +125,7 @@ jobs:
|
|||||||
|
|
||||||
pyupgrade:
|
pyupgrade:
|
||||||
name: Check pyupgrade
|
name: Check pyupgrade
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
- common
|
- common
|
||||||
steps:
|
steps:
|
||||||
@ -146,7 +146,7 @@ jobs:
|
|||||||
|
|
||||||
ci-custom:
|
ci-custom:
|
||||||
name: Run script/ci-custom
|
name: Run script/ci-custom
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
- common
|
- common
|
||||||
steps:
|
steps:
|
||||||
@ -225,7 +225,7 @@ jobs:
|
|||||||
|
|
||||||
clang-format:
|
clang-format:
|
||||||
name: Check clang-format
|
name: Check clang-format
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
- common
|
- common
|
||||||
steps:
|
steps:
|
||||||
@ -251,7 +251,7 @@ jobs:
|
|||||||
|
|
||||||
clang-tidy:
|
clang-tidy:
|
||||||
name: ${{ matrix.name }}
|
name: ${{ matrix.name }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
- common
|
- common
|
||||||
- black
|
- black
|
||||||
@ -302,23 +302,18 @@ jobs:
|
|||||||
|
|
||||||
- name: Cache platformio
|
- name: Cache platformio
|
||||||
if: github.ref == 'refs/heads/dev'
|
if: github.ref == 'refs/heads/dev'
|
||||||
uses: actions/cache@v4.1.2
|
uses: actions/cache@v4.2.0
|
||||||
with:
|
with:
|
||||||
path: ~/.platformio
|
path: ~/.platformio
|
||||||
key: platformio-${{ matrix.pio_cache_key }}
|
key: platformio-${{ matrix.pio_cache_key }}
|
||||||
|
|
||||||
- name: Cache platformio
|
- name: Cache platformio
|
||||||
if: github.ref != 'refs/heads/dev'
|
if: github.ref != 'refs/heads/dev'
|
||||||
uses: actions/cache/restore@v4.1.2
|
uses: actions/cache/restore@v4.2.0
|
||||||
with:
|
with:
|
||||||
path: ~/.platformio
|
path: ~/.platformio
|
||||||
key: platformio-${{ matrix.pio_cache_key }}
|
key: platformio-${{ matrix.pio_cache_key }}
|
||||||
|
|
||||||
- name: Install clang-tidy
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install clang-tidy-14
|
|
||||||
|
|
||||||
- name: Register problem matchers
|
- name: Register problem matchers
|
||||||
run: |
|
run: |
|
||||||
echo "::add-matcher::.github/workflows/matchers/gcc.json"
|
echo "::add-matcher::.github/workflows/matchers/gcc.json"
|
||||||
@ -345,7 +340,7 @@ jobs:
|
|||||||
if: always()
|
if: always()
|
||||||
|
|
||||||
list-components:
|
list-components:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
- common
|
- common
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
@ -387,7 +382,7 @@ jobs:
|
|||||||
|
|
||||||
test-build-components:
|
test-build-components:
|
||||||
name: Component test ${{ matrix.file }}
|
name: Component test ${{ matrix.file }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
- common
|
- common
|
||||||
- list-components
|
- list-components
|
||||||
@ -421,7 +416,7 @@ jobs:
|
|||||||
|
|
||||||
test-build-components-splitter:
|
test-build-components-splitter:
|
||||||
name: Split components for testing into 20 groups maximum
|
name: Split components for testing into 20 groups maximum
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
- common
|
- common
|
||||||
- list-components
|
- list-components
|
||||||
@ -439,7 +434,7 @@ jobs:
|
|||||||
|
|
||||||
test-build-components-split:
|
test-build-components-split:
|
||||||
name: Test split components
|
name: Test split components
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
- common
|
- common
|
||||||
- list-components
|
- list-components
|
||||||
@ -483,7 +478,7 @@ jobs:
|
|||||||
|
|
||||||
ci-status:
|
ci-status:
|
||||||
name: CI Status
|
name: CI Status
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
- common
|
- common
|
||||||
- black
|
- black
|
||||||
|
@ -179,6 +179,7 @@ esphome/components/haier/text_sensor/* @paveldn
|
|||||||
esphome/components/havells_solar/* @sourabhjaiswal
|
esphome/components/havells_solar/* @sourabhjaiswal
|
||||||
esphome/components/hbridge/fan/* @WeekendWarrior
|
esphome/components/hbridge/fan/* @WeekendWarrior
|
||||||
esphome/components/hbridge/light/* @DotNetDann
|
esphome/components/hbridge/light/* @DotNetDann
|
||||||
|
esphome/components/hbridge/switch/* @dwmw2
|
||||||
esphome/components/he60r/* @clydebarrow
|
esphome/components/he60r/* @clydebarrow
|
||||||
esphome/components/heatpumpir/* @rob-deutsch
|
esphome/components/heatpumpir/* @rob-deutsch
|
||||||
esphome/components/hitachi_ac424/* @sourabhjaiswal
|
esphome/components/hitachi_ac424/* @sourabhjaiswal
|
||||||
|
@ -163,6 +163,18 @@ ENTRYPOINT ["/entrypoint.sh"]
|
|||||||
CMD ["dashboard", "/config"]
|
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 =======================
|
# ======================= hassio-type image =======================
|
||||||
@ -194,7 +206,7 @@ RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
|
|||||||
# Labels
|
# Labels
|
||||||
LABEL \
|
LABEL \
|
||||||
io.hass.name="ESPHome" \
|
io.hass.name="ESPHome" \
|
||||||
io.hass.description="Manage and program ESP8266/ESP32 microcontrollers through YAML configuration files" \
|
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.type="addon" \
|
io.hass.type="addon" \
|
||||||
io.hass.version="${BUILD_VERSION}"
|
io.hass.version="${BUILD_VERSION}"
|
||||||
# io.hass.arch is inherited from addon-debian-base
|
# io.hass.arch is inherited from addon-debian-base
|
||||||
@ -209,17 +221,22 @@ ENV \
|
|||||||
PLATFORMIO_CORE_DIR=/esphome/.temp/platformio
|
PLATFORMIO_CORE_DIR=/esphome/.temp/platformio
|
||||||
|
|
||||||
RUN \
|
RUN \
|
||||||
apt-get update \
|
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 \
|
||||||
# Use pinned versions so that we get updates with build caching
|
# Use pinned versions so that we get updates with build caching
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
clang-format-13=1:13.0.1-11+b2 \
|
clang-format-13=1:13.0.1-11+b2 \
|
||||||
clang-tidy-14=1:14.0.6-12 \
|
|
||||||
patch=2.7.6-7 \
|
patch=2.7.6-7 \
|
||||||
software-properties-common=0.99.30-4.1~deb12u1 \
|
software-properties-common=0.99.30-4.1~deb12u1 \
|
||||||
nano=7.2-1+deb12u1 \
|
nano=7.2-1+deb12u1 \
|
||||||
build-essential=12.9 \
|
build-essential=12.9 \
|
||||||
python3-dev=3.11.2-1+b1 \
|
python3-dev=3.11.2-1+b1 \
|
||||||
&& rm -rf \
|
&& if [ "$TARGETARCH$TARGETVARIANT" != "armv7" ]; then \
|
||||||
|
# move this up after armv7 is retired
|
||||||
|
apt-get install -y --no-install-recommends clang-tidy-18=1:18.1.8~++20240731024826+3b5b5c1ec4a3-1~exp1~20240731144843.145 ; \
|
||||||
|
fi; \
|
||||||
|
rm -rf \
|
||||||
/tmp/* \
|
/tmp/* \
|
||||||
/var/{cache,log}/* \
|
/var/{cache,log}/* \
|
||||||
/var/lib/apt/lists/*
|
/var/lib/apt/lists/*
|
||||||
|
@ -363,7 +363,7 @@ def upload_program(config, args, host):
|
|||||||
|
|
||||||
from esphome import espota2
|
from esphome import espota2
|
||||||
|
|
||||||
remote_port = ota_conf[CONF_PORT]
|
remote_port = int(ota_conf[CONF_PORT])
|
||||||
password = ota_conf.get(CONF_PASSWORD, "")
|
password = ota_conf.get(CONF_PASSWORD, "")
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -2,7 +2,6 @@ import logging
|
|||||||
|
|
||||||
from esphome import automation, core
|
from esphome import automation, core
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.components import font
|
|
||||||
import esphome.components.image as espImage
|
import esphome.components.image as espImage
|
||||||
from esphome.components.image import (
|
from esphome.components.image import (
|
||||||
CONF_USE_TRANSPARENCY,
|
CONF_USE_TRANSPARENCY,
|
||||||
@ -131,7 +130,7 @@ ANIMATION_SCHEMA = cv.Schema(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, ANIMATION_SCHEMA)
|
CONFIG_SCHEMA = ANIMATION_SCHEMA
|
||||||
|
|
||||||
NEXT_FRAME_SCHEMA = automation.maybe_simple_id(
|
NEXT_FRAME_SCHEMA = automation.maybe_simple_id(
|
||||||
{
|
{
|
||||||
|
@ -662,20 +662,24 @@ void DisplayOnPageChangeTrigger::process(DisplayPage *from, DisplayPage *to) {
|
|||||||
if ((this->from_ == nullptr || this->from_ == from) && (this->to_ == nullptr || this->to_ == to))
|
if ((this->from_ == nullptr || this->from_ == from) && (this->to_ == nullptr || this->to_ == to))
|
||||||
this->trigger(from, to);
|
this->trigger(from, to);
|
||||||
}
|
}
|
||||||
void Display::strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time) {
|
void Display::strftime(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format,
|
||||||
|
ESPTime time) {
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
this->print(x, y, font, color, align, buffer);
|
this->print(x, y, font, color, align, buffer, background);
|
||||||
|
}
|
||||||
|
void Display::strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time) {
|
||||||
|
this->strftime(x, y, font, color, COLOR_OFF, TextAlign::TOP_LEFT, format, time);
|
||||||
}
|
}
|
||||||
void Display::strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time) {
|
void Display::strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time) {
|
||||||
this->strftime(x, y, font, color, TextAlign::TOP_LEFT, format, time);
|
this->strftime(x, y, font, color, COLOR_OFF, TextAlign::TOP_LEFT, format, time);
|
||||||
}
|
}
|
||||||
void Display::strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time) {
|
void Display::strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time) {
|
||||||
this->strftime(x, y, font, COLOR_ON, align, format, time);
|
this->strftime(x, y, font, COLOR_ON, COLOR_OFF, align, format, time);
|
||||||
}
|
}
|
||||||
void Display::strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) {
|
void Display::strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) {
|
||||||
this->strftime(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, time);
|
this->strftime(x, y, font, COLOR_ON, COLOR_OFF, TextAlign::TOP_LEFT, format, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Display::start_clipping(Rect rect) {
|
void Display::start_clipping(Rect rect) {
|
||||||
|
@ -437,6 +437,20 @@ class Display : public PollingComponent {
|
|||||||
*/
|
*/
|
||||||
void printf(int x, int y, BaseFont *font, const char *format, ...) __attribute__((format(printf, 5, 6)));
|
void printf(int x, int y, BaseFont *font, const char *format, ...) __attribute__((format(printf, 5, 6)));
|
||||||
|
|
||||||
|
/** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`.
|
||||||
|
*
|
||||||
|
* @param x The x coordinate of the text alignment anchor point.
|
||||||
|
* @param y The y coordinate of the text alignment anchor point.
|
||||||
|
* @param font The font to draw the text with.
|
||||||
|
* @param color The color to draw the text with.
|
||||||
|
* @param background The background color to draw the text with.
|
||||||
|
* @param align The alignment of the text.
|
||||||
|
* @param format The format to use.
|
||||||
|
* @param ... The arguments to use for the text formatting.
|
||||||
|
*/
|
||||||
|
void strftime(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format,
|
||||||
|
ESPTime time) __attribute__((format(strftime, 8, 0)));
|
||||||
|
|
||||||
/** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`.
|
/** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`.
|
||||||
*
|
*
|
||||||
* @param x The x coordinate of the text alignment anchor point.
|
* @param x The x coordinate of the text alignment anchor point.
|
||||||
|
@ -65,6 +65,8 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
CODEOWNERS = ["@esphome/core"]
|
CODEOWNERS = ["@esphome/core"]
|
||||||
AUTO_LOAD = ["preferences"]
|
AUTO_LOAD = ["preferences"]
|
||||||
|
|
||||||
|
CONF_RELEASE = "release"
|
||||||
|
|
||||||
|
|
||||||
def set_core_data(config):
|
def set_core_data(config):
|
||||||
CORE.data[KEY_ESP32] = {}
|
CORE.data[KEY_ESP32] = {}
|
||||||
@ -216,11 +218,17 @@ def _format_framework_arduino_version(ver: cv.Version) -> str:
|
|||||||
return f"~3.{ver.major}{ver.minor:02d}{ver.patch:02d}.0"
|
return f"~3.{ver.major}{ver.minor:02d}{ver.patch:02d}.0"
|
||||||
|
|
||||||
|
|
||||||
def _format_framework_espidf_version(ver: cv.Version) -> str:
|
def _format_framework_espidf_version(
|
||||||
|
ver: cv.Version, release: str, for_platformio: bool
|
||||||
|
) -> str:
|
||||||
# format the given arduino (https://github.com/espressif/esp-idf/releases) version to
|
# format the given arduino (https://github.com/espressif/esp-idf/releases) version to
|
||||||
# a PIO platformio/framework-espidf value
|
# a PIO platformio/framework-espidf value
|
||||||
# List of package versions: https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf
|
# List of package versions: https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf
|
||||||
return f"~3.{ver.major}{ver.minor:02d}{ver.patch:02d}.0"
|
if for_platformio:
|
||||||
|
return f"platformio/framework-espidf@~3.{ver.major}{ver.minor:02d}{ver.patch:02d}.0"
|
||||||
|
if release:
|
||||||
|
return f"pioarduino/framework-espidf@https://github.com/pioarduino/esp-idf/releases/download/v{str(ver)}.{release}/esp-idf-v{str(ver)}.zip"
|
||||||
|
return f"pioarduino/framework-espidf@https://github.com/pioarduino/esp-idf/releases/download/v{str(ver)}/esp-idf-v{str(ver)}.zip"
|
||||||
|
|
||||||
|
|
||||||
# NOTE: Keep this in mind when updating the recommended version:
|
# NOTE: Keep this in mind when updating the recommended version:
|
||||||
@ -241,11 +249,33 @@ ARDUINO_PLATFORM_VERSION = cv.Version(5, 4, 0)
|
|||||||
# The default/recommended esp-idf framework version
|
# The default/recommended esp-idf framework version
|
||||||
# - https://github.com/espressif/esp-idf/releases
|
# - https://github.com/espressif/esp-idf/releases
|
||||||
# - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf
|
# - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf
|
||||||
RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 4, 8)
|
RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(5, 1, 5)
|
||||||
# The platformio/espressif32 version to use for esp-idf frameworks
|
# The platformio/espressif32 version to use for esp-idf frameworks
|
||||||
# - https://github.com/platformio/platform-espressif32/releases
|
# - https://github.com/platformio/platform-espressif32/releases
|
||||||
# - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32
|
# - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32
|
||||||
ESP_IDF_PLATFORM_VERSION = cv.Version(5, 4, 0)
|
ESP_IDF_PLATFORM_VERSION = cv.Version(51, 3, 7)
|
||||||
|
|
||||||
|
# List based on https://registry.platformio.org/tools/platformio/framework-espidf/versions
|
||||||
|
SUPPORTED_PLATFORMIO_ESP_IDF_5X = [
|
||||||
|
cv.Version(5, 3, 1),
|
||||||
|
cv.Version(5, 3, 0),
|
||||||
|
cv.Version(5, 2, 2),
|
||||||
|
cv.Version(5, 2, 1),
|
||||||
|
cv.Version(5, 1, 2),
|
||||||
|
cv.Version(5, 1, 1),
|
||||||
|
cv.Version(5, 1, 0),
|
||||||
|
cv.Version(5, 0, 2),
|
||||||
|
cv.Version(5, 0, 1),
|
||||||
|
cv.Version(5, 0, 0),
|
||||||
|
]
|
||||||
|
|
||||||
|
# pioarduino versions that don't require a release number
|
||||||
|
# List based on https://github.com/pioarduino/esp-idf/releases
|
||||||
|
SUPPORTED_PIOARDUINO_ESP_IDF_5X = [
|
||||||
|
cv.Version(5, 3, 1),
|
||||||
|
cv.Version(5, 3, 0),
|
||||||
|
cv.Version(5, 1, 5),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def _arduino_check_versions(value):
|
def _arduino_check_versions(value):
|
||||||
@ -286,8 +316,8 @@ def _arduino_check_versions(value):
|
|||||||
def _esp_idf_check_versions(value):
|
def _esp_idf_check_versions(value):
|
||||||
value = value.copy()
|
value = value.copy()
|
||||||
lookups = {
|
lookups = {
|
||||||
"dev": (cv.Version(5, 1, 2), "https://github.com/espressif/esp-idf.git"),
|
"dev": (cv.Version(5, 1, 5), "https://github.com/espressif/esp-idf.git"),
|
||||||
"latest": (cv.Version(5, 1, 2), None),
|
"latest": (cv.Version(5, 1, 5), None),
|
||||||
"recommended": (RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION, None),
|
"recommended": (RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION, None),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,13 +335,51 @@ def _esp_idf_check_versions(value):
|
|||||||
if version < cv.Version(4, 0, 0):
|
if version < cv.Version(4, 0, 0):
|
||||||
raise cv.Invalid("Only ESP-IDF 4.0+ is supported.")
|
raise cv.Invalid("Only ESP-IDF 4.0+ is supported.")
|
||||||
|
|
||||||
value[CONF_VERSION] = str(version)
|
# flag this for later *before* we set value[CONF_PLATFORM_VERSION] below
|
||||||
value[CONF_SOURCE] = source or _format_framework_espidf_version(version)
|
has_platform_ver = CONF_PLATFORM_VERSION in value
|
||||||
|
|
||||||
value[CONF_PLATFORM_VERSION] = value.get(
|
value[CONF_PLATFORM_VERSION] = value.get(
|
||||||
CONF_PLATFORM_VERSION, _parse_platform_version(str(ESP_IDF_PLATFORM_VERSION))
|
CONF_PLATFORM_VERSION, _parse_platform_version(str(ESP_IDF_PLATFORM_VERSION))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
(is_platformio := _platform_is_platformio(value[CONF_PLATFORM_VERSION]))
|
||||||
|
and version.major >= 5
|
||||||
|
and version not in SUPPORTED_PLATFORMIO_ESP_IDF_5X
|
||||||
|
):
|
||||||
|
raise cv.Invalid(
|
||||||
|
f"ESP-IDF {str(version)} not supported by platformio/espressif32"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
version.major < 5
|
||||||
|
or (
|
||||||
|
version in SUPPORTED_PLATFORMIO_ESP_IDF_5X
|
||||||
|
and version not in SUPPORTED_PIOARDUINO_ESP_IDF_5X
|
||||||
|
)
|
||||||
|
) and not has_platform_ver:
|
||||||
|
raise cv.Invalid(
|
||||||
|
f"ESP-IDF {value[CONF_VERSION]} may be supported by platformio/espressif32; please specify '{CONF_PLATFORM_VERSION}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
not is_platformio
|
||||||
|
and CONF_RELEASE not in value
|
||||||
|
and version not in SUPPORTED_PIOARDUINO_ESP_IDF_5X
|
||||||
|
):
|
||||||
|
raise cv.Invalid(
|
||||||
|
f"ESP-IDF {value[CONF_VERSION]} is not available with pioarduino; you may need to specify '{CONF_RELEASE}'"
|
||||||
|
)
|
||||||
|
|
||||||
|
value[CONF_VERSION] = str(version)
|
||||||
|
value[CONF_SOURCE] = source or _format_framework_espidf_version(
|
||||||
|
version, value.get(CONF_RELEASE, None), is_platformio
|
||||||
|
)
|
||||||
|
|
||||||
|
if value[CONF_SOURCE].startswith("http"):
|
||||||
|
# prefix is necessary or platformio will complain with a cryptic error
|
||||||
|
value[CONF_SOURCE] = f"framework-espidf@{value[CONF_SOURCE]}"
|
||||||
|
|
||||||
if version != RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION:
|
if version != RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"The selected ESP-IDF framework version is not the recommended one. "
|
"The selected ESP-IDF framework version is not the recommended one. "
|
||||||
@ -323,6 +391,12 @@ def _esp_idf_check_versions(value):
|
|||||||
|
|
||||||
def _parse_platform_version(value):
|
def _parse_platform_version(value):
|
||||||
try:
|
try:
|
||||||
|
ver = cv.Version.parse(cv.version_number(value))
|
||||||
|
if ver.major >= 50: # a pioarduino version
|
||||||
|
if "-" in value:
|
||||||
|
# maybe a release candidate?...definitely not our default, just use it as-is...
|
||||||
|
return f"https://github.com/pioarduino/platform-espressif32.git#{value}"
|
||||||
|
return f"https://github.com/pioarduino/platform-espressif32.git#{ver.major}.{ver.minor:02d}.{ver.patch:02d}"
|
||||||
# if platform version is a valid version constraint, prefix the default package
|
# if platform version is a valid version constraint, prefix the default package
|
||||||
cv.platformio_version_constraint(value)
|
cv.platformio_version_constraint(value)
|
||||||
return f"platformio/espressif32@{value}"
|
return f"platformio/espressif32@{value}"
|
||||||
@ -330,6 +404,14 @@ def _parse_platform_version(value):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def _platform_is_platformio(value):
|
||||||
|
try:
|
||||||
|
ver = cv.Version.parse(cv.version_number(value))
|
||||||
|
return ver.major < 50
|
||||||
|
except cv.Invalid:
|
||||||
|
return "platformio" in value
|
||||||
|
|
||||||
|
|
||||||
def _detect_variant(value):
|
def _detect_variant(value):
|
||||||
board = value[CONF_BOARD]
|
board = value[CONF_BOARD]
|
||||||
if board in BOARDS:
|
if board in BOARDS:
|
||||||
@ -355,24 +437,20 @@ def _detect_variant(value):
|
|||||||
|
|
||||||
|
|
||||||
def final_validate(config):
|
def final_validate(config):
|
||||||
if CONF_PLATFORMIO_OPTIONS not in fv.full_config.get()[CONF_ESPHOME]:
|
if not (
|
||||||
|
pio_options := fv.full_config.get()[CONF_ESPHOME].get(CONF_PLATFORMIO_OPTIONS)
|
||||||
|
):
|
||||||
|
# Not specified or empty
|
||||||
return config
|
return config
|
||||||
|
|
||||||
pio_flash_size_key = "board_upload.flash_size"
|
pio_flash_size_key = "board_upload.flash_size"
|
||||||
pio_partitions_key = "board_build.partitions"
|
pio_partitions_key = "board_build.partitions"
|
||||||
if (
|
if CONF_PARTITIONS in config and pio_partitions_key in pio_options:
|
||||||
CONF_PARTITIONS in config
|
|
||||||
and pio_partitions_key
|
|
||||||
in fv.full_config.get()[CONF_ESPHOME][CONF_PLATFORMIO_OPTIONS]
|
|
||||||
):
|
|
||||||
raise cv.Invalid(
|
raise cv.Invalid(
|
||||||
f"Do not specify '{pio_partitions_key}' in '{CONF_PLATFORMIO_OPTIONS}' with '{CONF_PARTITIONS}' in esp32"
|
f"Do not specify '{pio_partitions_key}' in '{CONF_PLATFORMIO_OPTIONS}' with '{CONF_PARTITIONS}' in esp32"
|
||||||
)
|
)
|
||||||
|
|
||||||
if (
|
if pio_flash_size_key in pio_options:
|
||||||
pio_flash_size_key
|
|
||||||
in fv.full_config.get()[CONF_ESPHOME][CONF_PLATFORMIO_OPTIONS]
|
|
||||||
):
|
|
||||||
raise cv.Invalid(
|
raise cv.Invalid(
|
||||||
f"Please specify {CONF_FLASH_SIZE} within esp32 configuration only"
|
f"Please specify {CONF_FLASH_SIZE} within esp32 configuration only"
|
||||||
)
|
)
|
||||||
@ -412,6 +490,7 @@ ESP_IDF_FRAMEWORK_SCHEMA = cv.All(
|
|||||||
cv.Schema(
|
cv.Schema(
|
||||||
{
|
{
|
||||||
cv.Optional(CONF_VERSION, default="recommended"): cv.string_strict,
|
cv.Optional(CONF_VERSION, default="recommended"): cv.string_strict,
|
||||||
|
cv.Optional(CONF_RELEASE): cv.string_strict,
|
||||||
cv.Optional(CONF_SOURCE): cv.string_strict,
|
cv.Optional(CONF_SOURCE): cv.string_strict,
|
||||||
cv.Optional(CONF_PLATFORM_VERSION): _parse_platform_version,
|
cv.Optional(CONF_PLATFORM_VERSION): _parse_platform_version,
|
||||||
cv.Optional(CONF_SDKCONFIG_OPTIONS, default={}): {
|
cv.Optional(CONF_SDKCONFIG_OPTIONS, default={}): {
|
||||||
@ -515,10 +594,9 @@ async def to_code(config):
|
|||||||
cg.add_build_flag("-DUSE_ESP_IDF")
|
cg.add_build_flag("-DUSE_ESP_IDF")
|
||||||
cg.add_build_flag("-DUSE_ESP32_FRAMEWORK_ESP_IDF")
|
cg.add_build_flag("-DUSE_ESP32_FRAMEWORK_ESP_IDF")
|
||||||
cg.add_build_flag("-Wno-nonnull-compare")
|
cg.add_build_flag("-Wno-nonnull-compare")
|
||||||
cg.add_platformio_option(
|
|
||||||
"platform_packages",
|
cg.add_platformio_option("platform_packages", [conf[CONF_SOURCE]])
|
||||||
[f"platformio/framework-espidf@{conf[CONF_SOURCE]}"],
|
|
||||||
)
|
|
||||||
# platformio/toolchain-esp32ulp does not support linux_aarch64 yet and has not been updated for over 2 years
|
# platformio/toolchain-esp32ulp does not support linux_aarch64 yet and has not been updated for over 2 years
|
||||||
# This is espressif's own published version which is more up to date.
|
# This is espressif's own published version which is more up to date.
|
||||||
cg.add_platformio_option(
|
cg.add_platformio_option(
|
||||||
|
@ -2,8 +2,10 @@ from esphome import automation
|
|||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant
|
from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import CONF_ENABLE_ON_BOOT, CONF_ID
|
from esphome.const import CONF_ENABLE_ON_BOOT, CONF_ESPHOME, CONF_ID, CONF_NAME
|
||||||
from esphome.core import CORE
|
from esphome.core import CORE
|
||||||
|
from esphome.core.config import CONF_NAME_ADD_MAC_SUFFIX
|
||||||
|
import esphome.final_validate as fv
|
||||||
|
|
||||||
DEPENDENCIES = ["esp32"]
|
DEPENDENCIES = ["esp32"]
|
||||||
CODEOWNERS = ["@jesserockz", "@Rapsssito"]
|
CODEOWNERS = ["@jesserockz", "@Rapsssito"]
|
||||||
@ -50,6 +52,7 @@ TX_POWER_LEVELS = {
|
|||||||
CONFIG_SCHEMA = cv.Schema(
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(ESP32BLE),
|
cv.GenerateID(): cv.declare_id(ESP32BLE),
|
||||||
|
cv.Optional(CONF_NAME): cv.All(cv.string, cv.Length(max=20)),
|
||||||
cv.Optional(CONF_IO_CAPABILITY, default="none"): cv.enum(
|
cv.Optional(CONF_IO_CAPABILITY, default="none"): cv.enum(
|
||||||
IO_CAPABILITY, lower=True
|
IO_CAPABILITY, lower=True
|
||||||
),
|
),
|
||||||
@ -67,7 +70,22 @@ def validate_variant(_):
|
|||||||
raise cv.Invalid(f"{variant} does not support Bluetooth")
|
raise cv.Invalid(f"{variant} does not support Bluetooth")
|
||||||
|
|
||||||
|
|
||||||
FINAL_VALIDATE_SCHEMA = validate_variant
|
def final_validation(config):
|
||||||
|
validate_variant(config)
|
||||||
|
if (name := config.get(CONF_NAME)) is not None:
|
||||||
|
full_config = fv.full_config.get()
|
||||||
|
max_length = 20
|
||||||
|
if full_config[CONF_ESPHOME][CONF_NAME_ADD_MAC_SUFFIX]:
|
||||||
|
max_length -= 7 # "-AABBCC" is appended when add mac suffix option is used
|
||||||
|
if len(name) > max_length:
|
||||||
|
raise cv.Invalid(
|
||||||
|
f"Name '{name}' is too long, maximum length is {max_length} characters"
|
||||||
|
)
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = final_validation
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
@ -75,6 +93,8 @@ async def to_code(config):
|
|||||||
cg.add(var.set_enable_on_boot(config[CONF_ENABLE_ON_BOOT]))
|
cg.add(var.set_enable_on_boot(config[CONF_ENABLE_ON_BOOT]))
|
||||||
cg.add(var.set_io_capability(config[CONF_IO_CAPABILITY]))
|
cg.add(var.set_io_capability(config[CONF_IO_CAPABILITY]))
|
||||||
cg.add(var.set_advertising_cycle_time(config[CONF_ADVERTISING_CYCLE_TIME]))
|
cg.add(var.set_advertising_cycle_time(config[CONF_ADVERTISING_CYCLE_TIME]))
|
||||||
|
if (name := config.get(CONF_NAME)) is not None:
|
||||||
|
cg.add(var.set_name(name))
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
if CORE.using_esp_idf:
|
if CORE.using_esp_idf:
|
||||||
|
@ -188,12 +188,20 @@ bool ESP32BLE::ble_setup_() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string name = App.get_name();
|
std::string name;
|
||||||
if (name.length() > 20) {
|
if (this->name_.has_value()) {
|
||||||
|
name = this->name_.value();
|
||||||
if (App.is_name_add_mac_suffix_enabled()) {
|
if (App.is_name_add_mac_suffix_enabled()) {
|
||||||
name.erase(name.begin() + 13, name.end() - 7); // Remove characters between 13 and the mac address
|
name += "-" + get_mac_address().substr(6);
|
||||||
} else {
|
}
|
||||||
name = name.substr(0, 20);
|
} else {
|
||||||
|
name = App.get_name();
|
||||||
|
if (name.length() > 20) {
|
||||||
|
if (App.is_name_add_mac_suffix_enabled()) {
|
||||||
|
name.erase(name.begin() + 13, name.end() - 7); // Remove characters between 13 and the mac address
|
||||||
|
} else {
|
||||||
|
name = name.substr(0, 20);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +90,7 @@ class ESP32BLE : public Component {
|
|||||||
void loop() override;
|
void loop() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
float get_setup_priority() const override;
|
float get_setup_priority() const override;
|
||||||
|
void set_name(const std::string &name) { this->name_ = name; }
|
||||||
|
|
||||||
void advertising_start();
|
void advertising_start();
|
||||||
void advertising_set_service_data(const std::vector<uint8_t> &data);
|
void advertising_set_service_data(const std::vector<uint8_t> &data);
|
||||||
@ -131,6 +132,7 @@ class ESP32BLE : public Component {
|
|||||||
esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE};
|
esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE};
|
||||||
uint32_t advertising_cycle_time_;
|
uint32_t advertising_cycle_time_;
|
||||||
bool enable_on_boot_;
|
bool enable_on_boot_;
|
||||||
|
optional<std::string> name_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
@ -83,7 +83,7 @@ esp_err_t BLEAdvertising::services_advertisement_() {
|
|||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
|
|
||||||
this->advertising_data_.set_scan_rsp = false;
|
this->advertising_data_.set_scan_rsp = false;
|
||||||
this->advertising_data_.include_name = !this->scan_response_;
|
this->advertising_data_.include_name = true;
|
||||||
this->advertising_data_.include_txpower = !this->scan_response_;
|
this->advertising_data_.include_txpower = !this->scan_response_;
|
||||||
err = esp_ble_gap_config_adv_data(&this->advertising_data_);
|
err = esp_ble_gap_config_adv_data(&this->advertising_data_);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
import esphome.codegen as cg
|
|
||||||
import esphome.config_validation as cv
|
|
||||||
from esphome import pins
|
from esphome import pins
|
||||||
|
import esphome.codegen as cg
|
||||||
from esphome.components import esp32_rmt, light
|
from esphome.components import esp32_rmt, light
|
||||||
|
import esphome.config_validation as cv
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_CHIPSET,
|
CONF_CHIPSET,
|
||||||
CONF_IS_RGBW,
|
CONF_IS_RGBW,
|
||||||
@ -103,7 +103,7 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
default="0 us",
|
default="0 us",
|
||||||
): cv.positive_time_period_nanoseconds,
|
): cv.positive_time_period_nanoseconds,
|
||||||
}
|
}
|
||||||
),
|
).extend(cv.COMPONENT_SCHEMA),
|
||||||
cv.has_exactly_one_key(CONF_CHIPSET, CONF_BIT0_HIGH),
|
cv.has_exactly_one_key(CONF_CHIPSET, CONF_BIT0_HIGH),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
from collections.abc import Iterable
|
|
||||||
import functools
|
import functools
|
||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
@ -8,7 +7,6 @@ import re
|
|||||||
|
|
||||||
import freetype
|
import freetype
|
||||||
import glyphsets
|
import glyphsets
|
||||||
from packaging import version
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from esphome import core, external_files
|
from esphome import core, external_files
|
||||||
@ -88,7 +86,7 @@ def flatten(lists) -> list:
|
|||||||
return list(chain.from_iterable(lists))
|
return list(chain.from_iterable(lists))
|
||||||
|
|
||||||
|
|
||||||
def check_missing_glyphs(file, codepoints: Iterable, warning: bool = False):
|
def check_missing_glyphs(file, codepoints, warning: bool = False):
|
||||||
"""
|
"""
|
||||||
Check that the given font file actually contains the requested glyphs
|
Check that the given font file actually contains the requested glyphs
|
||||||
:param file: A Truetype font file
|
:param file: A Truetype font file
|
||||||
@ -177,24 +175,6 @@ def validate_glyphs(config):
|
|||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
def validate_pillow_installed(value):
|
|
||||||
try:
|
|
||||||
import PIL
|
|
||||||
except ImportError as err:
|
|
||||||
raise cv.Invalid(
|
|
||||||
"Please install the pillow python package to use this feature. "
|
|
||||||
'(pip install "pillow==10.4.0")'
|
|
||||||
) from err
|
|
||||||
|
|
||||||
if version.parse(PIL.__version__) != version.parse("10.4.0"):
|
|
||||||
raise cv.Invalid(
|
|
||||||
"Please update your pillow installation to 10.4.0. "
|
|
||||||
'(pip install "pillow==10.4.0")'
|
|
||||||
)
|
|
||||||
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
FONT_EXTENSIONS = (".ttf", ".woff", ".otf")
|
FONT_EXTENSIONS = (".ttf", ".woff", ".otf")
|
||||||
|
|
||||||
|
|
||||||
@ -393,7 +373,9 @@ def font_file_schema(value):
|
|||||||
# Default if no glyphs or glyphsets are provided
|
# Default if no glyphs or glyphsets are provided
|
||||||
DEFAULT_GLYPHSET = "GF_Latin_Kernel"
|
DEFAULT_GLYPHSET = "GF_Latin_Kernel"
|
||||||
# default for bitmap fonts
|
# default for bitmap fonts
|
||||||
DEFAULT_GLYPHS = ' !"%()+=,-.:/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz<C2><B0>'
|
DEFAULT_GLYPHS = (
|
||||||
|
' !"%()+=,-.:/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz°'
|
||||||
|
)
|
||||||
|
|
||||||
CONF_RAW_GLYPH_ID = "raw_glyph_id"
|
CONF_RAW_GLYPH_ID = "raw_glyph_id"
|
||||||
|
|
||||||
@ -421,7 +403,7 @@ FONT_SCHEMA = cv.Schema(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(validate_pillow_installed, FONT_SCHEMA, validate_glyphs)
|
CONFIG_SCHEMA = cv.All(FONT_SCHEMA, validate_glyphs)
|
||||||
|
|
||||||
|
|
||||||
# PIL doesn't provide a consistent interface for both TrueType and bitmap
|
# PIL doesn't provide a consistent interface for both TrueType and bitmap
|
||||||
|
@ -35,7 +35,9 @@ void HonClimate::set_beeper_state(bool state) {
|
|||||||
if (state != this->settings_.beeper_state) {
|
if (state != this->settings_.beeper_state) {
|
||||||
this->settings_.beeper_state = state;
|
this->settings_.beeper_state = state;
|
||||||
#ifdef USE_SWITCH
|
#ifdef USE_SWITCH
|
||||||
this->beeper_switch_->publish_state(state);
|
if (this->beeper_switch_ != nullptr) {
|
||||||
|
this->beeper_switch_->publish_state(state);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
this->hon_rtc_.save(&this->settings_);
|
this->hon_rtc_.save(&this->settings_);
|
||||||
}
|
}
|
||||||
@ -45,10 +47,17 @@ bool HonClimate::get_beeper_state() const { return this->settings_.beeper_state;
|
|||||||
|
|
||||||
void HonClimate::set_quiet_mode_state(bool state) {
|
void HonClimate::set_quiet_mode_state(bool state) {
|
||||||
if (state != this->get_quiet_mode_state()) {
|
if (state != this->get_quiet_mode_state()) {
|
||||||
this->quiet_mode_state_ = state ? SwitchState::PENDING_ON : SwitchState::PENDING_OFF;
|
if ((this->mode != ClimateMode::CLIMATE_MODE_OFF) && (this->mode != ClimateMode::CLIMATE_MODE_FAN_ONLY)) {
|
||||||
|
this->quiet_mode_state_ = state ? SwitchState::PENDING_ON : SwitchState::PENDING_OFF;
|
||||||
|
this->force_send_control_ = true;
|
||||||
|
} else {
|
||||||
|
this->quiet_mode_state_ = state ? SwitchState::ON : SwitchState::OFF;
|
||||||
|
}
|
||||||
this->settings_.quiet_mode_state = state;
|
this->settings_.quiet_mode_state = state;
|
||||||
#ifdef USE_SWITCH
|
#ifdef USE_SWITCH
|
||||||
this->quiet_mode_switch_->publish_state(state);
|
if (this->quiet_mode_switch_ != nullptr) {
|
||||||
|
this->quiet_mode_switch_->publish_state(state);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
this->hon_rtc_.save(&this->settings_);
|
this->hon_rtc_.save(&this->settings_);
|
||||||
}
|
}
|
||||||
@ -509,7 +518,7 @@ void HonClimate::initialization() {
|
|||||||
}
|
}
|
||||||
this->current_vertical_swing_ = this->settings_.last_vertiacal_swing;
|
this->current_vertical_swing_ = this->settings_.last_vertiacal_swing;
|
||||||
this->current_horizontal_swing_ = this->settings_.last_horizontal_swing;
|
this->current_horizontal_swing_ = this->settings_.last_horizontal_swing;
|
||||||
this->quiet_mode_state_ = this->settings_.quiet_mode_state ? SwitchState::PENDING_ON : SwitchState::PENDING_OFF;
|
this->quiet_mode_state_ = this->settings_.quiet_mode_state ? SwitchState::ON : SwitchState::OFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
haier_protocol::HaierMessage HonClimate::get_control_message() {
|
haier_protocol::HaierMessage HonClimate::get_control_message() {
|
||||||
@ -932,7 +941,7 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *
|
|||||||
if (this->mode == CLIMATE_MODE_OFF) {
|
if (this->mode == CLIMATE_MODE_OFF) {
|
||||||
// AC just turned on from remote need to turn off display
|
// AC just turned on from remote need to turn off display
|
||||||
this->force_send_control_ = true;
|
this->force_send_control_ = true;
|
||||||
} else if ((((uint8_t) this->health_mode_) & 0b10) == 0) {
|
} else if ((((uint8_t) this->display_status_) & 0b10) == 0) {
|
||||||
this->display_status_ = disp_status ? SwitchState::ON : SwitchState::OFF;
|
this->display_status_ = disp_status ? SwitchState::ON : SwitchState::OFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1004,6 +1013,11 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *
|
|||||||
if (new_quiet_mode != this->get_quiet_mode_state()) {
|
if (new_quiet_mode != this->get_quiet_mode_state()) {
|
||||||
this->quiet_mode_state_ = new_quiet_mode ? SwitchState::ON : SwitchState::OFF;
|
this->quiet_mode_state_ = new_quiet_mode ? SwitchState::ON : SwitchState::OFF;
|
||||||
this->settings_.quiet_mode_state = new_quiet_mode;
|
this->settings_.quiet_mode_state = new_quiet_mode;
|
||||||
|
#ifdef USE_SWITCH
|
||||||
|
if (this->quiet_mode_switch_ != nullptr) {
|
||||||
|
this->quiet_mode_switch_->publish_state(new_quiet_mode);
|
||||||
|
}
|
||||||
|
#endif // USE_SWITCH
|
||||||
this->hon_rtc_.save(&this->settings_);
|
this->hon_rtc_.save(&this->settings_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
44
esphome/components/hbridge/switch/__init__.py
Normal file
44
esphome/components/hbridge/switch/__init__.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
from esphome import pins
|
||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import switch
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import CONF_OPTIMISTIC, CONF_PULSE_LENGTH, CONF_WAIT_TIME
|
||||||
|
|
||||||
|
from .. import hbridge_ns
|
||||||
|
|
||||||
|
HBridgeSwitch = hbridge_ns.class_("HBridgeSwitch", switch.Switch, cg.Component)
|
||||||
|
|
||||||
|
CODEOWNERS = ["@dwmw2"]
|
||||||
|
|
||||||
|
CONF_OFF_PIN = "off_pin"
|
||||||
|
CONF_ON_PIN = "on_pin"
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = (
|
||||||
|
switch.switch_schema(HBridgeSwitch)
|
||||||
|
.extend(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_ON_PIN): pins.gpio_output_pin_schema,
|
||||||
|
cv.Required(CONF_OFF_PIN): pins.gpio_output_pin_schema,
|
||||||
|
cv.Optional(
|
||||||
|
CONF_PULSE_LENGTH, default="100ms"
|
||||||
|
): cv.positive_time_period_milliseconds,
|
||||||
|
cv.Optional(CONF_WAIT_TIME): cv.positive_time_period_milliseconds,
|
||||||
|
cv.Optional(CONF_OPTIMISTIC, default=False): cv.boolean,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.extend(cv.COMPONENT_SCHEMA)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = await switch.new_switch(config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
on_pin = await cg.gpio_pin_expression(config[CONF_ON_PIN])
|
||||||
|
cg.add(var.set_on_pin(on_pin))
|
||||||
|
off_pin = await cg.gpio_pin_expression(config[CONF_OFF_PIN])
|
||||||
|
cg.add(var.set_off_pin(off_pin))
|
||||||
|
cg.add(var.set_pulse_length(config[CONF_PULSE_LENGTH]))
|
||||||
|
cg.add(var.set_optimistic(config[CONF_OPTIMISTIC]))
|
||||||
|
if wait_time := config.get(CONF_WAIT_TIME):
|
||||||
|
cg.add(var.set_wait_time(wait_time))
|
95
esphome/components/hbridge/switch/hbridge_switch.cpp
Normal file
95
esphome/components/hbridge/switch/hbridge_switch.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#include "hbridge_switch.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace hbridge {
|
||||||
|
|
||||||
|
static const char *const TAG = "switch.hbridge";
|
||||||
|
|
||||||
|
float HBridgeSwitch::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||||
|
void HBridgeSwitch::setup() {
|
||||||
|
ESP_LOGCONFIG(TAG, "Setting up H-Bridge Switch '%s'...", this->name_.c_str());
|
||||||
|
|
||||||
|
optional<bool> initial_state = this->get_initial_state_with_restore_mode().value_or(false);
|
||||||
|
|
||||||
|
// Like GPIOSwitch does, set the pin state both before and after pin setup()
|
||||||
|
this->on_pin_->digital_write(false);
|
||||||
|
this->on_pin_->setup();
|
||||||
|
this->on_pin_->digital_write(false);
|
||||||
|
|
||||||
|
this->off_pin_->digital_write(false);
|
||||||
|
this->off_pin_->setup();
|
||||||
|
this->off_pin_->digital_write(false);
|
||||||
|
|
||||||
|
if (initial_state.has_value())
|
||||||
|
this->write_state(initial_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HBridgeSwitch::dump_config() {
|
||||||
|
LOG_SWITCH("", "H-Bridge Switch", this);
|
||||||
|
LOG_PIN(" On Pin: ", this->on_pin_);
|
||||||
|
LOG_PIN(" Off Pin: ", this->off_pin_);
|
||||||
|
ESP_LOGCONFIG(TAG, " Pulse length: %" PRId32 " ms", this->pulse_length_);
|
||||||
|
if (this->wait_time_)
|
||||||
|
ESP_LOGCONFIG(TAG, " Wait time %" PRId32 " ms", this->wait_time_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HBridgeSwitch::write_state(bool state) {
|
||||||
|
this->desired_state_ = state;
|
||||||
|
if (!this->timer_running_)
|
||||||
|
this->timer_fn_();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HBridgeSwitch::timer_fn_() {
|
||||||
|
uint32_t next_timeout = 0;
|
||||||
|
|
||||||
|
while ((uint8_t) this->desired_state_ != this->relay_state_) {
|
||||||
|
switch (this->relay_state_) {
|
||||||
|
case RELAY_STATE_ON:
|
||||||
|
case RELAY_STATE_OFF:
|
||||||
|
case RELAY_STATE_UNKNOWN:
|
||||||
|
if (this->desired_state_) {
|
||||||
|
this->on_pin_->digital_write(true);
|
||||||
|
this->relay_state_ = RELAY_STATE_SWITCHING_ON;
|
||||||
|
} else {
|
||||||
|
this->off_pin_->digital_write(true);
|
||||||
|
this->relay_state_ = RELAY_STATE_SWITCHING_OFF;
|
||||||
|
}
|
||||||
|
next_timeout = this->pulse_length_;
|
||||||
|
if (!this->optimistic_)
|
||||||
|
this->publish_state(this->desired_state_);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RELAY_STATE_SWITCHING_ON:
|
||||||
|
this->on_pin_->digital_write(false);
|
||||||
|
this->relay_state_ = RELAY_STATE_ON;
|
||||||
|
if (this->optimistic_)
|
||||||
|
this->publish_state(true);
|
||||||
|
next_timeout = this->wait_time_;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RELAY_STATE_SWITCHING_OFF:
|
||||||
|
this->off_pin_->digital_write(false);
|
||||||
|
this->relay_state_ = RELAY_STATE_OFF;
|
||||||
|
if (this->optimistic_)
|
||||||
|
this->publish_state(false);
|
||||||
|
next_timeout = this->wait_time_;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next_timeout) {
|
||||||
|
this->timer_running_ = true;
|
||||||
|
this->set_timeout(next_timeout, [this]() { this->timer_fn_(); });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the case where ON/OFF state has been reached but we need to
|
||||||
|
// immediately change back again to reach desired_state_, we loop.
|
||||||
|
}
|
||||||
|
this->timer_running_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace hbridge
|
||||||
|
} // namespace esphome
|
50
esphome/components/hbridge/switch/hbridge_switch.h
Normal file
50
esphome/components/hbridge/switch/hbridge_switch.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/components/switch/switch.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace hbridge {
|
||||||
|
|
||||||
|
enum RelayState : uint8_t {
|
||||||
|
RELAY_STATE_OFF = 0,
|
||||||
|
RELAY_STATE_ON = 1,
|
||||||
|
RELAY_STATE_SWITCHING_ON = 2,
|
||||||
|
RELAY_STATE_SWITCHING_OFF = 3,
|
||||||
|
RELAY_STATE_UNKNOWN = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
class HBridgeSwitch : public switch_::Switch, public Component {
|
||||||
|
public:
|
||||||
|
void set_on_pin(GPIOPin *pin) { this->on_pin_ = pin; }
|
||||||
|
void set_off_pin(GPIOPin *pin) { this->off_pin_ = pin; }
|
||||||
|
void set_pulse_length(uint32_t pulse_length) { this->pulse_length_ = pulse_length; }
|
||||||
|
void set_wait_time(uint32_t wait_time) { this->wait_time_ = wait_time; }
|
||||||
|
void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
|
||||||
|
|
||||||
|
// ========== INTERNAL METHODS ==========
|
||||||
|
// (In most use cases you won't need these)
|
||||||
|
float get_setup_priority() const override;
|
||||||
|
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void write_state(bool state) override;
|
||||||
|
void timer_fn_();
|
||||||
|
|
||||||
|
bool timer_running_{false};
|
||||||
|
bool desired_state_{false};
|
||||||
|
RelayState relay_state_{RELAY_STATE_UNKNOWN};
|
||||||
|
GPIOPin *on_pin_{nullptr};
|
||||||
|
GPIOPin *off_pin_{nullptr};
|
||||||
|
uint32_t pulse_length_{0};
|
||||||
|
uint32_t wait_time_{0};
|
||||||
|
bool optimistic_{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace hbridge
|
||||||
|
} // namespace esphome
|
@ -53,7 +53,7 @@ bool HX711Sensor::read_sensor_(uint32_t *result) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cycle clock pin for gain setting
|
// Cycle clock pin for gain setting
|
||||||
for (uint8_t i = 0; i < this->gain_; i++) {
|
for (uint8_t i = 0; i < static_cast<uint8_t>(this->gain_); i++) {
|
||||||
this->sck_pin_->digital_write(true);
|
this->sck_pin_->digital_write(true);
|
||||||
delayMicroseconds(1);
|
delayMicroseconds(1);
|
||||||
this->sck_pin_->digital_write(false);
|
this->sck_pin_->digital_write(false);
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace hx711 {
|
namespace hx711 {
|
||||||
|
|
||||||
enum HX711Gain {
|
enum HX711Gain : uint8_t {
|
||||||
HX711_GAIN_128 = 1,
|
HX711_GAIN_128 = 1,
|
||||||
HX711_GAIN_32 = 2,
|
HX711_GAIN_32 = 2,
|
||||||
HX711_GAIN_64 = 3,
|
HX711_GAIN_64 = 3,
|
||||||
|
@ -33,14 +33,15 @@ enum SpeakerEventGroupBits : uint32_t {
|
|||||||
STATE_RUNNING = (1 << 11),
|
STATE_RUNNING = (1 << 11),
|
||||||
STATE_STOPPING = (1 << 12),
|
STATE_STOPPING = (1 << 12),
|
||||||
STATE_STOPPED = (1 << 13),
|
STATE_STOPPED = (1 << 13),
|
||||||
ERR_INVALID_FORMAT = (1 << 14),
|
ERR_TASK_FAILED_TO_START = (1 << 14),
|
||||||
ERR_TASK_FAILED_TO_START = (1 << 15),
|
ERR_ESP_INVALID_STATE = (1 << 15),
|
||||||
ERR_ESP_INVALID_STATE = (1 << 16),
|
ERR_ESP_NOT_SUPPORTED = (1 << 16),
|
||||||
ERR_ESP_INVALID_ARG = (1 << 17),
|
ERR_ESP_INVALID_ARG = (1 << 17),
|
||||||
ERR_ESP_INVALID_SIZE = (1 << 18),
|
ERR_ESP_INVALID_SIZE = (1 << 18),
|
||||||
ERR_ESP_NO_MEM = (1 << 19),
|
ERR_ESP_NO_MEM = (1 << 19),
|
||||||
ERR_ESP_FAIL = (1 << 20),
|
ERR_ESP_FAIL = (1 << 20),
|
||||||
ALL_ERR_ESP_BITS = ERR_ESP_INVALID_STATE | ERR_ESP_INVALID_ARG | ERR_ESP_INVALID_SIZE | ERR_ESP_NO_MEM | ERR_ESP_FAIL,
|
ALL_ERR_ESP_BITS = ERR_ESP_INVALID_STATE | ERR_ESP_NOT_SUPPORTED | ERR_ESP_INVALID_ARG | ERR_ESP_INVALID_SIZE |
|
||||||
|
ERR_ESP_NO_MEM | ERR_ESP_FAIL,
|
||||||
ALL_BITS = 0x00FFFFFF, // All valid FreeRTOS event group bits
|
ALL_BITS = 0x00FFFFFF, // All valid FreeRTOS event group bits
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -55,6 +56,8 @@ static esp_err_t err_bit_to_esp_err(uint32_t bit) {
|
|||||||
return ESP_ERR_INVALID_SIZE;
|
return ESP_ERR_INVALID_SIZE;
|
||||||
case SpeakerEventGroupBits::ERR_ESP_NO_MEM:
|
case SpeakerEventGroupBits::ERR_ESP_NO_MEM:
|
||||||
return ESP_ERR_NO_MEM;
|
return ESP_ERR_NO_MEM;
|
||||||
|
case SpeakerEventGroupBits::ERR_ESP_NOT_SUPPORTED:
|
||||||
|
return ESP_ERR_NOT_SUPPORTED;
|
||||||
default:
|
default:
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@ -135,19 +138,19 @@ void I2SAudioSpeaker::loop() {
|
|||||||
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START);
|
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event_group_bits & SpeakerEventGroupBits::ERR_INVALID_FORMAT) {
|
if (event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS) {
|
||||||
|
uint32_t error_bits = event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS;
|
||||||
|
ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(err_bit_to_esp_err(error_bits)));
|
||||||
|
this->status_set_warning();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event_group_bits & SpeakerEventGroupBits::ERR_ESP_NOT_SUPPORTED) {
|
||||||
this->status_set_error("Failed to adjust I2S bus to match the incoming audio");
|
this->status_set_error("Failed to adjust I2S bus to match the incoming audio");
|
||||||
ESP_LOGE(TAG,
|
ESP_LOGE(TAG,
|
||||||
"Incompatible audio format: sample rate = %" PRIu32 ", channels = %" PRIu8 ", bits per sample = %" PRIu8,
|
"Incompatible audio format: sample rate = %" PRIu32 ", channels = %" PRIu8 ", bits per sample = %" PRIu8,
|
||||||
this->audio_stream_info_.sample_rate, this->audio_stream_info_.channels,
|
this->audio_stream_info_.sample_rate, this->audio_stream_info_.channels,
|
||||||
this->audio_stream_info_.bits_per_sample);
|
this->audio_stream_info_.bits_per_sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS) {
|
|
||||||
uint32_t error_bits = event_group_bits & SpeakerEventGroupBits::ALL_ERR_ESP_BITS;
|
|
||||||
ESP_LOGW(TAG, "Error writing to I2S: %s", esp_err_to_name(err_bit_to_esp_err(error_bits)));
|
|
||||||
this->status_set_warning();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2SAudioSpeaker::set_volume(float volume) {
|
void I2SAudioSpeaker::set_volume(float volume) {
|
||||||
@ -236,13 +239,15 @@ void I2SAudioSpeaker::speaker_task(void *params) {
|
|||||||
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STARTING);
|
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STARTING);
|
||||||
|
|
||||||
audio::AudioStreamInfo audio_stream_info = this_speaker->audio_stream_info_;
|
audio::AudioStreamInfo audio_stream_info = this_speaker->audio_stream_info_;
|
||||||
const ssize_t bytes_per_sample = audio_stream_info.get_bytes_per_sample();
|
|
||||||
const uint8_t number_of_channels = audio_stream_info.channels;
|
|
||||||
|
|
||||||
const size_t dma_buffers_size = DMA_BUFFERS_COUNT * DMA_BUFFER_DURATION_MS * this_speaker->sample_rate_ / 1000 *
|
const uint32_t bytes_per_ms =
|
||||||
bytes_per_sample * number_of_channels;
|
audio_stream_info.channels * audio_stream_info.get_bytes_per_sample() * audio_stream_info.sample_rate / 1000;
|
||||||
|
|
||||||
|
const size_t dma_buffers_size = DMA_BUFFERS_COUNT * DMA_BUFFER_DURATION_MS * bytes_per_ms;
|
||||||
|
|
||||||
|
// Ensure ring buffer is at least as large as the total size of the DMA buffers
|
||||||
const size_t ring_buffer_size =
|
const size_t ring_buffer_size =
|
||||||
this_speaker->buffer_duration_ms_ * this_speaker->sample_rate_ / 1000 * bytes_per_sample * number_of_channels;
|
std::min((uint32_t) dma_buffers_size, this_speaker->buffer_duration_ms_ * bytes_per_ms);
|
||||||
|
|
||||||
if (this_speaker->send_esp_err_to_event_group_(this_speaker->allocate_buffers_(dma_buffers_size, ring_buffer_size))) {
|
if (this_speaker->send_esp_err_to_event_group_(this_speaker->allocate_buffers_(dma_buffers_size, ring_buffer_size))) {
|
||||||
// Failed to allocate buffers
|
// Failed to allocate buffers
|
||||||
@ -250,14 +255,7 @@ void I2SAudioSpeaker::speaker_task(void *params) {
|
|||||||
this_speaker->delete_task_(dma_buffers_size);
|
this_speaker->delete_task_(dma_buffers_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this_speaker->send_esp_err_to_event_group_(this_speaker->start_i2s_driver_())) {
|
if (!this_speaker->send_esp_err_to_event_group_(this_speaker->start_i2s_driver_(audio_stream_info))) {
|
||||||
// Failed to start I2S driver
|
|
||||||
this_speaker->delete_task_(dma_buffers_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this_speaker->send_esp_err_to_event_group_(this_speaker->reconfigure_i2s_stream_info_(audio_stream_info))) {
|
|
||||||
// Successfully set the I2S stream info, ready to write audio data to the I2S port
|
|
||||||
|
|
||||||
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_RUNNING);
|
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_RUNNING);
|
||||||
|
|
||||||
bool stop_gracefully = false;
|
bool stop_gracefully = false;
|
||||||
@ -275,6 +273,12 @@ void I2SAudioSpeaker::speaker_task(void *params) {
|
|||||||
stop_gracefully = true;
|
stop_gracefully = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this_speaker->audio_stream_info_ != audio_stream_info) {
|
||||||
|
// Audio stream info has changed, stop the speaker task so it will restart with the proper settings.
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
i2s_event_t i2s_event;
|
i2s_event_t i2s_event;
|
||||||
while (xQueueReceive(this_speaker->i2s_event_queue_, &i2s_event, 0)) {
|
while (xQueueReceive(this_speaker->i2s_event_queue_, &i2s_event, 0)) {
|
||||||
if (i2s_event.type == I2S_EVENT_TX_Q_OVF) {
|
if (i2s_event.type == I2S_EVENT_TX_Q_OVF) {
|
||||||
@ -316,17 +320,14 @@ void I2SAudioSpeaker::speaker_task(void *params) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Couldn't configure the I2S port to be compatible with the incoming audio
|
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STOPPING);
|
||||||
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::ERR_INVALID_FORMAT);
|
|
||||||
|
i2s_driver_uninstall(this_speaker->parent_->get_port());
|
||||||
|
|
||||||
|
this_speaker->parent_->unlock();
|
||||||
}
|
}
|
||||||
i2s_zero_dma_buffer(this_speaker->parent_->get_port());
|
|
||||||
|
|
||||||
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STOPPING);
|
|
||||||
|
|
||||||
i2s_driver_uninstall(this_speaker->parent_->get_port());
|
|
||||||
|
|
||||||
this_speaker->parent_->unlock();
|
|
||||||
this_speaker->delete_task_(dma_buffers_size);
|
this_speaker->delete_task_(dma_buffers_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,6 +383,9 @@ bool I2SAudioSpeaker::send_esp_err_to_event_group_(esp_err_t err) {
|
|||||||
case ESP_ERR_NO_MEM:
|
case ESP_ERR_NO_MEM:
|
||||||
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM);
|
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM);
|
||||||
return true;
|
return true;
|
||||||
|
case ESP_ERR_NOT_SUPPORTED:
|
||||||
|
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_NOT_SUPPORTED);
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_FAIL);
|
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_FAIL);
|
||||||
return true;
|
return true;
|
||||||
@ -411,18 +415,40 @@ esp_err_t I2SAudioSpeaker::allocate_buffers_(size_t data_buffer_size, size_t rin
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t I2SAudioSpeaker::start_i2s_driver_() {
|
esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_stream_info) {
|
||||||
|
if ((this->i2s_mode_ & I2S_MODE_SLAVE) && (this->sample_rate_ != audio_stream_info.sample_rate)) { // NOLINT
|
||||||
|
// Can't reconfigure I2S bus, so the sample rate must match the configured value
|
||||||
|
return ESP_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((i2s_bits_per_sample_t) audio_stream_info.bits_per_sample > this->bits_per_sample_) {
|
||||||
|
// Currently can't handle the case when the incoming audio has more bits per sample than the configured value
|
||||||
|
return ESP_ERR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this->parent_->try_lock()) {
|
if (!this->parent_->try_lock()) {
|
||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i2s_channel_fmt_t channel = this->channel_;
|
||||||
|
|
||||||
|
if (audio_stream_info.channels == 1) {
|
||||||
|
if (this->channel_ == I2S_CHANNEL_FMT_ONLY_LEFT) {
|
||||||
|
channel = I2S_CHANNEL_FMT_ONLY_LEFT;
|
||||||
|
} else {
|
||||||
|
channel = I2S_CHANNEL_FMT_ONLY_RIGHT;
|
||||||
|
}
|
||||||
|
} else if (audio_stream_info.channels == 2) {
|
||||||
|
channel = I2S_CHANNEL_FMT_RIGHT_LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
int dma_buffer_length = DMA_BUFFER_DURATION_MS * this->sample_rate_ / 1000;
|
int dma_buffer_length = DMA_BUFFER_DURATION_MS * this->sample_rate_ / 1000;
|
||||||
|
|
||||||
i2s_driver_config_t config = {
|
i2s_driver_config_t config = {
|
||||||
.mode = (i2s_mode_t) (this->i2s_mode_ | I2S_MODE_TX),
|
.mode = (i2s_mode_t) (this->i2s_mode_ | I2S_MODE_TX),
|
||||||
.sample_rate = this->sample_rate_,
|
.sample_rate = audio_stream_info.sample_rate,
|
||||||
.bits_per_sample = this->bits_per_sample_,
|
.bits_per_sample = this->bits_per_sample_,
|
||||||
.channel_format = this->channel_,
|
.channel_format = channel,
|
||||||
.communication_format = this->i2s_comm_fmt_,
|
.communication_format = this->i2s_comm_fmt_,
|
||||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
||||||
.dma_buf_count = DMA_BUFFERS_COUNT,
|
.dma_buf_count = DMA_BUFFERS_COUNT,
|
||||||
@ -477,30 +503,6 @@ esp_err_t I2SAudioSpeaker::start_i2s_driver_() {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t I2SAudioSpeaker::reconfigure_i2s_stream_info_(audio::AudioStreamInfo &audio_stream_info) {
|
|
||||||
if (this->i2s_mode_ & I2S_MODE_MASTER) {
|
|
||||||
// ESP controls for the the I2S bus, so adjust the sample rate and bits per sample to match the incoming audio
|
|
||||||
this->sample_rate_ = audio_stream_info.sample_rate;
|
|
||||||
this->bits_per_sample_ = (i2s_bits_per_sample_t) audio_stream_info.bits_per_sample;
|
|
||||||
} else if (this->sample_rate_ != audio_stream_info.sample_rate) {
|
|
||||||
// Can't reconfigure I2S bus, so the sample rate must match the configured value
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((i2s_bits_per_sample_t) audio_stream_info.bits_per_sample > this->bits_per_sample_) {
|
|
||||||
// Currently can't handle the case when the incoming audio has more bits per sample than the configured value
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (audio_stream_info.channels == 1) {
|
|
||||||
return i2s_set_clk(this->parent_->get_port(), this->sample_rate_, this->bits_per_sample_, I2S_CHANNEL_MONO);
|
|
||||||
} else if (audio_stream_info.channels == 2) {
|
|
||||||
return i2s_set_clk(this->parent_->get_port(), this->sample_rate_, this->bits_per_sample_, I2S_CHANNEL_STEREO);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ESP_ERR_INVALID_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2SAudioSpeaker::delete_task_(size_t buffer_size) {
|
void I2SAudioSpeaker::delete_task_(size_t buffer_size) {
|
||||||
this->audio_ring_buffer_.reset(); // Releases onwership of the shared_ptr
|
this->audio_ring_buffer_.reset(); // Releases onwership of the shared_ptr
|
||||||
|
|
||||||
|
@ -91,24 +91,15 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp
|
|||||||
esp_err_t allocate_buffers_(size_t data_buffer_size, size_t ring_buffer_size);
|
esp_err_t allocate_buffers_(size_t data_buffer_size, size_t ring_buffer_size);
|
||||||
|
|
||||||
/// @brief Starts the ESP32 I2S driver.
|
/// @brief Starts the ESP32 I2S driver.
|
||||||
/// Attempts to lock the I2S port, starts the I2S driver, and sets the data out pin. If it fails, it will unlock
|
/// Attempts to lock the I2S port, starts the I2S driver using the passed in stream information, and sets the data out
|
||||||
/// the I2S port and uninstall the driver, if necessary.
|
/// pin. If it fails, it will unlock the I2S port and uninstall the driver, if necessary.
|
||||||
/// @return ESP_ERR_INVALID_STATE if the I2S port is already locked.
|
/// @param audio_stream_info Stream information for the I2S driver.
|
||||||
/// ESP_ERR_INVALID_ARG if installing the driver or setting the data out pin fails due to a parameter error.
|
/// @return ESP_ERR_NOT_ALLOWED if the I2S port can't play the incoming audio stream.
|
||||||
|
/// ESP_ERR_INVALID_STATE if the I2S port is already locked.
|
||||||
|
/// ESP_ERR_INVALID_ARG if nstalling the driver or setting the data outpin fails due to a parameter error.
|
||||||
/// ESP_ERR_NO_MEM if the driver fails to install due to a memory allocation error.
|
/// ESP_ERR_NO_MEM if the driver fails to install due to a memory allocation error.
|
||||||
/// ESP_FAIL if setting the data out pin fails due to an IO error
|
/// ESP_FAIL if setting the data out pin fails due to an IO error ESP_OK if successful
|
||||||
/// ESP_OK if successful
|
esp_err_t start_i2s_driver_(audio::AudioStreamInfo &audio_stream_info);
|
||||||
esp_err_t start_i2s_driver_();
|
|
||||||
|
|
||||||
/// @brief Adjusts the I2S driver configuration to match the incoming audio stream.
|
|
||||||
/// Modifies I2S driver's sample rate, bits per sample, and number of channel settings. If the I2S is in secondary
|
|
||||||
/// mode, it only modifies the number of channels.
|
|
||||||
/// @param audio_stream_info Describes the incoming audio stream
|
|
||||||
/// @return ESP_ERR_INVALID_ARG if there is a parameter error, if there is more than 2 channels in the stream, or if
|
|
||||||
/// the audio settings are incompatible with the configuration.
|
|
||||||
/// ESP_ERR_NO_MEM if the driver fails to reconfigure due to a memory allocation error.
|
|
||||||
/// ESP_OK if successful.
|
|
||||||
esp_err_t reconfigure_i2s_stream_info_(audio::AudioStreamInfo &audio_stream_info);
|
|
||||||
|
|
||||||
/// @brief Deletes the speaker's task.
|
/// @brief Deletes the speaker's task.
|
||||||
/// Deallocates the data_buffer_ and audio_ring_buffer_, if necessary, and deletes the task. Should only be called by
|
/// Deallocates the data_buffer_ and audio_ring_buffer_, if necessary, and deletes the task. Should only be called by
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from esphome import core, pins
|
from esphome import core, pins
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.components import display, font, spi
|
from esphome.components import display, spi
|
||||||
from esphome.components.display import validate_rotation
|
from esphome.components.display import validate_rotation
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
@ -147,7 +147,6 @@ def _validate(config):
|
|||||||
|
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.All(
|
||||||
font.validate_pillow_installed,
|
|
||||||
display.FULL_DISPLAY_SCHEMA.extend(
|
display.FULL_DISPLAY_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(ILI9XXXDisplay),
|
cv.GenerateID(): cv.declare_id(ILI9XXXDisplay),
|
||||||
|
@ -10,7 +10,6 @@ import puremagic
|
|||||||
|
|
||||||
from esphome import core, external_files
|
from esphome import core, external_files
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.components import font
|
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_DITHER,
|
CONF_DITHER,
|
||||||
@ -233,7 +232,7 @@ IMAGE_SCHEMA = cv.Schema(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, IMAGE_SCHEMA)
|
CONFIG_SCHEMA = IMAGE_SCHEMA
|
||||||
|
|
||||||
|
|
||||||
def load_svg_image(file: bytes, resize: tuple[int, int]):
|
def load_svg_image(file: bytes, resize: tuple[int, int]):
|
||||||
|
@ -38,7 +38,7 @@ def literal(arg):
|
|||||||
def call_lambda(lamb: LambdaExpression):
|
def call_lambda(lamb: LambdaExpression):
|
||||||
expr = lamb.content.strip()
|
expr = lamb.content.strip()
|
||||||
if expr.startswith("return") and expr.endswith(";"):
|
if expr.startswith("return") and expr.endswith(";"):
|
||||||
return expr[7:][:-1]
|
return expr[6:][:-1].strip()
|
||||||
return f"{lamb}()"
|
return f"{lamb}()"
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,6 +56,9 @@ static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BIT
|
|||||||
inline void lv_img_set_src(lv_obj_t *obj, esphome::image::Image *image) {
|
inline void lv_img_set_src(lv_obj_t *obj, esphome::image::Image *image) {
|
||||||
lv_img_set_src(obj, image->get_lv_img_dsc());
|
lv_img_set_src(obj, image->get_lv_img_dsc());
|
||||||
}
|
}
|
||||||
|
inline void lv_disp_set_bg_image(lv_disp_t *disp, esphome::image::Image *image) {
|
||||||
|
lv_disp_set_bg_image(disp, image->get_lv_img_dsc());
|
||||||
|
}
|
||||||
#endif // USE_LVGL_IMAGE
|
#endif // USE_LVGL_IMAGE
|
||||||
#ifdef USE_LVGL_ANIMIMG
|
#ifdef USE_LVGL_ANIMIMG
|
||||||
inline void lv_animimg_set_src(lv_obj_t *img, std::vector<image::Image *> images) {
|
inline void lv_animimg_set_src(lv_obj_t *img, std::vector<image::Image *> images) {
|
||||||
|
@ -35,6 +35,11 @@ LINE_SCHEMA = {
|
|||||||
cv.GenerateID(CONF_POINT_LIST_ID): cv.declare_id(lv_point_t),
|
cv.GenerateID(CONF_POINT_LIST_ID): cv.declare_id(lv_point_t),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LINE_MODIFY_SCHEMA = {
|
||||||
|
cv.Optional(CONF_POINTS): cv_point_list,
|
||||||
|
cv.GenerateID(CONF_POINT_LIST_ID): cv.declare_id(lv_point_t),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class LineType(WidgetType):
|
class LineType(WidgetType):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -43,6 +48,7 @@ class LineType(WidgetType):
|
|||||||
LvType("lv_line_t"),
|
LvType("lv_line_t"),
|
||||||
(CONF_MAIN,),
|
(CONF_MAIN,),
|
||||||
LINE_SCHEMA,
|
LINE_SCHEMA,
|
||||||
|
modify_schema=LINE_MODIFY_SCHEMA,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def to_code(self, w: Widget, config):
|
async def to_code(self, w: Widget, config):
|
||||||
|
@ -29,7 +29,7 @@ from ..lvcode import (
|
|||||||
)
|
)
|
||||||
from ..schemas import STYLE_SCHEMA, STYLED_TEXT_SCHEMA, container_schema, part_schema
|
from ..schemas import STYLE_SCHEMA, STYLED_TEXT_SCHEMA, container_schema, part_schema
|
||||||
from ..types import LV_EVENT, char_ptr, lv_obj_t
|
from ..types import LV_EVENT, char_ptr, lv_obj_t
|
||||||
from . import Widget, set_obj_properties
|
from . import Widget, add_widgets, set_obj_properties
|
||||||
from .button import button_spec
|
from .button import button_spec
|
||||||
from .buttonmatrix import (
|
from .buttonmatrix import (
|
||||||
BUTTONMATRIX_BUTTON_SCHEMA,
|
BUTTONMATRIX_BUTTON_SCHEMA,
|
||||||
@ -119,6 +119,7 @@ async def msgbox_to_code(top_layer, conf):
|
|||||||
button_style = {CONF_ITEMS: button_style}
|
button_style = {CONF_ITEMS: button_style}
|
||||||
await set_obj_properties(buttonmatrix_widget, button_style)
|
await set_obj_properties(buttonmatrix_widget, button_style)
|
||||||
await set_obj_properties(msgbox_widget, conf)
|
await set_obj_properties(msgbox_widget, conf)
|
||||||
|
await add_widgets(msgbox_widget, conf)
|
||||||
async with LambdaContext(EVENT_ARG, where=messagebox_id) as close_action:
|
async with LambdaContext(EVENT_ARG, where=messagebox_id) as close_action:
|
||||||
outer_widget.add_flag("LV_OBJ_FLAG_HIDDEN")
|
outer_widget.add_flag("LV_OBJ_FLAG_HIDDEN")
|
||||||
if close_button:
|
if close_button:
|
||||||
|
@ -152,11 +152,11 @@ void ModbusController::on_modbus_read_registers(uint8_t function_code, uint16_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
SensorSet ModbusController::find_sensors_(ModbusRegisterType register_type, uint16_t start_address) const {
|
SensorSet ModbusController::find_sensors_(ModbusRegisterType register_type, uint16_t start_address) const {
|
||||||
auto reg_it = find_if(begin(register_ranges_), end(register_ranges_), [=](RegisterRange const &r) {
|
auto reg_it = std::find_if(
|
||||||
return (r.start_address == start_address && r.register_type == register_type);
|
std::begin(this->register_ranges_), std::end(this->register_ranges_),
|
||||||
});
|
[=](RegisterRange const &r) { return (r.start_address == start_address && r.register_type == register_type); });
|
||||||
|
|
||||||
if (reg_it == register_ranges_.end()) {
|
if (reg_it == this->register_ranges_.end()) {
|
||||||
ESP_LOGE(TAG, "No matching range for sensor found - start_address : 0x%X", start_address);
|
ESP_LOGE(TAG, "No matching range for sensor found - start_address : 0x%X", start_address);
|
||||||
} else {
|
} else {
|
||||||
return reg_it->sensors;
|
return reg_it->sensors;
|
||||||
@ -240,18 +240,18 @@ void ModbusController::update() {
|
|||||||
|
|
||||||
// walk through the sensors and determine the register ranges to read
|
// walk through the sensors and determine the register ranges to read
|
||||||
size_t ModbusController::create_register_ranges_() {
|
size_t ModbusController::create_register_ranges_() {
|
||||||
register_ranges_.clear();
|
this->register_ranges_.clear();
|
||||||
if (this->parent_->role == modbus::ModbusRole::CLIENT && sensorset_.empty()) {
|
if (this->parent_->role == modbus::ModbusRole::CLIENT && this->sensorset_.empty()) {
|
||||||
ESP_LOGW(TAG, "No sensors registered");
|
ESP_LOGW(TAG, "No sensors registered");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterator is sorted see SensorItemsComparator for details
|
// iterator is sorted see SensorItemsComparator for details
|
||||||
auto ix = sensorset_.begin();
|
auto ix = this->sensorset_.begin();
|
||||||
RegisterRange r = {};
|
RegisterRange r = {};
|
||||||
uint8_t buffer_offset = 0;
|
uint8_t buffer_offset = 0;
|
||||||
SensorItem *prev = nullptr;
|
SensorItem *prev = nullptr;
|
||||||
while (ix != sensorset_.end()) {
|
while (ix != this->sensorset_.end()) {
|
||||||
SensorItem *curr = *ix;
|
SensorItem *curr = *ix;
|
||||||
|
|
||||||
ESP_LOGV(TAG, "Register: 0x%X %d %d %d offset=%u skip=%u addr=%p", curr->start_address, curr->register_count,
|
ESP_LOGV(TAG, "Register: 0x%X %d %d %d offset=%u skip=%u addr=%p", curr->start_address, curr->register_count,
|
||||||
@ -278,12 +278,12 @@ size_t ModbusController::create_register_ranges_() {
|
|||||||
// this register can re-use the data from the previous register
|
// this register can re-use the data from the previous register
|
||||||
|
|
||||||
// remove this sensore because start_address is changed (sort-order)
|
// remove this sensore because start_address is changed (sort-order)
|
||||||
ix = sensorset_.erase(ix);
|
ix = this->sensorset_.erase(ix);
|
||||||
|
|
||||||
curr->start_address = r.start_address;
|
curr->start_address = r.start_address;
|
||||||
curr->offset += prev->offset;
|
curr->offset += prev->offset;
|
||||||
|
|
||||||
sensorset_.insert(curr);
|
this->sensorset_.insert(curr);
|
||||||
// move iterator backwards because it will be incremented later
|
// move iterator backwards because it will be incremented later
|
||||||
ix--;
|
ix--;
|
||||||
|
|
||||||
@ -293,14 +293,14 @@ size_t ModbusController::create_register_ranges_() {
|
|||||||
// this register can extend the current range
|
// this register can extend the current range
|
||||||
|
|
||||||
// remove this sensore because start_address is changed (sort-order)
|
// remove this sensore because start_address is changed (sort-order)
|
||||||
ix = sensorset_.erase(ix);
|
ix = this->sensorset_.erase(ix);
|
||||||
|
|
||||||
curr->start_address = r.start_address;
|
curr->start_address = r.start_address;
|
||||||
curr->offset += buffer_offset;
|
curr->offset += buffer_offset;
|
||||||
buffer_offset += curr->get_register_size();
|
buffer_offset += curr->get_register_size();
|
||||||
r.register_count += curr->register_count;
|
r.register_count += curr->register_count;
|
||||||
|
|
||||||
sensorset_.insert(curr);
|
this->sensorset_.insert(curr);
|
||||||
// move iterator backwards because it will be incremented later
|
// move iterator backwards because it will be incremented later
|
||||||
ix--;
|
ix--;
|
||||||
|
|
||||||
@ -327,7 +327,7 @@ size_t ModbusController::create_register_ranges_() {
|
|||||||
ix++;
|
ix++;
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGV(TAG, "Add range 0x%X %d skip:%d", r.start_address, r.register_count, r.skip_updates);
|
ESP_LOGV(TAG, "Add range 0x%X %d skip:%d", r.start_address, r.register_count, r.skip_updates);
|
||||||
register_ranges_.push_back(r);
|
this->register_ranges_.push_back(r);
|
||||||
r = {};
|
r = {};
|
||||||
buffer_offset = 0;
|
buffer_offset = 0;
|
||||||
// do not increment the iterator here because the current sensor has to be re-evaluated
|
// do not increment the iterator here because the current sensor has to be re-evaluated
|
||||||
@ -339,10 +339,10 @@ size_t ModbusController::create_register_ranges_() {
|
|||||||
if (r.register_count > 0) {
|
if (r.register_count > 0) {
|
||||||
// Add the last range
|
// Add the last range
|
||||||
ESP_LOGV(TAG, "Add last range 0x%X %d skip:%d", r.start_address, r.register_count, r.skip_updates);
|
ESP_LOGV(TAG, "Add last range 0x%X %d skip:%d", r.start_address, r.register_count, r.skip_updates);
|
||||||
register_ranges_.push_back(r);
|
this->register_ranges_.push_back(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
return register_ranges_.size();
|
return this->register_ranges_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModbusController::dump_config() {
|
void ModbusController::dump_config() {
|
||||||
@ -352,18 +352,18 @@ void ModbusController::dump_config() {
|
|||||||
ESP_LOGCONFIG(TAG, " Offline Skip Updates: %d", this->offline_skip_updates_);
|
ESP_LOGCONFIG(TAG, " Offline Skip Updates: %d", this->offline_skip_updates_);
|
||||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||||
ESP_LOGCONFIG(TAG, "sensormap");
|
ESP_LOGCONFIG(TAG, "sensormap");
|
||||||
for (auto &it : sensorset_) {
|
for (auto &it : this->sensorset_) {
|
||||||
ESP_LOGCONFIG(TAG, " Sensor type=%zu start=0x%X offset=0x%X count=%d size=%d",
|
ESP_LOGCONFIG(TAG, " Sensor type=%zu start=0x%X offset=0x%X count=%d size=%d",
|
||||||
static_cast<uint8_t>(it->register_type), it->start_address, it->offset, it->register_count,
|
static_cast<uint8_t>(it->register_type), it->start_address, it->offset, it->register_count,
|
||||||
it->get_register_size());
|
it->get_register_size());
|
||||||
}
|
}
|
||||||
ESP_LOGCONFIG(TAG, "ranges");
|
ESP_LOGCONFIG(TAG, "ranges");
|
||||||
for (auto &it : register_ranges_) {
|
for (auto &it : this->register_ranges_) {
|
||||||
ESP_LOGCONFIG(TAG, " Range type=%zu start=0x%X count=%d skip_updates=%d", static_cast<uint8_t>(it.register_type),
|
ESP_LOGCONFIG(TAG, " Range type=%zu start=0x%X count=%d skip_updates=%d", static_cast<uint8_t>(it.register_type),
|
||||||
it.start_address, it.register_count, it.skip_updates);
|
it.start_address, it.register_count, it.skip_updates);
|
||||||
}
|
}
|
||||||
ESP_LOGCONFIG(TAG, "server registers");
|
ESP_LOGCONFIG(TAG, "server registers");
|
||||||
for (auto &r : server_registers_) {
|
for (auto &r : this->server_registers_) {
|
||||||
ESP_LOGCONFIG(TAG, " Address=0x%02X value_type=%zu register_count=%u", r->address,
|
ESP_LOGCONFIG(TAG, " Address=0x%02X value_type=%zu register_count=%u", r->address,
|
||||||
static_cast<uint8_t>(r->value_type), r->register_count);
|
static_cast<uint8_t>(r->value_type), r->register_count);
|
||||||
}
|
}
|
||||||
@ -372,15 +372,15 @@ void ModbusController::dump_config() {
|
|||||||
|
|
||||||
void ModbusController::loop() {
|
void ModbusController::loop() {
|
||||||
// Incoming data to process?
|
// Incoming data to process?
|
||||||
if (!incoming_queue_.empty()) {
|
if (!this->incoming_queue_.empty()) {
|
||||||
auto &message = incoming_queue_.front();
|
auto &message = this->incoming_queue_.front();
|
||||||
if (message != nullptr)
|
if (message != nullptr)
|
||||||
process_modbus_data_(message.get());
|
this->process_modbus_data_(message.get());
|
||||||
incoming_queue_.pop();
|
this->incoming_queue_.pop();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// all messages processed send pending commands
|
// all messages processed send pending commands
|
||||||
send_next_command_();
|
this->send_next_command_();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,7 +391,7 @@ void ModbusController::on_write_register_response(ModbusRegisterType register_ty
|
|||||||
|
|
||||||
void ModbusController::dump_sensors_() {
|
void ModbusController::dump_sensors_() {
|
||||||
ESP_LOGV(TAG, "sensors");
|
ESP_LOGV(TAG, "sensors");
|
||||||
for (auto &it : sensorset_) {
|
for (auto &it : this->sensorset_) {
|
||||||
ESP_LOGV(TAG, " Sensor start=0x%X count=%d size=%d offset=%d", it->start_address, it->register_count,
|
ESP_LOGV(TAG, " Sensor start=0x%X count=%d size=%d offset=%d", it->start_address, it->register_count,
|
||||||
it->get_register_size(), it->offset);
|
it->get_register_size(), it->offset);
|
||||||
}
|
}
|
||||||
|
@ -240,14 +240,14 @@ class SensorItem {
|
|||||||
}
|
}
|
||||||
// Override register size for modbus devices not using 1 register for one dword
|
// Override register size for modbus devices not using 1 register for one dword
|
||||||
void set_register_size(uint8_t register_size) { response_bytes = register_size; }
|
void set_register_size(uint8_t register_size) { response_bytes = register_size; }
|
||||||
ModbusRegisterType register_type;
|
ModbusRegisterType register_type{ModbusRegisterType::CUSTOM};
|
||||||
SensorValueType sensor_value_type;
|
SensorValueType sensor_value_type{SensorValueType::RAW};
|
||||||
uint16_t start_address;
|
uint16_t start_address{0};
|
||||||
uint32_t bitmask;
|
uint32_t bitmask{0};
|
||||||
uint8_t offset;
|
uint8_t offset{0};
|
||||||
uint8_t register_count;
|
uint8_t register_count{0};
|
||||||
uint8_t response_bytes{0};
|
uint8_t response_bytes{0};
|
||||||
uint16_t skip_updates;
|
uint16_t skip_updates{0};
|
||||||
std::vector<uint8_t> custom_data{};
|
std::vector<uint8_t> custom_data{};
|
||||||
bool force_new_range{false};
|
bool force_new_range{false};
|
||||||
};
|
};
|
||||||
@ -261,9 +261,9 @@ class ServerRegister {
|
|||||||
this->register_count = register_count;
|
this->register_count = register_count;
|
||||||
this->read_lambda = std::move(read_lambda);
|
this->read_lambda = std::move(read_lambda);
|
||||||
}
|
}
|
||||||
uint16_t address;
|
uint16_t address{0};
|
||||||
SensorValueType value_type;
|
SensorValueType value_type{SensorValueType::RAW};
|
||||||
uint8_t register_count;
|
uint8_t register_count{0};
|
||||||
std::function<float()> read_lambda;
|
std::function<float()> read_lambda;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -312,11 +312,11 @@ struct RegisterRange {
|
|||||||
class ModbusCommandItem {
|
class ModbusCommandItem {
|
||||||
public:
|
public:
|
||||||
static const size_t MAX_PAYLOAD_BYTES = 240;
|
static const size_t MAX_PAYLOAD_BYTES = 240;
|
||||||
ModbusController *modbusdevice;
|
ModbusController *modbusdevice{nullptr};
|
||||||
uint16_t register_address;
|
uint16_t register_address{0};
|
||||||
uint16_t register_count;
|
uint16_t register_count{0};
|
||||||
ModbusFunctionCode function_code;
|
ModbusFunctionCode function_code{ModbusFunctionCode::CUSTOM};
|
||||||
ModbusRegisterType register_type;
|
ModbusRegisterType register_type{ModbusRegisterType::CUSTOM};
|
||||||
std::function<void(ModbusRegisterType register_type, uint16_t start_address, const std::vector<uint8_t> &data)>
|
std::function<void(ModbusRegisterType register_type, uint16_t start_address, const std::vector<uint8_t> &data)>
|
||||||
on_data_func;
|
on_data_func;
|
||||||
std::vector<uint8_t> payload = {};
|
std::vector<uint8_t> payload = {};
|
||||||
@ -493,23 +493,23 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice {
|
|||||||
/// Collection of all sensors for this component
|
/// Collection of all sensors for this component
|
||||||
SensorSet sensorset_;
|
SensorSet sensorset_;
|
||||||
/// Collection of all server registers for this component
|
/// Collection of all server registers for this component
|
||||||
std::vector<ServerRegister *> server_registers_;
|
std::vector<ServerRegister *> server_registers_{};
|
||||||
/// Continuous range of modbus registers
|
/// Continuous range of modbus registers
|
||||||
std::vector<RegisterRange> register_ranges_;
|
std::vector<RegisterRange> register_ranges_{};
|
||||||
/// Hold the pending requests to be sent
|
/// Hold the pending requests to be sent
|
||||||
std::list<std::unique_ptr<ModbusCommandItem>> command_queue_;
|
std::list<std::unique_ptr<ModbusCommandItem>> command_queue_;
|
||||||
/// modbus response data waiting to get processed
|
/// modbus response data waiting to get processed
|
||||||
std::queue<std::unique_ptr<ModbusCommandItem>> incoming_queue_;
|
std::queue<std::unique_ptr<ModbusCommandItem>> incoming_queue_;
|
||||||
/// if duplicate commands can be sent
|
/// if duplicate commands can be sent
|
||||||
bool allow_duplicate_commands_;
|
bool allow_duplicate_commands_{false};
|
||||||
/// when was the last send operation
|
/// when was the last send operation
|
||||||
uint32_t last_command_timestamp_;
|
uint32_t last_command_timestamp_{0};
|
||||||
/// min time in ms between sending modbus commands
|
/// min time in ms between sending modbus commands
|
||||||
uint16_t command_throttle_;
|
uint16_t command_throttle_{0};
|
||||||
/// if module didn't respond the last command
|
/// if module didn't respond the last command
|
||||||
bool module_offline_;
|
bool module_offline_{false};
|
||||||
/// how many updates to skip if module is offline
|
/// how many updates to skip if module is offline
|
||||||
uint16_t offline_skip_updates_;
|
uint16_t offline_skip_updates_{0};
|
||||||
/// How many times we will retry a command if we get no response
|
/// How many times we will retry a command if we get no response
|
||||||
uint8_t max_cmd_retries_{4};
|
uint8_t max_cmd_retries_{4};
|
||||||
/// Command sent callback
|
/// Command sent callback
|
||||||
|
@ -8,7 +8,7 @@ namespace modbus_controller {
|
|||||||
static const char *const TAG = "modbus.number";
|
static const char *const TAG = "modbus.number";
|
||||||
|
|
||||||
void ModbusNumber::parse_and_publish(const std::vector<uint8_t> &data) {
|
void ModbusNumber::parse_and_publish(const std::vector<uint8_t> &data) {
|
||||||
float result = payload_to_float(data, *this) / multiply_by_;
|
float result = payload_to_float(data, *this) / this->multiply_by_;
|
||||||
|
|
||||||
// Is there a lambda registered
|
// Is there a lambda registered
|
||||||
// call it with the pre converted value and the raw data array
|
// call it with the pre converted value and the raw data array
|
||||||
@ -43,7 +43,7 @@ void ModbusNumber::control(float value) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
write_value = multiply_by_ * write_value;
|
write_value = this->multiply_by_ * write_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.empty()) {
|
if (!data.empty()) {
|
||||||
@ -63,21 +63,21 @@ void ModbusNumber::control(float value) {
|
|||||||
// Create and send the write command
|
// Create and send the write command
|
||||||
if (this->register_count == 1 && !this->use_write_multiple_) {
|
if (this->register_count == 1 && !this->use_write_multiple_) {
|
||||||
// since offset is in bytes and a register is 16 bits we get the start by adding offset/2
|
// since offset is in bytes and a register is 16 bits we get the start by adding offset/2
|
||||||
write_cmd =
|
write_cmd = ModbusCommandItem::create_write_single_command(this->parent_, this->start_address + this->offset / 2,
|
||||||
ModbusCommandItem::create_write_single_command(parent_, this->start_address + this->offset / 2, data[0]);
|
data[0]);
|
||||||
} else {
|
} else {
|
||||||
write_cmd = ModbusCommandItem::create_write_multiple_command(parent_, this->start_address + this->offset / 2,
|
write_cmd = ModbusCommandItem::create_write_multiple_command(
|
||||||
this->register_count, data);
|
this->parent_, this->start_address + this->offset / 2, this->register_count, data);
|
||||||
}
|
}
|
||||||
// publish new value
|
// publish new value
|
||||||
write_cmd.on_data_func = [this, write_cmd, value](ModbusRegisterType register_type, uint16_t start_address,
|
write_cmd.on_data_func = [this, write_cmd, value](ModbusRegisterType register_type, uint16_t start_address,
|
||||||
const std::vector<uint8_t> &data) {
|
const std::vector<uint8_t> &data) {
|
||||||
// gets called when the write command is ack'd from the device
|
// gets called when the write command is ack'd from the device
|
||||||
parent_->on_write_register_response(write_cmd.register_type, start_address, data);
|
this->parent_->on_write_register_response(write_cmd.register_type, start_address, data);
|
||||||
this->publish_state(value);
|
this->publish_state(value);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
parent_->queue_command(write_cmd);
|
this->parent_->queue_command(write_cmd);
|
||||||
this->publish_state(value);
|
this->publish_state(value);
|
||||||
}
|
}
|
||||||
void ModbusNumber::dump_config() { LOG_NUMBER(TAG, "Modbus Number", this); }
|
void ModbusNumber::dump_config() { LOG_NUMBER(TAG, "Modbus Number", this); }
|
||||||
|
@ -29,7 +29,7 @@ class ModbusNumber : public number::Number, public Component, public SensorItem
|
|||||||
void parse_and_publish(const std::vector<uint8_t> &data) override;
|
void parse_and_publish(const std::vector<uint8_t> &data) override;
|
||||||
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
||||||
void set_parent(ModbusController *parent) { this->parent_ = parent; }
|
void set_parent(ModbusController *parent) { this->parent_ = parent; }
|
||||||
void set_write_multiply(float factor) { multiply_by_ = factor; }
|
void set_write_multiply(float factor) { this->multiply_by_ = factor; }
|
||||||
|
|
||||||
using transform_func_t = std::function<optional<float>(ModbusNumber *, float, const std::vector<uint8_t> &)>;
|
using transform_func_t = std::function<optional<float>(ModbusNumber *, float, const std::vector<uint8_t> &)>;
|
||||||
using write_transform_func_t = std::function<optional<float>(ModbusNumber *, float, std::vector<uint16_t> &)>;
|
using write_transform_func_t = std::function<optional<float>(ModbusNumber *, float, std::vector<uint16_t> &)>;
|
||||||
@ -39,9 +39,9 @@ class ModbusNumber : public number::Number, public Component, public SensorItem
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
void control(float value) override;
|
void control(float value) override;
|
||||||
optional<transform_func_t> transform_func_;
|
optional<transform_func_t> transform_func_{nullopt};
|
||||||
optional<write_transform_func_t> write_transform_func_;
|
optional<write_transform_func_t> write_transform_func_{nullopt};
|
||||||
ModbusController *parent_;
|
ModbusController *parent_{nullptr};
|
||||||
float multiply_by_{1.0};
|
float multiply_by_{1.0};
|
||||||
bool use_write_multiple_{false};
|
bool use_write_multiple_{false};
|
||||||
};
|
};
|
||||||
|
@ -27,7 +27,7 @@ void ModbusFloatOutput::write_state(float value) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
value = multiply_by_ * value;
|
value = this->multiply_by_ * value;
|
||||||
}
|
}
|
||||||
// lambda didn't set payload
|
// lambda didn't set payload
|
||||||
if (data.empty()) {
|
if (data.empty()) {
|
||||||
@ -40,12 +40,13 @@ void ModbusFloatOutput::write_state(float value) {
|
|||||||
// Create and send the write command
|
// Create and send the write command
|
||||||
ModbusCommandItem write_cmd;
|
ModbusCommandItem write_cmd;
|
||||||
if (this->register_count == 1 && !this->use_write_multiple_) {
|
if (this->register_count == 1 && !this->use_write_multiple_) {
|
||||||
write_cmd = ModbusCommandItem::create_write_single_command(parent_, this->start_address + this->offset, data[0]);
|
write_cmd =
|
||||||
|
ModbusCommandItem::create_write_single_command(this->parent_, this->start_address + this->offset, data[0]);
|
||||||
} else {
|
} else {
|
||||||
write_cmd = ModbusCommandItem::create_write_multiple_command(parent_, this->start_address + this->offset,
|
write_cmd = ModbusCommandItem::create_write_multiple_command(this->parent_, this->start_address + this->offset,
|
||||||
this->register_count, data);
|
this->register_count, data);
|
||||||
}
|
}
|
||||||
parent_->queue_command(write_cmd);
|
this->parent_->queue_command(write_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModbusFloatOutput::dump_config() {
|
void ModbusFloatOutput::dump_config() {
|
||||||
@ -90,9 +91,9 @@ void ModbusBinaryOutput::write_state(bool state) {
|
|||||||
// offset for coil and discrete inputs is the coil/register number not bytes
|
// offset for coil and discrete inputs is the coil/register number not bytes
|
||||||
if (this->use_write_multiple_) {
|
if (this->use_write_multiple_) {
|
||||||
std::vector<bool> states{state};
|
std::vector<bool> states{state};
|
||||||
cmd = ModbusCommandItem::create_write_multiple_coils(parent_, this->start_address + this->offset, states);
|
cmd = ModbusCommandItem::create_write_multiple_coils(this->parent_, this->start_address + this->offset, states);
|
||||||
} else {
|
} else {
|
||||||
cmd = ModbusCommandItem::create_write_single_coil(parent_, this->start_address + this->offset, state);
|
cmd = ModbusCommandItem::create_write_single_coil(this->parent_, this->start_address + this->offset, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->parent_->queue_command(cmd);
|
this->parent_->queue_command(cmd);
|
||||||
|
@ -25,7 +25,7 @@ class ModbusFloatOutput : public output::FloatOutput, public Component, public S
|
|||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|
||||||
void set_parent(ModbusController *parent) { this->parent_ = parent; }
|
void set_parent(ModbusController *parent) { this->parent_ = parent; }
|
||||||
void set_write_multiply(float factor) { multiply_by_ = factor; }
|
void set_write_multiply(float factor) { this->multiply_by_ = factor; }
|
||||||
// Do nothing
|
// Do nothing
|
||||||
void parse_and_publish(const std::vector<uint8_t> &data) override{};
|
void parse_and_publish(const std::vector<uint8_t> &data) override{};
|
||||||
|
|
||||||
@ -37,9 +37,9 @@ class ModbusFloatOutput : public output::FloatOutput, public Component, public S
|
|||||||
void write_state(float value) override;
|
void write_state(float value) override;
|
||||||
optional<write_transform_func_t> write_transform_func_{nullopt};
|
optional<write_transform_func_t> write_transform_func_{nullopt};
|
||||||
|
|
||||||
ModbusController *parent_;
|
ModbusController *parent_{nullptr};
|
||||||
float multiply_by_{1.0};
|
float multiply_by_{1.0};
|
||||||
bool use_write_multiple_;
|
bool use_write_multiple_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModbusBinaryOutput : public output::BinaryOutput, public Component, public SensorItem {
|
class ModbusBinaryOutput : public output::BinaryOutput, public Component, public SensorItem {
|
||||||
@ -68,8 +68,8 @@ class ModbusBinaryOutput : public output::BinaryOutput, public Component, public
|
|||||||
void write_state(bool state) override;
|
void write_state(bool state) override;
|
||||||
optional<write_transform_func_t> write_transform_func_{nullopt};
|
optional<write_transform_func_t> write_transform_func_{nullopt};
|
||||||
|
|
||||||
ModbusController *parent_;
|
ModbusController *parent_{nullptr};
|
||||||
bool use_write_multiple_;
|
bool use_write_multiple_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace modbus_controller
|
} // namespace modbus_controller
|
||||||
|
@ -74,12 +74,13 @@ void ModbusSelect::control(const std::string &value) {
|
|||||||
const uint16_t write_address = this->start_address + this->offset / 2;
|
const uint16_t write_address = this->start_address + this->offset / 2;
|
||||||
ModbusCommandItem write_cmd;
|
ModbusCommandItem write_cmd;
|
||||||
if ((this->register_count == 1) && (!this->use_write_multiple_)) {
|
if ((this->register_count == 1) && (!this->use_write_multiple_)) {
|
||||||
write_cmd = ModbusCommandItem::create_write_single_command(parent_, write_address, data[0]);
|
write_cmd = ModbusCommandItem::create_write_single_command(this->parent_, write_address, data[0]);
|
||||||
} else {
|
} else {
|
||||||
write_cmd = ModbusCommandItem::create_write_multiple_command(parent_, write_address, this->register_count, data);
|
write_cmd =
|
||||||
|
ModbusCommandItem::create_write_multiple_command(this->parent_, write_address, this->register_count, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
parent_->queue_command(write_cmd);
|
this->parent_->queue_command(write_cmd);
|
||||||
|
|
||||||
if (this->optimistic_)
|
if (this->optimistic_)
|
||||||
this->publish_state(value);
|
this->publish_state(value);
|
||||||
|
@ -42,12 +42,12 @@ class ModbusSelect : public Component, public select::Select, public SensorItem
|
|||||||
void control(const std::string &value) override;
|
void control(const std::string &value) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<int64_t> mapping_;
|
std::vector<int64_t> mapping_{};
|
||||||
ModbusController *parent_;
|
ModbusController *parent_{nullptr};
|
||||||
bool use_write_multiple_{false};
|
bool use_write_multiple_{false};
|
||||||
bool optimistic_{false};
|
bool optimistic_{false};
|
||||||
optional<transform_func_t> transform_func_;
|
optional<transform_func_t> transform_func_{nullopt};
|
||||||
optional<write_transform_func_t> write_transform_func_;
|
optional<write_transform_func_t> write_transform_func_{nullopt};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace modbus_controller
|
} // namespace modbus_controller
|
||||||
|
@ -80,24 +80,24 @@ void ModbusSwitch::write_state(bool state) {
|
|||||||
// offset for coil and discrete inputs is the coil/register number not bytes
|
// offset for coil and discrete inputs is the coil/register number not bytes
|
||||||
if (this->use_write_multiple_) {
|
if (this->use_write_multiple_) {
|
||||||
std::vector<bool> states{state};
|
std::vector<bool> states{state};
|
||||||
cmd = ModbusCommandItem::create_write_multiple_coils(parent_, this->start_address + this->offset, states);
|
cmd = ModbusCommandItem::create_write_multiple_coils(this->parent_, this->start_address + this->offset, states);
|
||||||
} else {
|
} else {
|
||||||
cmd = ModbusCommandItem::create_write_single_coil(parent_, this->start_address + this->offset, state);
|
cmd = ModbusCommandItem::create_write_single_coil(this->parent_, this->start_address + this->offset, state);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// since offset is in bytes and a register is 16 bits we get the start by adding offset/2
|
// since offset is in bytes and a register is 16 bits we get the start by adding offset/2
|
||||||
if (this->use_write_multiple_) {
|
if (this->use_write_multiple_) {
|
||||||
std::vector<uint16_t> bool_states(1, state ? (0xFFFF & this->bitmask) : 0);
|
std::vector<uint16_t> bool_states(1, state ? (0xFFFF & this->bitmask) : 0);
|
||||||
cmd = ModbusCommandItem::create_write_multiple_command(parent_, this->start_address + this->offset / 2, 1,
|
cmd = ModbusCommandItem::create_write_multiple_command(this->parent_, this->start_address + this->offset / 2, 1,
|
||||||
bool_states);
|
bool_states);
|
||||||
} else {
|
} else {
|
||||||
cmd = ModbusCommandItem::create_write_single_command(parent_, this->start_address + this->offset / 2,
|
cmd = ModbusCommandItem::create_write_single_command(this->parent_, this->start_address + this->offset / 2,
|
||||||
state ? 0xFFFF & this->bitmask : 0u);
|
state ? 0xFFFF & this->bitmask : 0u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->parent_->queue_command(cmd);
|
this->parent_->queue_command(cmd);
|
||||||
publish_state(state);
|
this->publish_state(state);
|
||||||
}
|
}
|
||||||
// ModbusSwitch end
|
// ModbusSwitch end
|
||||||
} // namespace modbus_controller
|
} // namespace modbus_controller
|
||||||
|
@ -40,8 +40,8 @@ class ModbusSwitch : public Component, public switch_::Switch, public SensorItem
|
|||||||
void set_use_write_mutiple(bool use_write_multiple) { this->use_write_multiple_ = use_write_multiple; }
|
void set_use_write_mutiple(bool use_write_multiple) { this->use_write_multiple_ = use_write_multiple; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ModbusController *parent_;
|
ModbusController *parent_{nullptr};
|
||||||
bool use_write_multiple_;
|
bool use_write_multiple_{false};
|
||||||
optional<transform_func_t> publish_transform_func_{nullopt};
|
optional<transform_func_t> publish_transform_func_{nullopt};
|
||||||
optional<write_transform_func_t> write_transform_func_{nullopt};
|
optional<write_transform_func_t> write_transform_func_{nullopt};
|
||||||
};
|
};
|
||||||
|
@ -49,6 +49,7 @@ from esphome.const import (
|
|||||||
CONF_USE_ABBREVIATIONS,
|
CONF_USE_ABBREVIATIONS,
|
||||||
CONF_USERNAME,
|
CONF_USERNAME,
|
||||||
CONF_WILL_MESSAGE,
|
CONF_WILL_MESSAGE,
|
||||||
|
CONF_PUBLISH_NAN_AS_NONE,
|
||||||
PLATFORM_BK72XX,
|
PLATFORM_BK72XX,
|
||||||
PLATFORM_ESP32,
|
PLATFORM_ESP32,
|
||||||
PLATFORM_ESP8266,
|
PLATFORM_ESP8266,
|
||||||
@ -296,6 +297,7 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
cv.Optional(CONF_QOS, default=0): cv.mqtt_qos,
|
cv.Optional(CONF_QOS, default=0): cv.mqtt_qos,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
cv.Optional(CONF_PUBLISH_NAN_AS_NONE, default=False): cv.boolean,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
validate_config,
|
validate_config,
|
||||||
@ -449,6 +451,8 @@ async def to_code(config):
|
|||||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||||
await automation.build_automation(trigger, [], conf)
|
await automation.build_automation(trigger, [], conf)
|
||||||
|
|
||||||
|
cg.add(var.set_publish_nan_as_none(config[CONF_PUBLISH_NAN_AS_NONE]))
|
||||||
|
|
||||||
|
|
||||||
MQTT_PUBLISH_ACTION_SCHEMA = cv.Schema(
|
MQTT_PUBLISH_ACTION_SCHEMA = cv.Schema(
|
||||||
{
|
{
|
||||||
|
@ -608,6 +608,10 @@ void MQTTClientComponent::set_log_message_template(MQTTMessage &&message) { this
|
|||||||
const MQTTDiscoveryInfo &MQTTClientComponent::get_discovery_info() const { return this->discovery_info_; }
|
const MQTTDiscoveryInfo &MQTTClientComponent::get_discovery_info() const { return this->discovery_info_; }
|
||||||
void MQTTClientComponent::set_topic_prefix(const std::string &topic_prefix) { this->topic_prefix_ = topic_prefix; }
|
void MQTTClientComponent::set_topic_prefix(const std::string &topic_prefix) { this->topic_prefix_ = topic_prefix; }
|
||||||
const std::string &MQTTClientComponent::get_topic_prefix() const { return this->topic_prefix_; }
|
const std::string &MQTTClientComponent::get_topic_prefix() const { return this->topic_prefix_; }
|
||||||
|
void MQTTClientComponent::set_publish_nan_as_none(bool publish_nan_as_none) {
|
||||||
|
this->publish_nan_as_none_ = publish_nan_as_none;
|
||||||
|
}
|
||||||
|
bool MQTTClientComponent::is_publish_nan_as_none() const { return this->publish_nan_as_none_; }
|
||||||
void MQTTClientComponent::disable_birth_message() {
|
void MQTTClientComponent::disable_birth_message() {
|
||||||
this->birth_message_.topic = "";
|
this->birth_message_.topic = "";
|
||||||
this->recalculate_availability_();
|
this->recalculate_availability_();
|
||||||
|
@ -263,6 +263,10 @@ class MQTTClientComponent : public Component {
|
|||||||
void set_on_connect(mqtt_on_connect_callback_t &&callback);
|
void set_on_connect(mqtt_on_connect_callback_t &&callback);
|
||||||
void set_on_disconnect(mqtt_on_disconnect_callback_t &&callback);
|
void set_on_disconnect(mqtt_on_disconnect_callback_t &&callback);
|
||||||
|
|
||||||
|
// Publish None state instead of NaN for Home Assistant
|
||||||
|
void set_publish_nan_as_none(bool publish_nan_as_none);
|
||||||
|
bool is_publish_nan_as_none() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void send_device_info_();
|
void send_device_info_();
|
||||||
|
|
||||||
@ -328,6 +332,8 @@ class MQTTClientComponent : public Component {
|
|||||||
uint32_t connect_begin_;
|
uint32_t connect_begin_;
|
||||||
uint32_t last_connected_{0};
|
uint32_t last_connected_{0};
|
||||||
optional<MQTTClientDisconnectReason> disconnect_reason_{};
|
optional<MQTTClientDisconnectReason> disconnect_reason_{};
|
||||||
|
|
||||||
|
bool publish_nan_as_none_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MQTTClientComponent *global_mqtt_client; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
extern MQTTClientComponent *global_mqtt_client; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
@ -69,6 +69,8 @@ bool MQTTSensorComponent::send_initial_state() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool MQTTSensorComponent::publish_state(float value) {
|
bool MQTTSensorComponent::publish_state(float value) {
|
||||||
|
if (mqtt::global_mqtt_client->is_publish_nan_as_none() && std::isnan(value))
|
||||||
|
return this->publish(this->get_state_topic_(), "None");
|
||||||
int8_t accuracy = this->sensor_->get_accuracy_decimals();
|
int8_t accuracy = this->sensor_->get_accuracy_decimals();
|
||||||
return this->publish(this->get_state_topic_(), value_accuracy_to_string(value, accuracy));
|
return this->publish(this->get_state_topic_(), value_accuracy_to_string(value, accuracy));
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,6 @@
|
|||||||
#include "lwip/apps/sntp.h"
|
#include "lwip/apps/sntp.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Yes, the server names are leaked, but that's fine.
|
|
||||||
#ifdef CLANG_TIDY
|
|
||||||
#define strdup(x) (const_cast<char *>(x))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace sntp {
|
namespace sntp {
|
||||||
|
|
||||||
@ -26,30 +21,29 @@ void SNTPComponent::setup() {
|
|||||||
esp_sntp_stop();
|
esp_sntp_stop();
|
||||||
}
|
}
|
||||||
esp_sntp_setoperatingmode(ESP_SNTP_OPMODE_POLL);
|
esp_sntp_setoperatingmode(ESP_SNTP_OPMODE_POLL);
|
||||||
|
size_t i = 0;
|
||||||
|
for (auto &server : this->servers_) {
|
||||||
|
esp_sntp_setservername(i++, server.c_str());
|
||||||
|
}
|
||||||
|
esp_sntp_set_sync_interval(this->get_update_interval());
|
||||||
|
esp_sntp_init();
|
||||||
#else
|
#else
|
||||||
sntp_stop();
|
sntp_stop();
|
||||||
sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
||||||
#endif
|
|
||||||
|
|
||||||
sntp_setservername(0, strdup(this->server_1_.c_str()));
|
size_t i = 0;
|
||||||
if (!this->server_2_.empty()) {
|
for (auto &server : this->servers_) {
|
||||||
sntp_setservername(1, strdup(this->server_2_.c_str()));
|
sntp_setservername(i++, server.c_str());
|
||||||
}
|
}
|
||||||
if (!this->server_3_.empty()) {
|
|
||||||
sntp_setservername(2, strdup(this->server_3_.c_str()));
|
|
||||||
}
|
|
||||||
#ifdef USE_ESP_IDF
|
|
||||||
esp_sntp_set_sync_interval(this->get_update_interval());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
sntp_init();
|
sntp_init();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
void SNTPComponent::dump_config() {
|
void SNTPComponent::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, "SNTP Time:");
|
ESP_LOGCONFIG(TAG, "SNTP Time:");
|
||||||
ESP_LOGCONFIG(TAG, " Server 1: '%s'", this->server_1_.c_str());
|
size_t i = 0;
|
||||||
ESP_LOGCONFIG(TAG, " Server 2: '%s'", this->server_2_.c_str());
|
for (auto &server : this->servers_) {
|
||||||
ESP_LOGCONFIG(TAG, " Server 3: '%s'", this->server_3_.c_str());
|
ESP_LOGCONFIG(TAG, " Server %zu: '%s'", i++, server.c_str());
|
||||||
ESP_LOGCONFIG(TAG, " Timezone: '%s'", this->timezone_.c_str());
|
}
|
||||||
}
|
}
|
||||||
void SNTPComponent::update() {
|
void SNTPComponent::update() {
|
||||||
#if !defined(USE_ESP_IDF)
|
#if !defined(USE_ESP_IDF)
|
||||||
|
@ -14,23 +14,20 @@ namespace sntp {
|
|||||||
/// \see https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
|
/// \see https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
|
||||||
class SNTPComponent : public time::RealTimeClock {
|
class SNTPComponent : public time::RealTimeClock {
|
||||||
public:
|
public:
|
||||||
|
SNTPComponent(const std::vector<std::string> &servers) : servers_(servers) {}
|
||||||
|
|
||||||
|
// Note: set_servers() has been removed and replaced by a constructor - calling set_servers after setup would
|
||||||
|
// have had no effect anyway, and making the strings immutable avoids the need to strdup their contents.
|
||||||
|
|
||||||
void setup() override;
|
void setup() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
/// Change the servers used by SNTP for timekeeping
|
|
||||||
void set_servers(const std::string &server_1, const std::string &server_2, const std::string &server_3) {
|
|
||||||
this->server_1_ = server_1;
|
|
||||||
this->server_2_ = server_2;
|
|
||||||
this->server_3_ = server_3;
|
|
||||||
}
|
|
||||||
float get_setup_priority() const override { return setup_priority::BEFORE_CONNECTION; }
|
float get_setup_priority() const override { return setup_priority::BEFORE_CONNECTION; }
|
||||||
|
|
||||||
void update() override;
|
void update() override;
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string server_1_;
|
std::vector<std::string> servers_;
|
||||||
std::string server_2_;
|
|
||||||
std::string server_3_;
|
|
||||||
bool has_time_{false};
|
bool has_time_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
from esphome.components import time as time_
|
from esphome.components import time as time_
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
import esphome.codegen as cg
|
|
||||||
from esphome.core import CORE
|
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
CONF_SERVERS,
|
CONF_SERVERS,
|
||||||
|
PLATFORM_BK72XX,
|
||||||
PLATFORM_ESP32,
|
PLATFORM_ESP32,
|
||||||
PLATFORM_ESP8266,
|
PLATFORM_ESP8266,
|
||||||
PLATFORM_RP2040,
|
PLATFORM_RP2040,
|
||||||
PLATFORM_RTL87XX,
|
PLATFORM_RTL87XX,
|
||||||
PLATFORM_BK72XX,
|
|
||||||
)
|
)
|
||||||
|
from esphome.core import CORE
|
||||||
|
|
||||||
DEPENDENCIES = ["network"]
|
DEPENDENCIES = ["network"]
|
||||||
sntp_ns = cg.esphome_ns.namespace("sntp")
|
sntp_ns = cg.esphome_ns.namespace("sntp")
|
||||||
@ -40,11 +40,8 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
|
||||||
|
|
||||||
servers = config[CONF_SERVERS]
|
servers = config[CONF_SERVERS]
|
||||||
servers += [""] * (3 - len(servers))
|
var = cg.new_Pvariable(config[CONF_ID], servers)
|
||||||
cg.add(var.set_servers(*servers))
|
|
||||||
|
|
||||||
await cg.register_component(var, config)
|
await cg.register_component(var, config)
|
||||||
await time_.register_time(var, config)
|
await time_.register_time(var, config)
|
||||||
|
@ -692,6 +692,7 @@ CONF_PRIORITY = "priority"
|
|||||||
CONF_PROJECT = "project"
|
CONF_PROJECT = "project"
|
||||||
CONF_PROTOCOL = "protocol"
|
CONF_PROTOCOL = "protocol"
|
||||||
CONF_PUBLISH_INITIAL_STATE = "publish_initial_state"
|
CONF_PUBLISH_INITIAL_STATE = "publish_initial_state"
|
||||||
|
CONF_PUBLISH_NAN_AS_NONE = "publish_nan_as_none"
|
||||||
CONF_PULL_MODE = "pull_mode"
|
CONF_PULL_MODE = "pull_mode"
|
||||||
CONF_PULLDOWN = "pulldown"
|
CONF_PULLDOWN = "pulldown"
|
||||||
CONF_PULLUP = "pullup"
|
CONF_PULLUP = "pullup"
|
||||||
|
@ -259,10 +259,15 @@ bool random_bytes(uint8_t *data, size_t len) {
|
|||||||
bool str_equals_case_insensitive(const std::string &a, const std::string &b) {
|
bool str_equals_case_insensitive(const std::string &a, const std::string &b) {
|
||||||
return strcasecmp(a.c_str(), b.c_str()) == 0;
|
return strcasecmp(a.c_str(), b.c_str()) == 0;
|
||||||
}
|
}
|
||||||
|
#if ESP_IDF_VERSION_MAJOR >= 5
|
||||||
|
bool str_startswith(const std::string &str, const std::string &start) { return str.starts_with(start); }
|
||||||
|
bool str_endswith(const std::string &str, const std::string &end) { return str.ends_with(end); }
|
||||||
|
#else
|
||||||
bool str_startswith(const std::string &str, const std::string &start) { return str.rfind(start, 0) == 0; }
|
bool str_startswith(const std::string &str, const std::string &start) { return str.rfind(start, 0) == 0; }
|
||||||
bool str_endswith(const std::string &str, const std::string &end) {
|
bool str_endswith(const std::string &str, const std::string &end) {
|
||||||
return str.rfind(end) == (str.size() - end.size());
|
return str.rfind(end) == (str.size() - end.size());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
std::string str_truncate(const std::string &str, size_t length) {
|
std::string str_truncate(const std::string &str, size_t length) {
|
||||||
return str.length() > length ? str.substr(0, length) : str;
|
return str.length() > length ? str.substr(0, length) : str;
|
||||||
}
|
}
|
||||||
|
@ -137,9 +137,9 @@ extra_scripts = post:esphome/components/esp32/post_build.py.script
|
|||||||
; This are common settings for the ESP32 (all variants) using IDF.
|
; This are common settings for the ESP32 (all variants) using IDF.
|
||||||
[common:esp32-idf]
|
[common:esp32-idf]
|
||||||
extends = common:idf
|
extends = common:idf
|
||||||
platform = platformio/espressif32@5.4.0
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.06/platform-espressif32.zip
|
||||||
platform_packages =
|
platform_packages =
|
||||||
platformio/framework-espidf@~3.40408.0
|
pioarduino/framework-espidf@https://github.com/pioarduino/esp-idf/releases/download/v5.1.5/esp-idf-v5.1.5.zip
|
||||||
|
|
||||||
framework = espidf
|
framework = espidf
|
||||||
lib_deps =
|
lib_deps =
|
||||||
|
@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
[project]
|
[project]
|
||||||
name = "esphome"
|
name = "esphome"
|
||||||
license = {text = "MIT"}
|
license = {text = "MIT"}
|
||||||
description = "Make creating custom firmwares for ESP32/ESP8266 super easy."
|
description = "ESPHome is a system to configure your microcontrollers by simple yet powerful configuration files and control them remotely through Home Automation systems."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = [
|
authors = [
|
||||||
{name = "The ESPHome Authors", email = "esphome@nabucasa.com"}
|
{name = "The ESPHome Authors", email = "esphome@nabucasa.com"}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Useful stuff when working in a development environment
|
# Useful stuff when working in a development environment
|
||||||
clang-format==13.0.1 # also change in .pre-commit-config.yaml and Dockerfile when updating
|
clang-format==13.0.1 # also change in .pre-commit-config.yaml and Dockerfile when updating
|
||||||
clang-tidy==14.0.6 # When updating clang-tidy, also update Dockerfile
|
clang-tidy==18.1.8 # When updating clang-tidy, also update Dockerfile
|
||||||
yamllint==1.35.1 # also change in .pre-commit-config.yaml when updating
|
yamllint==1.35.1 # also change in .pre-commit-config.yaml when updating
|
||||||
|
@ -63,8 +63,6 @@ def clang_options(idedata):
|
|||||||
"-Ddeprecated(x)=",
|
"-Ddeprecated(x)=",
|
||||||
# allow to condition code on the presence of clang-tidy
|
# allow to condition code on the presence of clang-tidy
|
||||||
"-DCLANG_TIDY",
|
"-DCLANG_TIDY",
|
||||||
# (esp-idf) Disable this header because they use asm with registers clang-tidy doesn't know
|
|
||||||
"-D__XTENSA_API_H__",
|
|
||||||
# (esp-idf) Fix __once_callable in some libstdc++ headers
|
# (esp-idf) Fix __once_callable in some libstdc++ headers
|
||||||
"-D_GLIBCXX_HAVE_TLS",
|
"-D_GLIBCXX_HAVE_TLS",
|
||||||
]
|
]
|
||||||
@ -238,7 +236,7 @@ def main():
|
|||||||
|
|
||||||
failed_files = []
|
failed_files = []
|
||||||
try:
|
try:
|
||||||
executable = get_binary("clang-tidy", 14)
|
executable = get_binary("clang-tidy", 18)
|
||||||
task_queue = queue.Queue(args.jobs)
|
task_queue = queue.Queue(args.jobs)
|
||||||
lock = threading.Lock()
|
lock = threading.Lock()
|
||||||
for _ in range(args.jobs):
|
for _ in range(args.jobs):
|
||||||
@ -283,12 +281,12 @@ def main():
|
|||||||
print("Applying fixes ...")
|
print("Applying fixes ...")
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
subprocess.call(["clang-apply-replacements-14", tmpdir])
|
subprocess.call(["clang-apply-replacements-18", tmpdir])
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
subprocess.call(["clang-apply-replacements", tmpdir])
|
subprocess.call(["clang-apply-replacements", tmpdir])
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print(
|
print(
|
||||||
"Error please install clang-apply-replacements-14 or clang-apply-replacements.\n",
|
"Error please install clang-apply-replacements-18 or clang-apply-replacements.\n",
|
||||||
file=sys.stderr,
|
file=sys.stderr,
|
||||||
)
|
)
|
||||||
except:
|
except:
|
||||||
|
39
tests/components/hbridge/common.yaml
Normal file
39
tests/components/hbridge/common.yaml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
output:
|
||||||
|
- platform: ${pwm_platform}
|
||||||
|
pin: ${output1_pin}
|
||||||
|
id: gpio_output1
|
||||||
|
- platform: ${pwm_platform}
|
||||||
|
pin: ${output2_pin}
|
||||||
|
id: gpio_output2
|
||||||
|
- platform: ${pwm_platform}
|
||||||
|
pin: ${output3_pin}
|
||||||
|
id: gpio_output3
|
||||||
|
- platform: ${pwm_platform}
|
||||||
|
pin: ${output4_pin}
|
||||||
|
id: gpio_output4
|
||||||
|
|
||||||
|
light:
|
||||||
|
- platform: hbridge
|
||||||
|
name: Icicle Lights
|
||||||
|
pin_a: gpio_output3
|
||||||
|
pin_b: gpio_output4
|
||||||
|
|
||||||
|
fan:
|
||||||
|
- platform: hbridge
|
||||||
|
id: fan_hbridge
|
||||||
|
speed_count: 4
|
||||||
|
name: H-bridge Fan with Presets
|
||||||
|
pin_a: gpio_output1
|
||||||
|
pin_b: gpio_output2
|
||||||
|
preset_modes:
|
||||||
|
- Preset 1
|
||||||
|
- Preset 2
|
||||||
|
on_preset_set:
|
||||||
|
then:
|
||||||
|
- logger.log: Preset mode was changed!
|
||||||
|
|
||||||
|
switch:
|
||||||
|
- platform: hbridge
|
||||||
|
id: switch_hbridge
|
||||||
|
on_pin: ${hbridge_on_pin}
|
||||||
|
off_pin: ${hbridge_off_pin}
|
@ -1,33 +1,17 @@
|
|||||||
output:
|
substitutions:
|
||||||
- platform: ledc
|
pwm_platform: ledc
|
||||||
pin: 14
|
output1_pin: "14"
|
||||||
id: gpio_output1
|
output2_pin: "15"
|
||||||
- platform: ledc
|
output3_pin: "12"
|
||||||
pin: 15
|
output4_pin: "13"
|
||||||
id: gpio_output2
|
hbridge_on_pin: "4"
|
||||||
- platform: ledc
|
hbridge_off_pin: "5"
|
||||||
pin: 12
|
|
||||||
id: gpio_output3
|
|
||||||
- platform: ledc
|
|
||||||
pin: 13
|
|
||||||
id: gpio_output4
|
|
||||||
|
|
||||||
light:
|
packages:
|
||||||
- platform: hbridge
|
common: !include common.yaml
|
||||||
name: Icicle Lights
|
|
||||||
pin_a: gpio_output3
|
|
||||||
pin_b: gpio_output4
|
|
||||||
|
|
||||||
fan:
|
switch:
|
||||||
- platform: hbridge
|
- id: !extend switch_hbridge
|
||||||
id: fan_hbridge
|
pulse_length: 60ms
|
||||||
speed_count: 4
|
wait_time: 10ms
|
||||||
name: H-bridge Fan with Presets
|
optimistic: false
|
||||||
pin_a: gpio_output1
|
|
||||||
pin_b: gpio_output2
|
|
||||||
preset_modes:
|
|
||||||
- Preset 1
|
|
||||||
- Preset 2
|
|
||||||
on_preset_set:
|
|
||||||
then:
|
|
||||||
- logger.log: Preset mode was changed!
|
|
||||||
|
@ -1,33 +1,16 @@
|
|||||||
output:
|
substitutions:
|
||||||
- platform: ledc
|
pwm_platform: "ledc"
|
||||||
pin: 4
|
output1_pin: "4"
|
||||||
id: gpio_output1
|
output2_pin: "5"
|
||||||
- platform: ledc
|
output3_pin: "6"
|
||||||
pin: 5
|
output4_pin: "7"
|
||||||
id: gpio_output2
|
hbridge_on_pin: "2"
|
||||||
- platform: ledc
|
hbridge_off_pin: "3"
|
||||||
pin: 6
|
|
||||||
id: gpio_output3
|
|
||||||
- platform: ledc
|
|
||||||
pin: 7
|
|
||||||
id: gpio_output4
|
|
||||||
|
|
||||||
light:
|
packages:
|
||||||
- platform: hbridge
|
common: !include common.yaml
|
||||||
name: Icicle Lights
|
|
||||||
pin_a: gpio_output3
|
|
||||||
pin_b: gpio_output4
|
|
||||||
|
|
||||||
fan:
|
switch:
|
||||||
- platform: hbridge
|
- id: !extend switch_hbridge
|
||||||
id: fan_hbridge
|
wait_time: 10ms
|
||||||
speed_count: 4
|
optimistic: true
|
||||||
name: H-bridge Fan with Presets
|
|
||||||
pin_a: gpio_output1
|
|
||||||
pin_b: gpio_output2
|
|
||||||
preset_modes:
|
|
||||||
- Preset 1
|
|
||||||
- Preset 2
|
|
||||||
on_preset_set:
|
|
||||||
then:
|
|
||||||
- logger.log: Preset mode was changed!
|
|
||||||
|
@ -1,33 +1,15 @@
|
|||||||
output:
|
substitutions:
|
||||||
- platform: ledc
|
pwm_platform: "ledc"
|
||||||
pin: 4
|
output1_pin: "4"
|
||||||
id: gpio_output1
|
output2_pin: "5"
|
||||||
- platform: ledc
|
output3_pin: "6"
|
||||||
pin: 5
|
output4_pin: "7"
|
||||||
id: gpio_output2
|
hbridge_on_pin: "2"
|
||||||
- platform: ledc
|
hbridge_off_pin: "3"
|
||||||
pin: 6
|
|
||||||
id: gpio_output3
|
|
||||||
- platform: ledc
|
|
||||||
pin: 7
|
|
||||||
id: gpio_output4
|
|
||||||
|
|
||||||
light:
|
packages:
|
||||||
- platform: hbridge
|
common: !include common.yaml
|
||||||
name: Icicle Lights
|
|
||||||
pin_a: gpio_output3
|
|
||||||
pin_b: gpio_output4
|
|
||||||
|
|
||||||
fan:
|
switch:
|
||||||
- platform: hbridge
|
- id: !extend switch_hbridge
|
||||||
id: fan_hbridge
|
pulse_length: 60ms
|
||||||
speed_count: 4
|
|
||||||
name: H-bridge Fan with Presets
|
|
||||||
pin_a: gpio_output1
|
|
||||||
pin_b: gpio_output2
|
|
||||||
preset_modes:
|
|
||||||
- Preset 1
|
|
||||||
- Preset 2
|
|
||||||
on_preset_set:
|
|
||||||
then:
|
|
||||||
- logger.log: Preset mode was changed!
|
|
||||||
|
@ -1,33 +1,16 @@
|
|||||||
output:
|
substitutions:
|
||||||
- platform: ledc
|
pwm_platform: "ledc"
|
||||||
pin: 14
|
output1_pin: "14"
|
||||||
id: gpio_output1
|
output2_pin: "15"
|
||||||
- platform: ledc
|
output3_pin: "12"
|
||||||
pin: 15
|
output4_pin: "13"
|
||||||
id: gpio_output2
|
hbridge_on_pin: "4"
|
||||||
- platform: ledc
|
hbridge_off_pin: "5"
|
||||||
pin: 12
|
|
||||||
id: gpio_output3
|
|
||||||
- platform: ledc
|
|
||||||
pin: 13
|
|
||||||
id: gpio_output4
|
|
||||||
|
|
||||||
light:
|
packages:
|
||||||
- platform: hbridge
|
common: !include common.yaml
|
||||||
name: Icicle Lights
|
|
||||||
pin_a: gpio_output3
|
|
||||||
pin_b: gpio_output4
|
|
||||||
|
|
||||||
fan:
|
switch:
|
||||||
- platform: hbridge
|
- id: !extend switch_hbridge
|
||||||
id: fan_hbridge
|
pulse_length: 60ms
|
||||||
speed_count: 4
|
wait_time: 10ms
|
||||||
name: H-bridge Fan with Presets
|
|
||||||
pin_a: gpio_output1
|
|
||||||
pin_b: gpio_output2
|
|
||||||
preset_modes:
|
|
||||||
- Preset 1
|
|
||||||
- Preset 2
|
|
||||||
on_preset_set:
|
|
||||||
then:
|
|
||||||
- logger.log: Preset mode was changed!
|
|
||||||
|
@ -1,33 +1,16 @@
|
|||||||
output:
|
substitutions:
|
||||||
- platform: esp8266_pwm
|
pwm_platform: "esp8266_pwm"
|
||||||
pin: 4
|
output1_pin: "4"
|
||||||
id: gpio_output1
|
output2_pin: "5"
|
||||||
- platform: esp8266_pwm
|
output3_pin: "12"
|
||||||
pin: 5
|
output4_pin: "13"
|
||||||
id: gpio_output2
|
hbridge_on_pin: "14"
|
||||||
- platform: esp8266_pwm
|
hbridge_off_pin: "15"
|
||||||
pin: 12
|
|
||||||
id: gpio_output3
|
|
||||||
- platform: esp8266_pwm
|
|
||||||
pin: 13
|
|
||||||
id: gpio_output4
|
|
||||||
|
|
||||||
light:
|
packages:
|
||||||
- platform: hbridge
|
common: !include common.yaml
|
||||||
name: Icicle Lights
|
|
||||||
pin_a: gpio_output3
|
|
||||||
pin_b: gpio_output4
|
|
||||||
|
|
||||||
fan:
|
switch:
|
||||||
- platform: hbridge
|
- id: !extend switch_hbridge
|
||||||
id: fan_hbridge
|
pulse_length: 60ms
|
||||||
speed_count: 4
|
wait_time: 10ms
|
||||||
name: H-bridge Fan with Presets
|
|
||||||
pin_a: gpio_output1
|
|
||||||
pin_b: gpio_output2
|
|
||||||
preset_modes:
|
|
||||||
- Preset 1
|
|
||||||
- Preset 2
|
|
||||||
on_preset_set:
|
|
||||||
then:
|
|
||||||
- logger.log: Preset mode was changed!
|
|
||||||
|
@ -1,33 +1,16 @@
|
|||||||
output:
|
substitutions:
|
||||||
- platform: rp2040_pwm
|
pwm_platform: "rp2040_pwm"
|
||||||
pin: 4
|
output1_pin: "4"
|
||||||
id: gpio_output1
|
output2_pin: "5"
|
||||||
- platform: rp2040_pwm
|
output3_pin: "6"
|
||||||
pin: 5
|
output4_pin: "7"
|
||||||
id: gpio_output2
|
hbridge_on_pin: "2"
|
||||||
- platform: rp2040_pwm
|
hbridge_off_pin: "3"
|
||||||
pin: 6
|
|
||||||
id: gpio_output3
|
|
||||||
- platform: rp2040_pwm
|
|
||||||
pin: 7
|
|
||||||
id: gpio_output4
|
|
||||||
|
|
||||||
light:
|
packages:
|
||||||
- platform: hbridge
|
common: !include common.yaml
|
||||||
name: Icicle Lights
|
|
||||||
pin_a: gpio_output3
|
|
||||||
pin_b: gpio_output4
|
|
||||||
|
|
||||||
fan:
|
switch:
|
||||||
- platform: hbridge
|
- id: !extend switch_hbridge
|
||||||
id: fan_hbridge
|
wait_time: 10ms
|
||||||
speed_count: 4
|
optimistic: true
|
||||||
name: H-bridge Fan with Presets
|
|
||||||
pin_a: gpio_output1
|
|
||||||
pin_b: gpio_output2
|
|
||||||
preset_modes:
|
|
||||||
- Preset 1
|
|
||||||
- Preset 2
|
|
||||||
on_preset_set:
|
|
||||||
then:
|
|
||||||
- logger.log: Preset mode was changed!
|
|
||||||
|
@ -109,6 +109,10 @@ lvgl:
|
|||||||
close_button: true
|
close_button: true
|
||||||
title: Messagebox
|
title: Messagebox
|
||||||
bg_color: 0xffff
|
bg_color: 0xffff
|
||||||
|
widgets:
|
||||||
|
- label:
|
||||||
|
text: Hello Msgbox
|
||||||
|
id: msgbox_label
|
||||||
body:
|
body:
|
||||||
text: This is a sample messagebox
|
text: This is a sample messagebox
|
||||||
bg_color: 0x808080
|
bg_color: 0x808080
|
||||||
@ -137,6 +141,9 @@ lvgl:
|
|||||||
- lvgl.widget.focus: mark
|
- lvgl.widget.focus: mark
|
||||||
- lvgl.widget.redraw: hello_label
|
- lvgl.widget.redraw: hello_label
|
||||||
- lvgl.widget.redraw:
|
- lvgl.widget.redraw:
|
||||||
|
- lvgl.label.update:
|
||||||
|
id: msgbox_label
|
||||||
|
text: Unloaded
|
||||||
on_all_events:
|
on_all_events:
|
||||||
logger.log:
|
logger.log:
|
||||||
format: "Event %s"
|
format: "Event %s"
|
||||||
@ -337,7 +344,7 @@ lvgl:
|
|||||||
id: button_button
|
id: button_button
|
||||||
width: 20%
|
width: 20%
|
||||||
height: 10%
|
height: 10%
|
||||||
transform_angle: !lambda return 180*100;
|
transform_angle: !lambda return(180*100);
|
||||||
arc_width: !lambda return 4;
|
arc_width: !lambda return 4;
|
||||||
border_width: !lambda return 6;
|
border_width: !lambda return 6;
|
||||||
shadow_ofs_x: !lambda return 6;
|
shadow_ofs_x: !lambda return 6;
|
||||||
@ -581,7 +588,7 @@ lvgl:
|
|||||||
- 180, 60
|
- 180, 60
|
||||||
- 240, 10
|
- 240, 10
|
||||||
on_click:
|
on_click:
|
||||||
- lvgl.widget.update:
|
- lvgl.line.update:
|
||||||
id: lv_line_id
|
id: lv_line_id
|
||||||
line_color: 0xFFFF
|
line_color: 0xFFFF
|
||||||
- lvgl.page.next:
|
- lvgl.page.next:
|
||||||
|
@ -60,6 +60,7 @@ mqtt:
|
|||||||
- mqtt.publish:
|
- mqtt.publish:
|
||||||
topic: some/topic
|
topic: some/topic
|
||||||
payload: Good-bye
|
payload: Good-bye
|
||||||
|
publish_nan_as_none: false
|
||||||
|
|
||||||
binary_sensor:
|
binary_sensor:
|
||||||
- platform: template
|
- platform: template
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
esphome:
|
|
||||||
name: componenttestesp32c3idf51
|
|
||||||
friendly_name: $component_name
|
|
||||||
|
|
||||||
esp32:
|
|
||||||
board: lolin_c3_mini
|
|
||||||
framework:
|
|
||||||
type: esp-idf
|
|
||||||
version: 5.1.2
|
|
||||||
platform_version: 6.5.0
|
|
||||||
|
|
||||||
logger:
|
|
||||||
level: VERY_VERBOSE
|
|
||||||
|
|
||||||
packages:
|
|
||||||
component_under_test: !include
|
|
||||||
file: $component_test_file
|
|
||||||
vars:
|
|
||||||
component_test_file: $component_test_file
|
|
@ -1,19 +0,0 @@
|
|||||||
esphome:
|
|
||||||
name: componenttestesp32idf51
|
|
||||||
friendly_name: $component_name
|
|
||||||
|
|
||||||
esp32:
|
|
||||||
board: nodemcu-32s
|
|
||||||
framework:
|
|
||||||
type: esp-idf
|
|
||||||
version: 5.1.2
|
|
||||||
platform_version: 6.5.0
|
|
||||||
|
|
||||||
logger:
|
|
||||||
level: VERY_VERBOSE
|
|
||||||
|
|
||||||
packages:
|
|
||||||
component_under_test: !include
|
|
||||||
file: $component_test_file
|
|
||||||
vars:
|
|
||||||
component_test_file: $component_test_file
|
|
@ -1,20 +0,0 @@
|
|||||||
esphome:
|
|
||||||
name: componenttestesp32s2idf51
|
|
||||||
friendly_name: $component_name
|
|
||||||
|
|
||||||
esp32:
|
|
||||||
board: esp32-s2-saola-1
|
|
||||||
variant: ESP32S2
|
|
||||||
framework:
|
|
||||||
type: esp-idf
|
|
||||||
version: 5.1.2
|
|
||||||
platform_version: 6.5.0
|
|
||||||
|
|
||||||
logger:
|
|
||||||
level: VERY_VERBOSE
|
|
||||||
|
|
||||||
packages:
|
|
||||||
component_under_test: !include
|
|
||||||
file: $component_test_file
|
|
||||||
vars:
|
|
||||||
component_test_file: $component_test_file
|
|
@ -1,20 +0,0 @@
|
|||||||
esphome:
|
|
||||||
name: componenttestesp32s3idf51
|
|
||||||
friendly_name: $component_name
|
|
||||||
|
|
||||||
esp32:
|
|
||||||
board: esp32s3box
|
|
||||||
variant: ESP32S3
|
|
||||||
framework:
|
|
||||||
type: esp-idf
|
|
||||||
version: 5.1.2
|
|
||||||
platform_version: 6.5.0
|
|
||||||
|
|
||||||
logger:
|
|
||||||
level: VERY_VERBOSE
|
|
||||||
|
|
||||||
packages:
|
|
||||||
component_under_test: !include
|
|
||||||
file: $component_test_file
|
|
||||||
vars:
|
|
||||||
component_test_file: $component_test_file
|
|
Loading…
x
Reference in New Issue
Block a user