mirror of
https://github.com/esphome/esphome.git
synced 2025-11-01 23:51:47 +00:00
Compare commits
12 Commits
jesserockz
...
2024.11.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c87658503 | ||
|
|
c80e035bd5 | ||
|
|
c8ec0bb7ea | ||
|
|
86ae1c5931 | ||
|
|
d0958f7cf2 | ||
|
|
982ce1db72 | ||
|
|
f042c6e643 | ||
|
|
5fcd26bfe9 | ||
|
|
5717d557f5 | ||
|
|
3bac45e737 | ||
|
|
e623989878 | ||
|
|
39cbc6b183 |
36
.clang-tidy
36
.clang-tidy
@@ -7,39 +7,28 @@ Checks: >-
|
||||
-boost-*,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-bugprone-implicit-widening-of-multiplication-result,
|
||||
-bugprone-multi-level-implicit-pointer-conversion,
|
||||
-bugprone-narrowing-conversions,
|
||||
-bugprone-signed-char-misuse,
|
||||
-bugprone-switch-missing-default-case,
|
||||
-cert-dcl50-cpp,
|
||||
-cert-err33-c,
|
||||
-cert-err58-cpp,
|
||||
-cert-oop57-cpp,
|
||||
-cert-str34-c,
|
||||
-clang-analyzer-optin.core.EnumCastOutOfRange,
|
||||
-clang-analyzer-optin.cplusplus.UninitializedObject,
|
||||
-clang-analyzer-osx.*,
|
||||
-clang-diagnostic-delete-abstract-non-virtual-dtor,
|
||||
-clang-diagnostic-delete-non-abstract-non-virtual-dtor,
|
||||
-clang-diagnostic-deprecated-declarations,
|
||||
-clang-diagnostic-ignored-optimization-argument,
|
||||
-clang-diagnostic-missing-field-initializers,
|
||||
-clang-diagnostic-shadow-field,
|
||||
-clang-diagnostic-unused-const-variable,
|
||||
-clang-diagnostic-unused-parameter,
|
||||
-clang-diagnostic-vla-cxx-extension,
|
||||
-concurrency-*,
|
||||
-cppcoreguidelines-avoid-c-arrays,
|
||||
-cppcoreguidelines-avoid-const-or-ref-data-members,
|
||||
-cppcoreguidelines-avoid-do-while,
|
||||
-cppcoreguidelines-avoid-magic-numbers,
|
||||
-cppcoreguidelines-init-variables,
|
||||
-cppcoreguidelines-macro-to-enum,
|
||||
-cppcoreguidelines-macro-usage,
|
||||
-cppcoreguidelines-missing-std-forward,
|
||||
-cppcoreguidelines-narrowing-conversions,
|
||||
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||
-cppcoreguidelines-owning-memory,
|
||||
-cppcoreguidelines-prefer-member-initializer,
|
||||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||
-cppcoreguidelines-pro-bounds-constant-array-index,
|
||||
@@ -51,9 +40,7 @@ Checks: >-
|
||||
-cppcoreguidelines-pro-type-static-cast-downcast,
|
||||
-cppcoreguidelines-pro-type-union-access,
|
||||
-cppcoreguidelines-pro-type-vararg,
|
||||
-cppcoreguidelines-rvalue-reference-param-not-moved,
|
||||
-cppcoreguidelines-special-member-functions,
|
||||
-cppcoreguidelines-use-default-member-init,
|
||||
-cppcoreguidelines-virtual-class-destructor,
|
||||
-fuchsia-multiple-inheritance,
|
||||
-fuchsia-overloaded-operator,
|
||||
@@ -73,32 +60,20 @@ Checks: >-
|
||||
-llvm-include-order,
|
||||
-llvm-qualified-auto,
|
||||
-llvmlibc-*,
|
||||
-misc-const-correctness,
|
||||
-misc-include-cleaner,
|
||||
-misc-no-recursion,
|
||||
-misc-non-private-member-variables-in-classes,
|
||||
-misc-no-recursion,
|
||||
-misc-unused-parameters,
|
||||
-misc-use-anonymous-namespace,
|
||||
-modernize-avoid-bind,
|
||||
-modernize-avoid-c-arrays,
|
||||
-modernize-avoid-bind,
|
||||
-modernize-concat-nested-namespaces,
|
||||
-modernize-macro-to-enum,
|
||||
-modernize-return-braced-init-list,
|
||||
-modernize-type-traits,
|
||||
-modernize-use-auto,
|
||||
-modernize-use-constraints,
|
||||
-modernize-use-default-member-init,
|
||||
-modernize-use-equals-default,
|
||||
-modernize-use-nodiscard,
|
||||
-modernize-use-nullptr,
|
||||
-modernize-use-nodiscard,
|
||||
-modernize-use-nullptr,
|
||||
-modernize-use-trailing-return-type,
|
||||
-modernize-use-nodiscard,
|
||||
-mpi-*,
|
||||
-objc-*,
|
||||
-performance-enum-size,
|
||||
-readability-avoid-nested-conditional-operator,
|
||||
-readability-container-contains,
|
||||
-readability-container-data-pointer,
|
||||
-readability-convert-member-functions-to-static,
|
||||
-readability-else-after-return,
|
||||
@@ -107,14 +82,11 @@ Checks: >-
|
||||
-readability-isolate-declaration,
|
||||
-readability-magic-numbers,
|
||||
-readability-make-member-function-const,
|
||||
-readability-named-parameter,
|
||||
-readability-redundant-casting,
|
||||
-readability-redundant-inline-specifier,
|
||||
-readability-redundant-member-init,
|
||||
-readability-redundant-string-init,
|
||||
-readability-uppercase-literal-suffix,
|
||||
-readability-use-anyofallof,
|
||||
WarningsAsErrors: '*'
|
||||
AnalyzeTemporaryDtors: false
|
||||
FormatStyle: google
|
||||
CheckOptions:
|
||||
- key: google-readability-function-size.StatementThreshold
|
||||
|
||||
4
.github/actions/build-image/action.yaml
vendored
4
.github/actions/build-image/action.yaml
vendored
@@ -46,7 +46,7 @@ runs:
|
||||
|
||||
- name: Build and push to ghcr by digest
|
||||
id: build-ghcr
|
||||
uses: docker/build-push-action@v6.10.0
|
||||
uses: docker/build-push-action@v6.9.0
|
||||
env:
|
||||
DOCKER_BUILD_SUMMARY: false
|
||||
DOCKER_BUILD_RECORD_UPLOAD: false
|
||||
@@ -72,7 +72,7 @@ runs:
|
||||
|
||||
- name: Build and push to dockerhub by digest
|
||||
id: build-dockerhub
|
||||
uses: docker/build-push-action@v6.10.0
|
||||
uses: docker/build-push-action@v6.9.0
|
||||
env:
|
||||
DOCKER_BUILD_SUMMARY: false
|
||||
DOCKER_BUILD_RECORD_UPLOAD: false
|
||||
|
||||
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 }}
|
||||
- name: Restore Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.1.2
|
||||
with:
|
||||
path: venv
|
||||
# yamllint disable-line rule:line-length
|
||||
|
||||
39
.github/workflows/ci.yml
vendored
39
.github/workflows/ci.yml
vendored
@@ -30,7 +30,7 @@ concurrency:
|
||||
jobs:
|
||||
common:
|
||||
name: Create common environment
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
cache-key: ${{ steps.cache-key.outputs.key }}
|
||||
steps:
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
python-version: ${{ env.DEFAULT_PYTHON }}
|
||||
- name: Restore Python virtual environment
|
||||
id: cache-venv
|
||||
uses: actions/cache@v4.2.0
|
||||
uses: actions/cache@v4.1.2
|
||||
with:
|
||||
path: venv
|
||||
# yamllint disable-line rule:line-length
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
|
||||
black:
|
||||
name: Check black
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
steps:
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
|
||||
flake8:
|
||||
name: Check flake8
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
steps:
|
||||
@@ -104,7 +104,7 @@ jobs:
|
||||
|
||||
pylint:
|
||||
name: Check pylint
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
steps:
|
||||
@@ -125,7 +125,7 @@ jobs:
|
||||
|
||||
pyupgrade:
|
||||
name: Check pyupgrade
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
steps:
|
||||
@@ -146,7 +146,7 @@ jobs:
|
||||
|
||||
ci-custom:
|
||||
name: Run script/ci-custom
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
steps:
|
||||
@@ -219,13 +219,13 @@ jobs:
|
||||
. venv/bin/activate
|
||||
pytest -vv --cov-report=xml --tb=native tests
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v5
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
clang-format:
|
||||
name: Check clang-format
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
steps:
|
||||
@@ -251,7 +251,7 @@ jobs:
|
||||
|
||||
clang-tidy:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
- black
|
||||
@@ -302,18 +302,23 @@ jobs:
|
||||
|
||||
- name: Cache platformio
|
||||
if: github.ref == 'refs/heads/dev'
|
||||
uses: actions/cache@v4.2.0
|
||||
uses: actions/cache@v4.1.2
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: platformio-${{ matrix.pio_cache_key }}
|
||||
|
||||
- name: Cache platformio
|
||||
if: github.ref != 'refs/heads/dev'
|
||||
uses: actions/cache/restore@v4.2.0
|
||||
uses: actions/cache/restore@v4.1.2
|
||||
with:
|
||||
path: ~/.platformio
|
||||
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
|
||||
run: |
|
||||
echo "::add-matcher::.github/workflows/matchers/gcc.json"
|
||||
@@ -340,7 +345,7 @@ jobs:
|
||||
if: always()
|
||||
|
||||
list-components:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
if: github.event_name == 'pull_request'
|
||||
@@ -382,7 +387,7 @@ jobs:
|
||||
|
||||
test-build-components:
|
||||
name: Component test ${{ matrix.file }}
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
- list-components
|
||||
@@ -416,7 +421,7 @@ jobs:
|
||||
|
||||
test-build-components-splitter:
|
||||
name: Split components for testing into 20 groups maximum
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
- list-components
|
||||
@@ -434,7 +439,7 @@ jobs:
|
||||
|
||||
test-build-components-split:
|
||||
name: Test split components
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
- list-components
|
||||
@@ -478,7 +483,7 @@ jobs:
|
||||
|
||||
ci-status:
|
||||
name: CI Status
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- common
|
||||
- black
|
||||
|
||||
@@ -179,7 +179,6 @@ esphome/components/haier/text_sensor/* @paveldn
|
||||
esphome/components/havells_solar/* @sourabhjaiswal
|
||||
esphome/components/hbridge/fan/* @WeekendWarrior
|
||||
esphome/components/hbridge/light/* @DotNetDann
|
||||
esphome/components/hbridge/switch/* @dwmw2
|
||||
esphome/components/he60r/* @clydebarrow
|
||||
esphome/components/heatpumpir/* @rob-deutsch
|
||||
esphome/components/hitachi_ac424/* @sourabhjaiswal
|
||||
@@ -355,7 +354,6 @@ esphome/components/sdl/* @clydebarrow
|
||||
esphome/components/sdm_meter/* @jesserockz @polyfaces
|
||||
esphome/components/sdp3x/* @Azimath
|
||||
esphome/components/seeed_mr24hpc1/* @limengdu
|
||||
esphome/components/seeed_mr60fda2/* @limengdu
|
||||
esphome/components/selec_meter/* @sourabhjaiswal
|
||||
esphome/components/select/* @esphome/core
|
||||
esphome/components/sen0321/* @notjj
|
||||
@@ -410,7 +408,6 @@ esphome/components/substitutions/* @esphome/core
|
||||
esphome/components/sun/* @OttoWinter
|
||||
esphome/components/sun_gtil2/* @Mat931
|
||||
esphome/components/switch/* @esphome/core
|
||||
esphome/components/switch/binary_sensor/* @ssieb
|
||||
esphome/components/t6615/* @tylermenezes
|
||||
esphome/components/tc74/* @sethgirvan
|
||||
esphome/components/tca9548a/* @andreashergert1984
|
||||
|
||||
@@ -163,18 +163,6 @@ ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD ["dashboard", "/config"]
|
||||
|
||||
|
||||
ARG BUILD_VERSION=dev
|
||||
|
||||
# Labels
|
||||
LABEL \
|
||||
org.opencontainers.image.authors="The ESPHome Authors" \
|
||||
org.opencontainers.image.title="ESPHome" \
|
||||
org.opencontainers.image.description="Manage and program ESP8266/ESP32 microcontrollers through YAML configuration files" \
|
||||
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 =======================
|
||||
@@ -221,22 +209,17 @@ ENV \
|
||||
PLATFORMIO_CORE_DIR=/esphome/.temp/platformio
|
||||
|
||||
RUN \
|
||||
curl -L https://apt.llvm.org/llvm-snapshot.gpg.key -o /etc/apt/trusted.gpg.d/apt.llvm.org.asc \
|
||||
&& echo "deb http://apt.llvm.org/bookworm/ llvm-toolchain-bookworm-18 main" > /etc/apt/sources.list.d/llvm.sources.list \
|
||||
&& apt-get update \
|
||||
apt-get update \
|
||||
# Use pinned versions so that we get updates with build caching
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
clang-format-13=1:13.0.1-11+b2 \
|
||||
clang-tidy-14=1:14.0.6-12 \
|
||||
patch=2.7.6-7 \
|
||||
software-properties-common=0.99.30-4.1~deb12u1 \
|
||||
nano=7.2-1+deb12u1 \
|
||||
build-essential=12.9 \
|
||||
python3-dev=3.11.2-1+b1 \
|
||||
&& 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 \
|
||||
&& rm -rf \
|
||||
/tmp/* \
|
||||
/var/{cache,log}/* \
|
||||
/var/lib/apt/lists/*
|
||||
|
||||
@@ -72,9 +72,10 @@ void AlarmControlPanelCall::validate_() {
|
||||
this->state_.reset();
|
||||
return;
|
||||
}
|
||||
if (state == ACP_STATE_DISARMED && !this->parent_->is_state_armed(this->parent_->get_state()) &&
|
||||
this->parent_->get_state() != ACP_STATE_PENDING && this->parent_->get_state() != ACP_STATE_ARMING &&
|
||||
this->parent_->get_state() != ACP_STATE_TRIGGERED) {
|
||||
if (state == ACP_STATE_DISARMED &&
|
||||
!(this->parent_->is_state_armed(this->parent_->get_state()) ||
|
||||
this->parent_->get_state() == ACP_STATE_PENDING || this->parent_->get_state() == ACP_STATE_ARMING ||
|
||||
this->parent_->get_state() == ACP_STATE_TRIGGERED)) {
|
||||
ESP_LOGW(TAG, "Cannot disarm when not armed");
|
||||
this->state_.reset();
|
||||
return;
|
||||
|
||||
@@ -2,6 +2,7 @@ import logging
|
||||
|
||||
from esphome import automation, core
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import font
|
||||
import esphome.components.image as espImage
|
||||
from esphome.components.image import (
|
||||
CONF_USE_TRANSPARENCY,
|
||||
@@ -130,7 +131,7 @@ ANIMATION_SCHEMA = cv.Schema(
|
||||
)
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = ANIMATION_SCHEMA
|
||||
CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, ANIMATION_SCHEMA)
|
||||
|
||||
NEXT_FRAME_SCHEMA = automation.maybe_simple_id(
|
||||
{
|
||||
|
||||
@@ -122,8 +122,7 @@ void APDS9306::update() {
|
||||
|
||||
this->status_clear_warning();
|
||||
|
||||
status &= 0b00001000;
|
||||
if (!status) { // No new data
|
||||
if (!(status &= 0b00001000)) { // No new data
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -213,7 +213,6 @@ message DeviceInfoResponse {
|
||||
// The esphome project details if set
|
||||
string project_name = 8;
|
||||
string project_version = 9;
|
||||
string project_manufacturer = 18;
|
||||
|
||||
uint32 webserver_port = 10;
|
||||
|
||||
|
||||
@@ -1429,7 +1429,7 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) {
|
||||
|
||||
HelloResponse resp;
|
||||
resp.api_version_major = 1;
|
||||
resp.api_version_minor = 11;
|
||||
resp.api_version_minor = 10;
|
||||
resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
|
||||
resp.name = App.get_name();
|
||||
|
||||
@@ -1479,13 +1479,7 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
|
||||
resp.has_deep_sleep = deep_sleep::global_has_deep_sleep;
|
||||
#endif
|
||||
#ifdef ESPHOME_PROJECT_NAME
|
||||
if (this->client_api_version_major_ > 1 ||
|
||||
(this->client_api_version_major_ == 1 && this->client_api_version_minor_ >= 11)) {
|
||||
resp.project_name = ESPHOME_PROJECT_NAME;
|
||||
resp.project_manufacturer = ESPHOME_PROJECT_MANUFACTURER;
|
||||
} else {
|
||||
resp.project_name = ESPHOME_PROJECT_MANUFACTURER "." ESPHOME_PROJECT_NAME;
|
||||
}
|
||||
resp.project_name = ESPHOME_PROJECT_NAME;
|
||||
resp.project_version = ESPHOME_PROJECT_VERSION;
|
||||
#endif
|
||||
#ifdef USE_WEBSERVER
|
||||
|
||||
@@ -826,10 +826,6 @@ bool DeviceInfoResponse::decode_length(uint32_t field_id, ProtoLengthDelimited v
|
||||
this->project_version = value.as_string();
|
||||
return true;
|
||||
}
|
||||
case 18: {
|
||||
this->project_manufacturer = value.as_string();
|
||||
return true;
|
||||
}
|
||||
case 12: {
|
||||
this->manufacturer = value.as_string();
|
||||
return true;
|
||||
@@ -856,7 +852,6 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_bool(7, this->has_deep_sleep);
|
||||
buffer.encode_string(8, this->project_name);
|
||||
buffer.encode_string(9, this->project_version);
|
||||
buffer.encode_string(18, this->project_manufacturer);
|
||||
buffer.encode_uint32(10, this->webserver_port);
|
||||
buffer.encode_uint32(11, this->legacy_bluetooth_proxy_version);
|
||||
buffer.encode_uint32(15, this->bluetooth_proxy_feature_flags);
|
||||
@@ -906,10 +901,6 @@ void DeviceInfoResponse::dump_to(std::string &out) const {
|
||||
out.append("'").append(this->project_version).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" project_manufacturer: ");
|
||||
out.append("'").append(this->project_manufacturer).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" webserver_port: ");
|
||||
sprintf(buffer, "%" PRIu32, this->webserver_port);
|
||||
out.append(buffer);
|
||||
|
||||
@@ -346,7 +346,6 @@ class DeviceInfoResponse : public ProtoMessage {
|
||||
bool has_deep_sleep{false};
|
||||
std::string project_name{};
|
||||
std::string project_version{};
|
||||
std::string project_manufacturer{};
|
||||
uint32_t webserver_port{0};
|
||||
uint32_t legacy_bluetooth_proxy_version{0};
|
||||
uint32_t bluetooth_proxy_feature_flags{0};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace esphome {
|
||||
namespace audio {
|
||||
|
||||
@@ -15,7 +15,7 @@ from esphome.components.libretiny.const import (
|
||||
)
|
||||
from esphome.core import CORE
|
||||
|
||||
from .boards import BK72XX_BOARD_PINS, BK72XX_BOARDS
|
||||
from .boards import BK72XX_BOARDS, BK72XX_BOARD_PINS
|
||||
|
||||
CODEOWNERS = ["@kuba2k2"]
|
||||
AUTO_LOAD = ["libretiny"]
|
||||
|
||||
@@ -43,7 +43,7 @@ bool CSE7766Component::check_byte_() {
|
||||
uint8_t index = this->raw_data_index_;
|
||||
uint8_t byte = this->raw_data_[index];
|
||||
if (index == 0) {
|
||||
return (byte == 0x55) || ((byte & 0xF0) == 0xF0) || (byte == 0xAA);
|
||||
return !((byte != 0x55) && ((byte & 0xF0) != 0xF0) && (byte != 0xAA));
|
||||
}
|
||||
|
||||
if (index == 1) {
|
||||
|
||||
@@ -52,11 +52,11 @@ void DeepSleepComponent::dump_config_platform_() {
|
||||
|
||||
bool DeepSleepComponent::prepare_to_sleep_() {
|
||||
if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_KEEP_AWAKE && this->wakeup_pin_ != nullptr &&
|
||||
this->wakeup_pin_->digital_read()) {
|
||||
!this->sleep_duration_.has_value() && this->wakeup_pin_->digital_read()) {
|
||||
// Defer deep sleep until inactive
|
||||
if (!this->next_enter_deep_sleep_) {
|
||||
this->status_set_warning();
|
||||
ESP_LOGW(TAG, "Waiting wakeup pin state change to enter deep sleep...");
|
||||
ESP_LOGW(TAG, "Waiting for pin_ to switch state to enter deep sleep...");
|
||||
}
|
||||
this->next_enter_deep_sleep_ = true;
|
||||
return false;
|
||||
|
||||
@@ -135,8 +135,7 @@ bool HOT IRAM_ATTR DHT::read_sensor_(float *temperature, float *humidity, bool r
|
||||
|
||||
// Wait for falling edge
|
||||
while (this->pin_->digital_read()) {
|
||||
end_time = micros();
|
||||
if (end_time - start_time > 90) {
|
||||
if ((end_time = micros()) - start_time > 90) {
|
||||
if (i < 0) {
|
||||
error_code = 3;
|
||||
} else {
|
||||
|
||||
@@ -662,24 +662,20 @@ void DisplayOnPageChangeTrigger::process(DisplayPage *from, DisplayPage *to) {
|
||||
if ((this->from_ == nullptr || this->from_ == from) && (this->to_ == nullptr || this->to_ == to))
|
||||
this->trigger(from, to);
|
||||
}
|
||||
void Display::strftime(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format,
|
||||
ESPTime time) {
|
||||
void Display::strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time) {
|
||||
char buffer[64];
|
||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||
if (ret > 0)
|
||||
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);
|
||||
this->print(x, y, font, color, align, buffer);
|
||||
}
|
||||
void Display::strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time) {
|
||||
this->strftime(x, y, font, color, COLOR_OFF, TextAlign::TOP_LEFT, format, time);
|
||||
this->strftime(x, y, font, color, TextAlign::TOP_LEFT, format, time);
|
||||
}
|
||||
void Display::strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time) {
|
||||
this->strftime(x, y, font, COLOR_ON, COLOR_OFF, align, format, time);
|
||||
this->strftime(x, y, font, COLOR_ON, align, format, time);
|
||||
}
|
||||
void Display::strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) {
|
||||
this->strftime(x, y, font, COLOR_ON, COLOR_OFF, TextAlign::TOP_LEFT, format, time);
|
||||
this->strftime(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, time);
|
||||
}
|
||||
|
||||
void Display::start_clipping(Rect rect) {
|
||||
|
||||
@@ -437,20 +437,6 @@ class Display : public PollingComponent {
|
||||
*/
|
||||
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`.
|
||||
*
|
||||
* @param x The x coordinate of the text alignment anchor point.
|
||||
|
||||
@@ -68,6 +68,8 @@ IsActiveCondition = display_menu_base_ns.class_(
|
||||
"IsActiveCondition", automation.Condition
|
||||
)
|
||||
|
||||
MULTI_CONF = True
|
||||
|
||||
MenuItemType = display_menu_base_ns.enum("MenuItemType")
|
||||
|
||||
MENU_ITEM_TYPES = {
|
||||
|
||||
@@ -280,7 +280,7 @@ bool DisplayMenuComponent::cursor_down_() {
|
||||
bool DisplayMenuComponent::enter_menu_() {
|
||||
this->displayed_item_->on_leave();
|
||||
this->displayed_item_ = static_cast<MenuItemMenu *>(this->get_selected_item_());
|
||||
this->selection_stack_.emplace_front(this->top_index_, this->cursor_index_);
|
||||
this->selection_stack_.push_front({this->top_index_, this->cursor_index_});
|
||||
this->cursor_index_ = this->top_index_ = 0;
|
||||
this->displayed_item_->on_enter();
|
||||
|
||||
|
||||
@@ -296,7 +296,7 @@ void Dsmr::dump_config() {
|
||||
}
|
||||
|
||||
void Dsmr::set_decryption_key(const std::string &decryption_key) {
|
||||
if (decryption_key.empty()) {
|
||||
if (decryption_key.length() == 0) {
|
||||
ESP_LOGI(TAG, "Disabling decryption");
|
||||
this->decryption_key_.clear();
|
||||
if (this->crypt_telegram_ != nullptr) {
|
||||
|
||||
@@ -65,8 +65,6 @@ _LOGGER = logging.getLogger(__name__)
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
AUTO_LOAD = ["preferences"]
|
||||
|
||||
CONF_RELEASE = "release"
|
||||
|
||||
|
||||
def set_core_data(config):
|
||||
CORE.data[KEY_ESP32] = {}
|
||||
@@ -218,17 +216,11 @@ def _format_framework_arduino_version(ver: cv.Version) -> str:
|
||||
return f"~3.{ver.major}{ver.minor:02d}{ver.patch:02d}.0"
|
||||
|
||||
|
||||
def _format_framework_espidf_version(
|
||||
ver: cv.Version, release: str, for_platformio: bool
|
||||
) -> str:
|
||||
def _format_framework_espidf_version(ver: cv.Version) -> str:
|
||||
# format the given arduino (https://github.com/espressif/esp-idf/releases) version to
|
||||
# a PIO platformio/framework-espidf value
|
||||
# List of package versions: https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf
|
||||
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"
|
||||
return f"~3.{ver.major}{ver.minor:02d}{ver.patch:02d}.0"
|
||||
|
||||
|
||||
# NOTE: Keep this in mind when updating the recommended version:
|
||||
@@ -249,33 +241,11 @@ ARDUINO_PLATFORM_VERSION = cv.Version(5, 4, 0)
|
||||
# The default/recommended esp-idf framework version
|
||||
# - https://github.com/espressif/esp-idf/releases
|
||||
# - https://api.registry.platformio.org/v3/packages/platformio/tool/framework-espidf
|
||||
RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(5, 1, 5)
|
||||
RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION = cv.Version(4, 4, 8)
|
||||
# The platformio/espressif32 version to use for esp-idf frameworks
|
||||
# - https://github.com/platformio/platform-espressif32/releases
|
||||
# - https://api.registry.platformio.org/v3/packages/platformio/platform/espressif32
|
||||
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),
|
||||
]
|
||||
ESP_IDF_PLATFORM_VERSION = cv.Version(5, 4, 0)
|
||||
|
||||
|
||||
def _arduino_check_versions(value):
|
||||
@@ -316,8 +286,8 @@ def _arduino_check_versions(value):
|
||||
def _esp_idf_check_versions(value):
|
||||
value = value.copy()
|
||||
lookups = {
|
||||
"dev": (cv.Version(5, 1, 5), "https://github.com/espressif/esp-idf.git"),
|
||||
"latest": (cv.Version(5, 1, 5), None),
|
||||
"dev": (cv.Version(5, 1, 2), "https://github.com/espressif/esp-idf.git"),
|
||||
"latest": (cv.Version(5, 1, 2), None),
|
||||
"recommended": (RECOMMENDED_ESP_IDF_FRAMEWORK_VERSION, None),
|
||||
}
|
||||
|
||||
@@ -335,51 +305,13 @@ def _esp_idf_check_versions(value):
|
||||
if version < cv.Version(4, 0, 0):
|
||||
raise cv.Invalid("Only ESP-IDF 4.0+ is supported.")
|
||||
|
||||
# flag this for later *before* we set value[CONF_PLATFORM_VERSION] below
|
||||
has_platform_ver = CONF_PLATFORM_VERSION in value
|
||||
value[CONF_VERSION] = str(version)
|
||||
value[CONF_SOURCE] = source or _format_framework_espidf_version(version)
|
||||
|
||||
value[CONF_PLATFORM_VERSION] = value.get(
|
||||
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:
|
||||
_LOGGER.warning(
|
||||
"The selected ESP-IDF framework version is not the recommended one. "
|
||||
@@ -391,12 +323,6 @@ def _esp_idf_check_versions(value):
|
||||
|
||||
def _parse_platform_version(value):
|
||||
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
|
||||
cv.platformio_version_constraint(value)
|
||||
return f"platformio/espressif32@{value}"
|
||||
@@ -404,14 +330,6 @@ def _parse_platform_version(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):
|
||||
board = value[CONF_BOARD]
|
||||
if board in BOARDS:
|
||||
@@ -490,7 +408,6 @@ ESP_IDF_FRAMEWORK_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
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_PLATFORM_VERSION): _parse_platform_version,
|
||||
cv.Optional(CONF_SDKCONFIG_OPTIONS, default={}): {
|
||||
@@ -594,9 +511,10 @@ async def to_code(config):
|
||||
cg.add_build_flag("-DUSE_ESP_IDF")
|
||||
cg.add_build_flag("-DUSE_ESP32_FRAMEWORK_ESP_IDF")
|
||||
cg.add_build_flag("-Wno-nonnull-compare")
|
||||
|
||||
cg.add_platformio_option("platform_packages", [conf[CONF_SOURCE]])
|
||||
|
||||
cg.add_platformio_option(
|
||||
"platform_packages",
|
||||
[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
|
||||
# This is espressif's own published version which is more up to date.
|
||||
cg.add_platformio_option(
|
||||
|
||||
@@ -2,10 +2,8 @@ from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ENABLE_ON_BOOT, CONF_ESPHOME, CONF_ID, CONF_NAME
|
||||
from esphome.const import CONF_ENABLE_ON_BOOT, CONF_ID
|
||||
from esphome.core import CORE
|
||||
from esphome.core.config import CONF_NAME_ADD_MAC_SUFFIX
|
||||
import esphome.final_validate as fv
|
||||
|
||||
DEPENDENCIES = ["esp32"]
|
||||
CODEOWNERS = ["@jesserockz", "@Rapsssito"]
|
||||
@@ -52,7 +50,6 @@ TX_POWER_LEVELS = {
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
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(
|
||||
IO_CAPABILITY, lower=True
|
||||
),
|
||||
@@ -70,22 +67,7 @@ def validate_variant(_):
|
||||
raise cv.Invalid(f"{variant} does not support Bluetooth")
|
||||
|
||||
|
||||
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
|
||||
FINAL_VALIDATE_SCHEMA = validate_variant
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
@@ -93,8 +75,6 @@ async def to_code(config):
|
||||
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_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)
|
||||
|
||||
if CORE.using_esp_idf:
|
||||
|
||||
@@ -188,20 +188,12 @@ bool ESP32BLE::ble_setup_() {
|
||||
}
|
||||
}
|
||||
|
||||
std::string name;
|
||||
if (this->name_.has_value()) {
|
||||
name = this->name_.value();
|
||||
std::string name = App.get_name();
|
||||
if (name.length() > 20) {
|
||||
if (App.is_name_add_mac_suffix_enabled()) {
|
||||
name += "-" + get_mac_address().substr(6);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
name.erase(name.begin() + 13, name.end() - 7); // Remove characters between 13 and the mac address
|
||||
} else {
|
||||
name = name.substr(0, 20);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,6 @@ class ESP32BLE : public Component {
|
||||
void loop() override;
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override;
|
||||
void set_name(const std::string &name) { this->name_ = name; }
|
||||
|
||||
void advertising_start();
|
||||
void advertising_set_service_data(const std::vector<uint8_t> &data);
|
||||
@@ -132,7 +131,6 @@ class ESP32BLE : public Component {
|
||||
esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE};
|
||||
uint32_t advertising_cycle_time_;
|
||||
bool enable_on_boot_;
|
||||
optional<std::string> name_;
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
@@ -83,7 +83,7 @@ esp_err_t BLEAdvertising::services_advertisement_() {
|
||||
esp_err_t err;
|
||||
|
||||
this->advertising_data_.set_scan_rsp = false;
|
||||
this->advertising_data_.include_name = true;
|
||||
this->advertising_data_.include_name = !this->scan_response_;
|
||||
this->advertising_data_.include_txpower = !this->scan_response_;
|
||||
err = esp_ble_gap_config_adv_data(&this->advertising_data_);
|
||||
if (err != ESP_OK) {
|
||||
|
||||
@@ -34,7 +34,7 @@ ESPBTUUID ESPBTUUID::from_raw(const uint8_t *data) {
|
||||
ESPBTUUID ESPBTUUID::from_raw_reversed(const uint8_t *data) {
|
||||
ESPBTUUID ret;
|
||||
ret.uuid_.len = ESP_UUID_LEN_128;
|
||||
for (uint8_t i = 0; i < ESP_UUID_LEN_128; i++)
|
||||
for (int i = 0; i < ESP_UUID_LEN_128; i++)
|
||||
ret.uuid_.uuid.uuid128[ESP_UUID_LEN_128 - 1 - i] = data[i];
|
||||
return ret;
|
||||
}
|
||||
@@ -43,30 +43,30 @@ ESPBTUUID ESPBTUUID::from_raw(const std::string &data) {
|
||||
if (data.length() == 4) {
|
||||
ret.uuid_.len = ESP_UUID_LEN_16;
|
||||
ret.uuid_.uuid.uuid16 = 0;
|
||||
for (uint i = 0; i < data.length(); i += 2) {
|
||||
for (int i = 0; i < data.length();) {
|
||||
uint8_t msb = data.c_str()[i];
|
||||
uint8_t lsb = data.c_str()[i + 1];
|
||||
uint8_t lsb_shift = i <= 2 ? (2 - i) * 4 : 0;
|
||||
|
||||
if (msb > '9')
|
||||
msb -= 7;
|
||||
if (lsb > '9')
|
||||
lsb -= 7;
|
||||
ret.uuid_.uuid.uuid16 += (((msb & 0x0F) << 4) | (lsb & 0x0F)) << lsb_shift;
|
||||
ret.uuid_.uuid.uuid16 += (((msb & 0x0F) << 4) | (lsb & 0x0F)) << (2 - i) * 4;
|
||||
i += 2;
|
||||
}
|
||||
} else if (data.length() == 8) {
|
||||
ret.uuid_.len = ESP_UUID_LEN_32;
|
||||
ret.uuid_.uuid.uuid32 = 0;
|
||||
for (uint i = 0; i < data.length(); i += 2) {
|
||||
for (int i = 0; i < data.length();) {
|
||||
uint8_t msb = data.c_str()[i];
|
||||
uint8_t lsb = data.c_str()[i + 1];
|
||||
uint8_t lsb_shift = i <= 6 ? (6 - i) * 4 : 0;
|
||||
|
||||
if (msb > '9')
|
||||
msb -= 7;
|
||||
if (lsb > '9')
|
||||
lsb -= 7;
|
||||
ret.uuid_.uuid.uuid32 += (((msb & 0x0F) << 4) | (lsb & 0x0F)) << lsb_shift;
|
||||
ret.uuid_.uuid.uuid32 += (((msb & 0x0F) << 4) | (lsb & 0x0F)) << (6 - i) * 4;
|
||||
i += 2;
|
||||
}
|
||||
} else if (data.length() == 16) { // how we can have 16 byte length string reprezenting 128 bit uuid??? needs to be
|
||||
// investigated (lack of time)
|
||||
@@ -77,7 +77,7 @@ ESPBTUUID ESPBTUUID::from_raw(const std::string &data) {
|
||||
// UUID format.
|
||||
ret.uuid_.len = ESP_UUID_LEN_128;
|
||||
int n = 0;
|
||||
for (uint i = 0; i < data.length(); i += 2) {
|
||||
for (int i = 0; i < data.length();) {
|
||||
if (data.c_str()[i] == '-')
|
||||
i++;
|
||||
uint8_t msb = data.c_str()[i];
|
||||
@@ -88,6 +88,7 @@ ESPBTUUID ESPBTUUID::from_raw(const std::string &data) {
|
||||
if (lsb > '9')
|
||||
lsb -= 7;
|
||||
ret.uuid_.uuid.uuid128[15 - n++] = ((msb & 0x0F) << 4) | (lsb & 0x0F);
|
||||
i += 2;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "ERROR: UUID value not 2, 4, 16 or 36 bytes - %s", data.c_str());
|
||||
@@ -154,7 +155,7 @@ bool ESPBTUUID::operator==(const ESPBTUUID &uuid) const {
|
||||
}
|
||||
break;
|
||||
case ESP_UUID_LEN_128:
|
||||
for (uint8_t i = 0; i < ESP_UUID_LEN_128; i++) {
|
||||
for (int i = 0; i < ESP_UUID_LEN_128; i++) {
|
||||
if (uuid.uuid_.uuid.uuid128[i] != this->uuid_.uuid.uuid128[i]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -432,7 +432,7 @@ void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_e
|
||||
|
||||
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
|
||||
ESP_LOGVV(TAG, "Parse Result:");
|
||||
const char *address_type;
|
||||
const char *address_type = "";
|
||||
switch (this->address_type_) {
|
||||
case BLE_ADDR_TYPE_PUBLIC:
|
||||
address_type = "PUBLIC";
|
||||
@@ -446,9 +446,6 @@ void ESPBTDevice::parse_scan_rst(const esp_ble_gap_cb_param_t::ble_scan_result_e
|
||||
case BLE_ADDR_TYPE_RPA_RANDOM:
|
||||
address_type = "RPA_RANDOM";
|
||||
break;
|
||||
default:
|
||||
address_type = "UNKNOWN";
|
||||
break;
|
||||
}
|
||||
ESP_LOGVV(TAG, " Address: %02X:%02X:%02X:%02X:%02X:%02X (%s)", this->address_[0], this->address_[1],
|
||||
this->address_[2], this->address_[3], this->address_[4], this->address_[5], address_type);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/preferences.h"
|
||||
|
||||
struct httpd_req; // NOLINT(readability-identifier-naming)
|
||||
struct httpd_req;
|
||||
|
||||
namespace esphome {
|
||||
namespace esp32_camera_web_server {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from esphome import pins
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import esp32_rmt, light
|
||||
import esphome.config_validation as cv
|
||||
from esphome import pins
|
||||
from esphome.components import esp32_rmt, light
|
||||
from esphome.const import (
|
||||
CONF_CHIPSET,
|
||||
CONF_IS_RGBW,
|
||||
@@ -103,7 +103,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
default="0 us",
|
||||
): cv.positive_time_period_nanoseconds,
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
),
|
||||
cv.has_exactly_one_key(CONF_CHIPSET, CONF_BIT0_HIGH),
|
||||
)
|
||||
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import logging
|
||||
import os
|
||||
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_BOARD,
|
||||
CONF_BOARD_FLASH_MODE,
|
||||
CONF_FRAMEWORK,
|
||||
CONF_PLATFORM_VERSION,
|
||||
CONF_SOURCE,
|
||||
CONF_VERSION,
|
||||
KEY_CORE,
|
||||
@@ -15,22 +12,27 @@ from esphome.const import (
|
||||
KEY_TARGET_FRAMEWORK,
|
||||
KEY_TARGET_PLATFORM,
|
||||
PLATFORM_ESP8266,
|
||||
CONF_PLATFORM_VERSION,
|
||||
)
|
||||
from esphome.core import CORE, coroutine_with_priority
|
||||
import esphome.config_validation as cv
|
||||
import esphome.codegen as cg
|
||||
from esphome.helpers import copy_file_if_changed
|
||||
|
||||
from .boards import BOARDS, ESP8266_LD_SCRIPTS
|
||||
from .const import (
|
||||
CONF_EARLY_PIN_INIT,
|
||||
CONF_RESTORE_FROM_FLASH,
|
||||
CONF_EARLY_PIN_INIT,
|
||||
KEY_BOARD,
|
||||
KEY_ESP8266,
|
||||
KEY_FLASH_SIZE,
|
||||
KEY_PIN_INITIAL_STATES,
|
||||
esp8266_ns,
|
||||
)
|
||||
from .boards import BOARDS, ESP8266_LD_SCRIPTS
|
||||
|
||||
from .gpio import PinInitialState, add_pin_initial_states_array
|
||||
|
||||
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
AUTO_LOAD = ["preferences"]
|
||||
|
||||
@@ -111,11 +111,11 @@ void EZOSensor::loop() {
|
||||
if (buf[0] == 1) {
|
||||
std::string payload = reinterpret_cast<char *>(&buf[1]);
|
||||
if (!payload.empty()) {
|
||||
auto start_location = payload.find(',');
|
||||
switch (to_run->command_type) {
|
||||
case EzoCommandType::EZO_READ: {
|
||||
// some sensors return multiple comma-separated values, terminate string after first one
|
||||
if (start_location != std::string::npos) {
|
||||
int start_location = 0;
|
||||
if ((start_location = payload.find(',')) != std::string::npos) {
|
||||
payload.erase(start_location);
|
||||
}
|
||||
auto val = parse_number<float>(payload);
|
||||
@@ -126,37 +126,49 @@ void EZOSensor::loop() {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EzoCommandType::EZO_LED:
|
||||
case EzoCommandType::EZO_LED: {
|
||||
this->led_callback_.call(payload.back() == '1');
|
||||
break;
|
||||
case EzoCommandType::EZO_DEVICE_INFORMATION:
|
||||
if (start_location != std::string::npos) {
|
||||
}
|
||||
case EzoCommandType::EZO_DEVICE_INFORMATION: {
|
||||
int start_location = 0;
|
||||
if ((start_location = payload.find(',')) != std::string::npos) {
|
||||
this->device_infomation_callback_.call(payload.substr(start_location + 1));
|
||||
}
|
||||
break;
|
||||
case EzoCommandType::EZO_SLOPE:
|
||||
if (start_location != std::string::npos) {
|
||||
}
|
||||
case EzoCommandType::EZO_SLOPE: {
|
||||
int start_location = 0;
|
||||
if ((start_location = payload.find(',')) != std::string::npos) {
|
||||
this->slope_callback_.call(payload.substr(start_location + 1));
|
||||
}
|
||||
break;
|
||||
case EzoCommandType::EZO_CALIBRATION:
|
||||
if (start_location != std::string::npos) {
|
||||
}
|
||||
case EzoCommandType::EZO_CALIBRATION: {
|
||||
int start_location = 0;
|
||||
if ((start_location = payload.find(',')) != std::string::npos) {
|
||||
this->calibration_callback_.call(payload.substr(start_location + 1));
|
||||
}
|
||||
break;
|
||||
case EzoCommandType::EZO_T:
|
||||
if (start_location != std::string::npos) {
|
||||
}
|
||||
case EzoCommandType::EZO_T: {
|
||||
int start_location = 0;
|
||||
if ((start_location = payload.find(',')) != std::string::npos) {
|
||||
this->t_callback_.call(payload.substr(start_location + 1));
|
||||
}
|
||||
break;
|
||||
case EzoCommandType::EZO_CUSTOM:
|
||||
}
|
||||
case EzoCommandType::EZO_CUSTOM: {
|
||||
this->custom_callback_.call(payload);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->commands_.pop_front();
|
||||
}
|
||||
|
||||
@@ -166,7 +178,7 @@ void EZOSensor::add_command_(const std::string &command, EzoCommandType command_
|
||||
ezo_command->command_type = command_type;
|
||||
ezo_command->delay_ms = delay_ms;
|
||||
this->commands_.push_back(std::move(ezo_command));
|
||||
}
|
||||
};
|
||||
|
||||
void EZOSensor::set_calibration_point_(EzoCalibrationType type, float value) {
|
||||
std::string payload = str_sprintf("Cal,%s,%0.2f", EZO_CALIBRATION_TYPE_STRINGS[type], value);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from collections.abc import Iterable
|
||||
import functools
|
||||
import hashlib
|
||||
import logging
|
||||
@@ -7,6 +8,7 @@ import re
|
||||
|
||||
import freetype
|
||||
import glyphsets
|
||||
from packaging import version
|
||||
import requests
|
||||
|
||||
from esphome import core, external_files
|
||||
@@ -86,7 +88,7 @@ def flatten(lists) -> list:
|
||||
return list(chain.from_iterable(lists))
|
||||
|
||||
|
||||
def check_missing_glyphs(file, codepoints, warning: bool = False):
|
||||
def check_missing_glyphs(file, codepoints: Iterable, warning: bool = False):
|
||||
"""
|
||||
Check that the given font file actually contains the requested glyphs
|
||||
:param file: A Truetype font file
|
||||
@@ -175,6 +177,24 @@ def validate_glyphs(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")
|
||||
|
||||
|
||||
@@ -373,9 +393,7 @@ def font_file_schema(value):
|
||||
# Default if no glyphs or glyphsets are provided
|
||||
DEFAULT_GLYPHSET = "GF_Latin_Kernel"
|
||||
# default for bitmap fonts
|
||||
DEFAULT_GLYPHS = (
|
||||
' !"%()+=,-.:/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz°'
|
||||
)
|
||||
DEFAULT_GLYPHS = ' !"%()+=,-.:/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz<C2><B0>'
|
||||
|
||||
CONF_RAW_GLYPH_ID = "raw_glyph_id"
|
||||
|
||||
@@ -403,7 +421,7 @@ FONT_SCHEMA = cv.Schema(
|
||||
},
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(FONT_SCHEMA, validate_glyphs)
|
||||
CONFIG_SCHEMA = cv.All(validate_pillow_installed, FONT_SCHEMA, validate_glyphs)
|
||||
|
||||
|
||||
# PIL doesn't provide a consistent interface for both TrueType and bitmap
|
||||
|
||||
@@ -36,8 +36,6 @@ CODEOWNERS = ["@MrMDavidson"]
|
||||
|
||||
AUTO_LOAD = ["display_menu_base"]
|
||||
|
||||
MULTI_CONF = True
|
||||
|
||||
CONFIG_SCHEMA = DISPLAY_MENU_BASE_SCHEMA.extend(
|
||||
cv.Schema(
|
||||
{
|
||||
|
||||
@@ -35,9 +35,7 @@ void HonClimate::set_beeper_state(bool state) {
|
||||
if (state != this->settings_.beeper_state) {
|
||||
this->settings_.beeper_state = state;
|
||||
#ifdef USE_SWITCH
|
||||
if (this->beeper_switch_ != nullptr) {
|
||||
this->beeper_switch_->publish_state(state);
|
||||
}
|
||||
this->beeper_switch_->publish_state(state);
|
||||
#endif
|
||||
this->hon_rtc_.save(&this->settings_);
|
||||
}
|
||||
@@ -47,17 +45,10 @@ bool HonClimate::get_beeper_state() const { return this->settings_.beeper_state;
|
||||
|
||||
void HonClimate::set_quiet_mode_state(bool state) {
|
||||
if (state != this->get_quiet_mode_state()) {
|
||||
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->quiet_mode_state_ = state ? SwitchState::PENDING_ON : SwitchState::PENDING_OFF;
|
||||
this->settings_.quiet_mode_state = state;
|
||||
#ifdef USE_SWITCH
|
||||
if (this->quiet_mode_switch_ != nullptr) {
|
||||
this->quiet_mode_switch_->publish_state(state);
|
||||
}
|
||||
this->quiet_mode_switch_->publish_state(state);
|
||||
#endif
|
||||
this->hon_rtc_.save(&this->settings_);
|
||||
}
|
||||
@@ -518,7 +509,7 @@ void HonClimate::initialization() {
|
||||
}
|
||||
this->current_vertical_swing_ = this->settings_.last_vertiacal_swing;
|
||||
this->current_horizontal_swing_ = this->settings_.last_horizontal_swing;
|
||||
this->quiet_mode_state_ = this->settings_.quiet_mode_state ? SwitchState::ON : SwitchState::OFF;
|
||||
this->quiet_mode_state_ = this->settings_.quiet_mode_state ? SwitchState::PENDING_ON : SwitchState::PENDING_OFF;
|
||||
}
|
||||
|
||||
haier_protocol::HaierMessage HonClimate::get_control_message() {
|
||||
@@ -941,7 +932,7 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *
|
||||
if (this->mode == CLIMATE_MODE_OFF) {
|
||||
// AC just turned on from remote need to turn off display
|
||||
this->force_send_control_ = true;
|
||||
} else if ((((uint8_t) this->display_status_) & 0b10) == 0) {
|
||||
} else if ((((uint8_t) this->health_mode_) & 0b10) == 0) {
|
||||
this->display_status_ = disp_status ? SwitchState::ON : SwitchState::OFF;
|
||||
}
|
||||
}
|
||||
@@ -1013,11 +1004,6 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *
|
||||
if (new_quiet_mode != this->get_quiet_mode_state()) {
|
||||
this->quiet_mode_state_ = new_quiet_mode ? SwitchState::ON : SwitchState::OFF;
|
||||
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_);
|
||||
}
|
||||
}
|
||||
@@ -1083,17 +1069,19 @@ void HonClimate::fill_control_messages_queue_() {
|
||||
climate_control = this->current_hvac_settings_;
|
||||
// Beeper command
|
||||
{
|
||||
this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::BEEPER_STATUS,
|
||||
this->get_beeper_state() ? ZERO_BUF : ONE_BUF, 2);
|
||||
this->control_messages_queue_.push(
|
||||
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::BEEPER_STATUS,
|
||||
this->get_beeper_state() ? ZERO_BUF : ONE_BUF, 2));
|
||||
}
|
||||
// Health mode
|
||||
{
|
||||
this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::HEALTH_MODE,
|
||||
this->get_health_mode() ? ONE_BUF : ZERO_BUF, 2);
|
||||
this->control_messages_queue_.push(
|
||||
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::HEALTH_MODE,
|
||||
this->get_health_mode() ? ONE_BUF : ZERO_BUF, 2));
|
||||
this->health_mode_ = (SwitchState) ((uint8_t) this->health_mode_ & 0b01);
|
||||
}
|
||||
// Climate mode
|
||||
@@ -1111,46 +1099,51 @@ void HonClimate::fill_control_messages_queue_() {
|
||||
case CLIMATE_MODE_HEAT_COOL:
|
||||
new_power = true;
|
||||
buffer[1] = (uint8_t) hon_protocol::ConditioningMode::AUTO;
|
||||
this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::AC_MODE,
|
||||
buffer, 2);
|
||||
this->control_messages_queue_.push(
|
||||
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::AC_MODE,
|
||||
buffer, 2));
|
||||
fan_mode_buf[1] = this->other_modes_fan_speed_;
|
||||
break;
|
||||
case CLIMATE_MODE_HEAT:
|
||||
new_power = true;
|
||||
buffer[1] = (uint8_t) hon_protocol::ConditioningMode::HEAT;
|
||||
this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::AC_MODE,
|
||||
buffer, 2);
|
||||
this->control_messages_queue_.push(
|
||||
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::AC_MODE,
|
||||
buffer, 2));
|
||||
fan_mode_buf[1] = this->other_modes_fan_speed_;
|
||||
break;
|
||||
case CLIMATE_MODE_DRY:
|
||||
new_power = true;
|
||||
buffer[1] = (uint8_t) hon_protocol::ConditioningMode::DRY;
|
||||
this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::AC_MODE,
|
||||
buffer, 2);
|
||||
this->control_messages_queue_.push(
|
||||
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::AC_MODE,
|
||||
buffer, 2));
|
||||
fan_mode_buf[1] = this->other_modes_fan_speed_;
|
||||
break;
|
||||
case CLIMATE_MODE_FAN_ONLY:
|
||||
new_power = true;
|
||||
buffer[1] = (uint8_t) hon_protocol::ConditioningMode::FAN;
|
||||
this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::AC_MODE,
|
||||
buffer, 2);
|
||||
this->control_messages_queue_.push(
|
||||
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::AC_MODE,
|
||||
buffer, 2));
|
||||
fan_mode_buf[1] = this->other_modes_fan_speed_; // Auto doesn't work in fan only mode
|
||||
break;
|
||||
case CLIMATE_MODE_COOL:
|
||||
new_power = true;
|
||||
buffer[1] = (uint8_t) hon_protocol::ConditioningMode::COOL;
|
||||
this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::AC_MODE,
|
||||
buffer, 2);
|
||||
this->control_messages_queue_.push(
|
||||
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::AC_MODE,
|
||||
buffer, 2));
|
||||
fan_mode_buf[1] = this->other_modes_fan_speed_;
|
||||
break;
|
||||
default:
|
||||
@@ -1160,10 +1153,11 @@ void HonClimate::fill_control_messages_queue_() {
|
||||
}
|
||||
// Climate power
|
||||
{
|
||||
this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::AC_POWER,
|
||||
new_power ? ONE_BUF : ZERO_BUF, 2);
|
||||
this->control_messages_queue_.push(
|
||||
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::AC_POWER,
|
||||
new_power ? ONE_BUF : ZERO_BUF, 2));
|
||||
}
|
||||
// CLimate preset
|
||||
{
|
||||
@@ -1205,32 +1199,36 @@ void HonClimate::fill_control_messages_queue_() {
|
||||
}
|
||||
auto presets = this->traits_.get_supported_presets();
|
||||
if (quiet_mode_buf[1] != 0xFF) {
|
||||
this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::QUIET_MODE,
|
||||
quiet_mode_buf, 2);
|
||||
this->control_messages_queue_.push(
|
||||
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::QUIET_MODE,
|
||||
quiet_mode_buf, 2));
|
||||
}
|
||||
if ((fast_mode_buf[1] != 0xFF) && ((presets.find(climate::ClimatePreset::CLIMATE_PRESET_BOOST) != presets.end()))) {
|
||||
this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::FAST_MODE,
|
||||
fast_mode_buf, 2);
|
||||
this->control_messages_queue_.push(
|
||||
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::FAST_MODE,
|
||||
fast_mode_buf, 2));
|
||||
}
|
||||
if ((away_mode_buf[1] != 0xFF) && ((presets.find(climate::ClimatePreset::CLIMATE_PRESET_AWAY) != presets.end()))) {
|
||||
this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::TEN_DEGREE,
|
||||
away_mode_buf, 2);
|
||||
this->control_messages_queue_.push(
|
||||
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::TEN_DEGREE,
|
||||
away_mode_buf, 2));
|
||||
}
|
||||
}
|
||||
// Target temperature
|
||||
if (climate_control.target_temperature.has_value() && (this->mode != ClimateMode::CLIMATE_MODE_FAN_ONLY)) {
|
||||
uint8_t buffer[2] = {0x00, 0x00};
|
||||
buffer[1] = ((uint8_t) climate_control.target_temperature.value()) - 16;
|
||||
this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::SET_POINT,
|
||||
buffer, 2);
|
||||
this->control_messages_queue_.push(
|
||||
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::SET_POINT,
|
||||
buffer, 2));
|
||||
}
|
||||
// Vertical swing mode
|
||||
if (climate_control.swing_mode.has_value()) {
|
||||
@@ -1250,14 +1248,16 @@ void HonClimate::fill_control_messages_queue_() {
|
||||
case CLIMATE_SWING_BOTH:
|
||||
break;
|
||||
}
|
||||
this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::HORIZONTAL_SWING_MODE,
|
||||
horizontal_swing_buf, 2);
|
||||
this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::VERTICAL_SWING_MODE,
|
||||
vertical_swing_buf, 2);
|
||||
this->control_messages_queue_.push(
|
||||
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::HORIZONTAL_SWING_MODE,
|
||||
horizontal_swing_buf, 2));
|
||||
this->control_messages_queue_.push(
|
||||
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::VERTICAL_SWING_MODE,
|
||||
vertical_swing_buf, 2));
|
||||
}
|
||||
// Fan mode
|
||||
if (climate_control.fan_mode.has_value()) {
|
||||
@@ -1280,10 +1280,11 @@ void HonClimate::fill_control_messages_queue_() {
|
||||
break;
|
||||
}
|
||||
if (fan_mode_buf[1] != 0xFF) {
|
||||
this->control_messages_queue_.emplace(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::FAN_MODE,
|
||||
fan_mode_buf, 2);
|
||||
this->control_messages_queue_.push(
|
||||
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
|
||||
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
|
||||
(uint8_t) hon_protocol::DataParameters::FAN_MODE,
|
||||
fan_mode_buf, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
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))
|
||||
@@ -1,95 +0,0 @@
|
||||
#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
|
||||
@@ -1,50 +0,0 @@
|
||||
#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
|
||||
@@ -133,10 +133,8 @@ bool HitachiClimate::get_swing_v_() {
|
||||
}
|
||||
|
||||
void HitachiClimate::set_swing_h_(uint8_t position) {
|
||||
if (position > HITACHI_AC344_SWINGH_LEFT_MAX) {
|
||||
set_swing_h_(HITACHI_AC344_SWINGH_MIDDLE);
|
||||
return;
|
||||
}
|
||||
if (position > HITACHI_AC344_SWINGH_LEFT_MAX)
|
||||
return set_swing_h_(HITACHI_AC344_SWINGH_MIDDLE);
|
||||
set_bits(&remote_state_[HITACHI_AC344_SWINGH_BYTE], HITACHI_AC344_SWINGH_OFFSET, HITACHI_AC344_SWINGH_SIZE, position);
|
||||
set_button_(HITACHI_AC344_BUTTON_SWINGH);
|
||||
}
|
||||
|
||||
@@ -133,10 +133,8 @@ bool HitachiClimate::get_swing_v_() {
|
||||
}
|
||||
|
||||
void HitachiClimate::set_swing_h_(uint8_t position) {
|
||||
if (position > HITACHI_AC424_SWINGH_LEFT_MAX) {
|
||||
set_swing_h_(HITACHI_AC424_SWINGH_MIDDLE);
|
||||
return;
|
||||
}
|
||||
if (position > HITACHI_AC424_SWINGH_LEFT_MAX)
|
||||
return set_swing_h_(HITACHI_AC424_SWINGH_MIDDLE);
|
||||
set_bits(&remote_state_[HITACHI_AC424_SWINGH_BYTE], HITACHI_AC424_SWINGH_OFFSET, HITACHI_AC424_SWINGH_SIZE, position);
|
||||
set_button_(HITACHI_AC424_BUTTON_SWINGH);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ void HomeassistantNumber::min_retrieved_(const std::string &min) {
|
||||
auto min_value = parse_number<float>(min);
|
||||
if (!min_value.has_value()) {
|
||||
ESP_LOGE(TAG, "'%s': Can't convert 'min' value '%s' to number!", this->entity_id_.c_str(), min.c_str());
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "'%s': Min retrieved: %s", get_name().c_str(), min.c_str());
|
||||
this->traits.set_min_value(min_value.value());
|
||||
@@ -37,7 +36,6 @@ void HomeassistantNumber::max_retrieved_(const std::string &max) {
|
||||
auto max_value = parse_number<float>(max);
|
||||
if (!max_value.has_value()) {
|
||||
ESP_LOGE(TAG, "'%s': Can't convert 'max' value '%s' to number!", this->entity_id_.c_str(), max.c_str());
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "'%s': Max retrieved: %s", get_name().c_str(), max.c_str());
|
||||
this->traits.set_max_value(max_value.value());
|
||||
@@ -47,7 +45,6 @@ void HomeassistantNumber::step_retrieved_(const std::string &step) {
|
||||
auto step_value = parse_number<float>(step);
|
||||
if (!step_value.has_value()) {
|
||||
ESP_LOGE(TAG, "'%s': Can't convert 'step' value '%s' to number!", this->entity_id_.c_str(), step.c_str());
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "'%s': Step Retrieved %s", get_name().c_str(), step.c_str());
|
||||
this->traits.set_step(step_value.value());
|
||||
|
||||
@@ -53,7 +53,7 @@ bool HX711Sensor::read_sensor_(uint32_t *result) {
|
||||
}
|
||||
|
||||
// Cycle clock pin for gain setting
|
||||
for (uint8_t i = 0; i < static_cast<uint8_t>(this->gain_); i++) {
|
||||
for (uint8_t i = 0; i < this->gain_; i++) {
|
||||
this->sck_pin_->digital_write(true);
|
||||
delayMicroseconds(1);
|
||||
this->sck_pin_->digital_write(false);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
namespace esphome {
|
||||
namespace hx711 {
|
||||
|
||||
enum HX711Gain : uint8_t {
|
||||
enum HX711Gain {
|
||||
HX711_GAIN_128 = 1,
|
||||
HX711_GAIN_32 = 2,
|
||||
HX711_GAIN_64 = 3,
|
||||
|
||||
@@ -33,15 +33,14 @@ enum SpeakerEventGroupBits : uint32_t {
|
||||
STATE_RUNNING = (1 << 11),
|
||||
STATE_STOPPING = (1 << 12),
|
||||
STATE_STOPPED = (1 << 13),
|
||||
ERR_TASK_FAILED_TO_START = (1 << 14),
|
||||
ERR_ESP_INVALID_STATE = (1 << 15),
|
||||
ERR_ESP_NOT_SUPPORTED = (1 << 16),
|
||||
ERR_INVALID_FORMAT = (1 << 14),
|
||||
ERR_TASK_FAILED_TO_START = (1 << 15),
|
||||
ERR_ESP_INVALID_STATE = (1 << 16),
|
||||
ERR_ESP_INVALID_ARG = (1 << 17),
|
||||
ERR_ESP_INVALID_SIZE = (1 << 18),
|
||||
ERR_ESP_NO_MEM = (1 << 19),
|
||||
ERR_ESP_FAIL = (1 << 20),
|
||||
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_ERR_ESP_BITS = ERR_ESP_INVALID_STATE | ERR_ESP_INVALID_ARG | ERR_ESP_INVALID_SIZE | ERR_ESP_NO_MEM | ERR_ESP_FAIL,
|
||||
ALL_BITS = 0x00FFFFFF, // All valid FreeRTOS event group bits
|
||||
};
|
||||
|
||||
@@ -56,8 +55,6 @@ static esp_err_t err_bit_to_esp_err(uint32_t bit) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
case SpeakerEventGroupBits::ERR_ESP_NO_MEM:
|
||||
return ESP_ERR_NO_MEM;
|
||||
case SpeakerEventGroupBits::ERR_ESP_NOT_SUPPORTED:
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
default:
|
||||
return ESP_FAIL;
|
||||
}
|
||||
@@ -138,19 +135,19 @@ void I2SAudioSpeaker::loop() {
|
||||
xEventGroupClearBits(this->event_group_, SpeakerEventGroupBits::ERR_TASK_FAILED_TO_START);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (event_group_bits & SpeakerEventGroupBits::ERR_INVALID_FORMAT) {
|
||||
this->status_set_error("Failed to adjust I2S bus to match the incoming audio");
|
||||
ESP_LOGE(TAG,
|
||||
"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_.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) {
|
||||
@@ -239,15 +236,13 @@ void I2SAudioSpeaker::speaker_task(void *params) {
|
||||
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STARTING);
|
||||
|
||||
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 uint32_t bytes_per_ms =
|
||||
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 dma_buffers_size = DMA_BUFFERS_COUNT * DMA_BUFFER_DURATION_MS * this_speaker->sample_rate_ / 1000 *
|
||||
bytes_per_sample * number_of_channels;
|
||||
const size_t ring_buffer_size =
|
||||
std::min((uint32_t) dma_buffers_size, this_speaker->buffer_duration_ms_ * bytes_per_ms);
|
||||
this_speaker->buffer_duration_ms_ * this_speaker->sample_rate_ / 1000 * bytes_per_sample * number_of_channels;
|
||||
|
||||
if (this_speaker->send_esp_err_to_event_group_(this_speaker->allocate_buffers_(dma_buffers_size, ring_buffer_size))) {
|
||||
// Failed to allocate buffers
|
||||
@@ -255,7 +250,14 @@ void I2SAudioSpeaker::speaker_task(void *params) {
|
||||
this_speaker->delete_task_(dma_buffers_size);
|
||||
}
|
||||
|
||||
if (!this_speaker->send_esp_err_to_event_group_(this_speaker->start_i2s_driver_(audio_stream_info))) {
|
||||
if (this_speaker->send_esp_err_to_event_group_(this_speaker->start_i2s_driver_())) {
|
||||
// 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);
|
||||
|
||||
bool stop_gracefully = false;
|
||||
@@ -273,12 +275,6 @@ void I2SAudioSpeaker::speaker_task(void *params) {
|
||||
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;
|
||||
while (xQueueReceive(this_speaker->i2s_event_queue_, &i2s_event, 0)) {
|
||||
if (i2s_event.type == I2S_EVENT_TX_Q_OVF) {
|
||||
@@ -320,14 +316,17 @@ void I2SAudioSpeaker::speaker_task(void *params) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STOPPING);
|
||||
|
||||
i2s_driver_uninstall(this_speaker->parent_->get_port());
|
||||
|
||||
this_speaker->parent_->unlock();
|
||||
} else {
|
||||
// Couldn't configure the I2S port to be compatible with the incoming audio
|
||||
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::ERR_INVALID_FORMAT);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -383,9 +382,6 @@ bool I2SAudioSpeaker::send_esp_err_to_event_group_(esp_err_t err) {
|
||||
case ESP_ERR_NO_MEM:
|
||||
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_NO_MEM);
|
||||
return true;
|
||||
case ESP_ERR_NOT_SUPPORTED:
|
||||
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_NOT_SUPPORTED);
|
||||
return true;
|
||||
default:
|
||||
xEventGroupSetBits(this->event_group_, SpeakerEventGroupBits::ERR_ESP_FAIL);
|
||||
return true;
|
||||
@@ -415,40 +411,18 @@ esp_err_t I2SAudioSpeaker::allocate_buffers_(size_t data_buffer_size, size_t rin
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
esp_err_t I2SAudioSpeaker::start_i2s_driver_() {
|
||||
if (!this->parent_->try_lock()) {
|
||||
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;
|
||||
|
||||
i2s_driver_config_t config = {
|
||||
.mode = (i2s_mode_t) (this->i2s_mode_ | I2S_MODE_TX),
|
||||
.sample_rate = audio_stream_info.sample_rate,
|
||||
.sample_rate = this->sample_rate_,
|
||||
.bits_per_sample = this->bits_per_sample_,
|
||||
.channel_format = channel,
|
||||
.channel_format = this->channel_,
|
||||
.communication_format = this->i2s_comm_fmt_,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
||||
.dma_buf_count = DMA_BUFFERS_COUNT,
|
||||
@@ -503,6 +477,30 @@ esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_strea
|
||||
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) {
|
||||
this->audio_ring_buffer_.reset(); // Releases onwership of the shared_ptr
|
||||
|
||||
|
||||
@@ -91,15 +91,24 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp
|
||||
esp_err_t allocate_buffers_(size_t data_buffer_size, size_t ring_buffer_size);
|
||||
|
||||
/// @brief Starts the ESP32 I2S driver.
|
||||
/// Attempts to lock the I2S port, starts the I2S driver using the passed in stream information, and sets the data out
|
||||
/// pin. If it fails, it will unlock the I2S port and uninstall the driver, if necessary.
|
||||
/// @param audio_stream_info Stream information for the I2S driver.
|
||||
/// @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.
|
||||
/// Attempts to lock the I2S port, starts the I2S driver, and sets the data out 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.
|
||||
/// ESP_ERR_INVALID_ARG if installing the driver or setting the data out pin fails due to a parameter 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_OK if successful
|
||||
esp_err_t start_i2s_driver_(audio::AudioStreamInfo &audio_stream_info);
|
||||
/// ESP_FAIL if setting the data out pin fails due to an IO error
|
||||
/// ESP_OK if successful
|
||||
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.
|
||||
/// 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
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import display, spi
|
||||
from esphome.components import display, font, spi
|
||||
from esphome.components.display import validate_rotation
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
@@ -147,6 +147,7 @@ def _validate(config):
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
font.validate_pillow_installed,
|
||||
display.FULL_DISPLAY_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(ILI9XXXDisplay),
|
||||
|
||||
@@ -313,9 +313,8 @@ void ILI9XXXDisplay::draw_pixels_at(int x_start, int y_start, int w, int h, cons
|
||||
// do color conversion pixel-by-pixel into the buffer and draw it later. If this is happening the user has not
|
||||
// configured the renderer well.
|
||||
if (this->rotation_ != display::DISPLAY_ROTATION_0_DEGREES || bitness != display::COLOR_BITNESS_565 || !big_endian) {
|
||||
display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset,
|
||||
x_pad);
|
||||
return;
|
||||
return display::Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset,
|
||||
x_pad);
|
||||
}
|
||||
this->set_addr_window_(x_start, y_start, x_start + w - 1, y_start + h - 1);
|
||||
// x_ and y_offset are offsets into the source buffer, unrelated to our own offsets into the display.
|
||||
|
||||
@@ -10,6 +10,7 @@ import puremagic
|
||||
|
||||
from esphome import core, external_files
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import font
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_DITHER,
|
||||
@@ -232,7 +233,7 @@ IMAGE_SCHEMA = cv.Schema(
|
||||
)
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = IMAGE_SCHEMA
|
||||
CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, IMAGE_SCHEMA)
|
||||
|
||||
|
||||
def load_svg_image(file: bytes, resize: tuple[int, int]):
|
||||
|
||||
@@ -47,7 +47,7 @@ void Logger::write_header_(int level, const char *tag, int line) {
|
||||
if (current_task == main_task_) {
|
||||
this->printf_to_buffer_("%s[%s][%s:%03u]: ", color, letter, tag, line);
|
||||
} else {
|
||||
const char *thread_name = ""; // NOLINT(clang-analyzer-deadcode.DeadStores)
|
||||
const char *thread_name = "";
|
||||
#if defined(USE_ESP32)
|
||||
thread_name = pcTaskGetName(current_task);
|
||||
#elif defined(USE_LIBRETINY)
|
||||
|
||||
@@ -23,7 +23,7 @@ bool operator==(const GainTimePair &lhs, const GainTimePair &rhs) {
|
||||
}
|
||||
|
||||
bool operator!=(const GainTimePair &lhs, const GainTimePair &rhs) {
|
||||
return lhs.gain != rhs.gain || lhs.time != rhs.time;
|
||||
return !(lhs.gain == rhs.gain && lhs.time == rhs.time);
|
||||
}
|
||||
|
||||
template<typename T, size_t size> T get_next(const T (&array)[size], const T val) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import logging
|
||||
|
||||
from esphome import codegen as cg, config_validation as cv
|
||||
from esphome.const import CONF_ITEMS
|
||||
from esphome.core import ID, Lambda
|
||||
from esphome.core import Lambda
|
||||
from esphome.cpp_generator import LambdaExpression, MockObj
|
||||
from esphome.cpp_types import uint32
|
||||
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
|
||||
@@ -72,12 +72,6 @@ class LValidator:
|
||||
)
|
||||
if self.retmapper is not None:
|
||||
return self.retmapper(value)
|
||||
if isinstance(value, ID):
|
||||
return await cg.get_variable(value)
|
||||
if isinstance(value, list):
|
||||
value = [
|
||||
await cg.get_variable(x) if isinstance(x, ID) else x for x in value
|
||||
]
|
||||
return cg.safe_exp(value)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from typing import Union
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import image
|
||||
from esphome.components.color import CONF_HEX, ColorStruct, from_rgbw
|
||||
from esphome.components.font import Font
|
||||
from esphome.components.image import Image_
|
||||
@@ -32,7 +31,7 @@ from .defines import (
|
||||
literal,
|
||||
)
|
||||
from .helpers import add_lv_use, esphome_fonts_used, lv_fonts_used, requires_component
|
||||
from .types import lv_font_t, lv_gradient_t
|
||||
from .types import lv_font_t, lv_gradient_t, lv_img_t
|
||||
|
||||
opacity_consts = LvConstant("LV_OPA_", "TRANSP", "COVER")
|
||||
|
||||
@@ -333,12 +332,8 @@ def image_validator(value):
|
||||
|
||||
lv_image = LValidator(
|
||||
image_validator,
|
||||
image.Image_.operator("ptr"),
|
||||
requires="image",
|
||||
)
|
||||
lv_image_list = LValidator(
|
||||
cv.ensure_list(image_validator),
|
||||
cg.std_vector.template(image.Image_.operator("ptr")),
|
||||
lv_img_t,
|
||||
retmapper=lambda x: MockObj(x, "->").get_lv_img_dsc(),
|
||||
requires="image",
|
||||
)
|
||||
lv_bool = LValidator(cv.boolean, cg.bool_, retmapper=literal)
|
||||
|
||||
@@ -279,7 +279,7 @@ std::string LvSelectable::get_selected_text() {
|
||||
static std::string join_string(std::vector<std::string> options) {
|
||||
return std::accumulate(
|
||||
options.begin(), options.end(), std::string(),
|
||||
[](const std::string &a, const std::string &b) -> std::string { return a + (!a.empty() ? "\n" : "") + b; });
|
||||
[](const std::string &a, const std::string &b) -> std::string { return a + (a.length() > 0 ? "\n" : "") + b; });
|
||||
}
|
||||
|
||||
void LvSelectable::set_selected_text(const std::string &text, lv_anim_enable_t anim) {
|
||||
|
||||
@@ -60,22 +60,6 @@ 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
|
||||
#ifdef USE_LVGL_ANIMIMG
|
||||
inline void lv_animimg_set_src(lv_obj_t *img, std::vector<image::Image *> images) {
|
||||
auto *dsc = static_cast<std::vector<lv_img_dsc_t *> *>(lv_obj_get_user_data(img));
|
||||
if (dsc == nullptr) {
|
||||
// object will be lazily allocated but never freed.
|
||||
dsc = new std::vector<lv_img_dsc_t *>(images.size()); // NOLINT
|
||||
lv_obj_set_user_data(img, dsc);
|
||||
}
|
||||
dsc->clear();
|
||||
for (auto &image : images) {
|
||||
dsc->push_back(image->get_lv_img_dsc());
|
||||
}
|
||||
lv_animimg_set_src(img, (const void **) dsc->data(), dsc->size());
|
||||
}
|
||||
|
||||
#endif // USE_LVGL_ANIMIMG
|
||||
|
||||
// Parent class for things that wrap an LVGL object
|
||||
class LvCompound {
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_DURATION, CONF_ID
|
||||
|
||||
from ..automation import action_to_code
|
||||
from ..defines import CONF_AUTO_START, CONF_MAIN, CONF_REPEAT_COUNT, CONF_SRC
|
||||
from ..helpers import lvgl_components_required
|
||||
from ..lv_validation import lv_image_list, lv_milliseconds
|
||||
from ..lv_validation import lv_image, lv_milliseconds
|
||||
from ..lvcode import lv
|
||||
from ..types import LvType, ObjUpdateAction
|
||||
from ..types import LvType, ObjUpdateAction, void_ptr
|
||||
from . import Widget, WidgetType, get_widgets
|
||||
from .img import CONF_IMAGE
|
||||
from .label import CONF_LABEL
|
||||
|
||||
CONF_ANIMIMG = "animimg"
|
||||
CONF_SRC_LIST_ID = "src_list_id"
|
||||
|
||||
|
||||
def lv_repeat_count(value):
|
||||
@@ -30,14 +32,14 @@ ANIMIMG_BASE_SCHEMA = cv.Schema(
|
||||
ANIMIMG_SCHEMA = ANIMIMG_BASE_SCHEMA.extend(
|
||||
{
|
||||
cv.Required(CONF_DURATION): lv_milliseconds,
|
||||
cv.Required(CONF_SRC): lv_image_list,
|
||||
cv.Required(CONF_SRC): cv.ensure_list(lv_image),
|
||||
cv.GenerateID(CONF_SRC_LIST_ID): cv.declare_id(void_ptr),
|
||||
}
|
||||
)
|
||||
|
||||
ANIMIMG_MODIFY_SCHEMA = ANIMIMG_BASE_SCHEMA.extend(
|
||||
{
|
||||
cv.Optional(CONF_DURATION): lv_milliseconds,
|
||||
cv.Optional(CONF_SRC): lv_image_list,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -57,14 +59,17 @@ class AnimimgType(WidgetType):
|
||||
async def to_code(self, w: Widget, config):
|
||||
lvgl_components_required.add(CONF_IMAGE)
|
||||
lvgl_components_required.add(CONF_ANIMIMG)
|
||||
if srcs := config.get(CONF_SRC):
|
||||
srcs = await lv_image_list.process(srcs)
|
||||
lv.animimg_set_src(w.obj, srcs)
|
||||
if repeat_count := config.get(CONF_REPEAT_COUNT):
|
||||
lv.animimg_set_repeat_count(w.obj, repeat_count)
|
||||
if duration := config.get(CONF_DURATION):
|
||||
lv.animimg_set_duration(w.obj, duration)
|
||||
if config[CONF_AUTO_START]:
|
||||
if CONF_SRC in config:
|
||||
srcs = [
|
||||
await lv_image.process(await cg.get_variable(x))
|
||||
for x in config[CONF_SRC]
|
||||
]
|
||||
src_id = cg.static_const_array(config[CONF_SRC_LIST_ID], srcs)
|
||||
count = len(config[CONF_SRC])
|
||||
lv.animimg_set_src(w.obj, src_id, count)
|
||||
lv.animimg_set_repeat_count(w.obj, config[CONF_REPEAT_COUNT])
|
||||
lv.animimg_set_duration(w.obj, config[CONF_DURATION])
|
||||
if config.get(CONF_AUTO_START):
|
||||
lv.animimg_start(w.obj)
|
||||
|
||||
def get_uses(self):
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ANGLE, CONF_MODE
|
||||
|
||||
@@ -64,6 +65,7 @@ class ImgType(WidgetType):
|
||||
|
||||
async def to_code(self, w: Widget, config):
|
||||
if src := config.get(CONF_SRC):
|
||||
src = await cg.get_variable(src)
|
||||
lv.img_set_src(w.obj, await lv_image.process(src))
|
||||
if (cf_angle := config.get(CONF_ANGLE)) is not None:
|
||||
pivot_x = config[CONF_PIVOT_X]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from esphome import automation, pins
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import key_provider
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, CONF_ON_KEY, CONF_PIN, CONF_TRIGGER_ID
|
||||
from esphome import pins
|
||||
from esphome.components import key_provider
|
||||
from esphome.const import CONF_ID, CONF_PIN
|
||||
|
||||
CODEOWNERS = ["@ssieb"]
|
||||
|
||||
@@ -14,9 +14,6 @@ matrix_keypad_ns = cg.esphome_ns.namespace("matrix_keypad")
|
||||
MatrixKeypad = matrix_keypad_ns.class_(
|
||||
"MatrixKeypad", key_provider.KeyProvider, cg.Component
|
||||
)
|
||||
MatrixKeyTrigger = matrix_keypad_ns.class_(
|
||||
"MatrixKeyTrigger", automation.Trigger.template(cg.uint8)
|
||||
)
|
||||
|
||||
CONF_KEYPAD_ID = "keypad_id"
|
||||
CONF_ROWS = "rows"
|
||||
@@ -50,11 +47,6 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Optional(CONF_DEBOUNCE_TIME, default=1): cv.int_range(min=1, max=100),
|
||||
cv.Optional(CONF_HAS_DIODES): cv.boolean,
|
||||
cv.Optional(CONF_HAS_PULLDOWNS): cv.boolean,
|
||||
cv.Optional(CONF_ON_KEY): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(MatrixKeyTrigger),
|
||||
}
|
||||
),
|
||||
}
|
||||
),
|
||||
check_keys,
|
||||
@@ -81,7 +73,3 @@ async def to_code(config):
|
||||
cg.add(var.set_has_diodes(config[CONF_HAS_DIODES]))
|
||||
if CONF_HAS_PULLDOWNS in config:
|
||||
cg.add(var.set_has_pulldowns(config[CONF_HAS_PULLDOWNS]))
|
||||
for conf in config.get(CONF_ON_KEY, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID])
|
||||
cg.add(var.register_key_trigger(trigger))
|
||||
await automation.build_automation(trigger, [(cg.uint8, "x")], conf)
|
||||
|
||||
@@ -86,8 +86,6 @@ void MatrixKeypad::loop() {
|
||||
if (!this->keys_.empty()) {
|
||||
uint8_t keycode = this->keys_[key];
|
||||
ESP_LOGD(TAG, "key '%c' pressed", keycode);
|
||||
for (auto &trigger : this->key_triggers_)
|
||||
trigger->trigger(keycode);
|
||||
for (auto &listener : this->listeners_)
|
||||
listener->key_pressed(keycode);
|
||||
this->send_key_(keycode);
|
||||
@@ -109,7 +107,5 @@ void MatrixKeypad::dump_config() {
|
||||
|
||||
void MatrixKeypad::register_listener(MatrixKeypadListener *listener) { this->listeners_.push_back(listener); }
|
||||
|
||||
void MatrixKeypad::register_key_trigger(MatrixKeyTrigger *trig) { this->key_triggers_.push_back(trig); }
|
||||
|
||||
} // namespace matrix_keypad
|
||||
} // namespace esphome
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/components/key_provider/key_provider.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
@@ -19,8 +18,6 @@ class MatrixKeypadListener {
|
||||
virtual void key_released(uint8_t key){};
|
||||
};
|
||||
|
||||
class MatrixKeyTrigger : public Trigger<uint8_t> {};
|
||||
|
||||
class MatrixKeypad : public key_provider::KeyProvider, public Component {
|
||||
public:
|
||||
void setup() override;
|
||||
@@ -34,7 +31,6 @@ class MatrixKeypad : public key_provider::KeyProvider, public Component {
|
||||
void set_has_pulldowns(int has_pulldowns) { has_pulldowns_ = has_pulldowns; };
|
||||
|
||||
void register_listener(MatrixKeypadListener *listener);
|
||||
void register_key_trigger(MatrixKeyTrigger *trig);
|
||||
|
||||
protected:
|
||||
std::vector<GPIOPin *> rows_;
|
||||
@@ -46,7 +42,6 @@ class MatrixKeypad : public key_provider::KeyProvider, public Component {
|
||||
int pressed_key_ = -1;
|
||||
|
||||
std::vector<MatrixKeypadListener *> listeners_{};
|
||||
std::vector<MatrixKeyTrigger *> key_triggers_;
|
||||
};
|
||||
|
||||
} // namespace matrix_keypad
|
||||
|
||||
@@ -106,8 +106,7 @@ void MAX31865Sensor::read_data_() {
|
||||
|
||||
// Check faults
|
||||
const uint8_t faults = this->read_register_(FAULT_STATUS_REG);
|
||||
has_fault_ = faults & 0b00111100;
|
||||
if (has_fault_) {
|
||||
if ((has_fault_ = faults & 0b00111100)) {
|
||||
if (faults & (1 << 2)) {
|
||||
ESP_LOGE(TAG, "Overvoltage/undervoltage fault");
|
||||
}
|
||||
@@ -126,8 +125,7 @@ void MAX31865Sensor::read_data_() {
|
||||
} else {
|
||||
this->status_clear_error();
|
||||
}
|
||||
has_warn_ = faults & 0b11000000;
|
||||
if (has_warn_) {
|
||||
if ((has_warn_ = faults & 0b11000000)) {
|
||||
if (faults & (1 << 6)) {
|
||||
ESP_LOGW(TAG, "RTD Low Threshold");
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
auto reg_it = find_if(begin(this->register_ranges_), end(this->register_ranges_), [=](RegisterRange const &r) {
|
||||
auto reg_it = find_if(begin(register_ranges_), end(register_ranges_), [=](RegisterRange const &r) {
|
||||
return (r.start_address == start_address && r.register_type == register_type);
|
||||
});
|
||||
|
||||
if (reg_it == this->register_ranges_.end()) {
|
||||
if (reg_it == register_ranges_.end()) {
|
||||
ESP_LOGE(TAG, "No matching range for sensor found - start_address : 0x%X", start_address);
|
||||
} else {
|
||||
return reg_it->sensors;
|
||||
@@ -240,18 +240,18 @@ void ModbusController::update() {
|
||||
|
||||
// walk through the sensors and determine the register ranges to read
|
||||
size_t ModbusController::create_register_ranges_() {
|
||||
this->register_ranges_.clear();
|
||||
if (this->parent_->role == modbus::ModbusRole::CLIENT && this->sensorset_.empty()) {
|
||||
register_ranges_.clear();
|
||||
if (this->parent_->role == modbus::ModbusRole::CLIENT && sensorset_.empty()) {
|
||||
ESP_LOGW(TAG, "No sensors registered");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// iterator is sorted see SensorItemsComparator for details
|
||||
auto ix = this->sensorset_.begin();
|
||||
auto ix = sensorset_.begin();
|
||||
RegisterRange r = {};
|
||||
uint8_t buffer_offset = 0;
|
||||
SensorItem *prev = nullptr;
|
||||
while (ix != this->sensorset_.end()) {
|
||||
while (ix != sensorset_.end()) {
|
||||
SensorItem *curr = *ix;
|
||||
|
||||
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
|
||||
|
||||
// remove this sensore because start_address is changed (sort-order)
|
||||
ix = this->sensorset_.erase(ix);
|
||||
ix = sensorset_.erase(ix);
|
||||
|
||||
curr->start_address = r.start_address;
|
||||
curr->offset += prev->offset;
|
||||
|
||||
this->sensorset_.insert(curr);
|
||||
sensorset_.insert(curr);
|
||||
// move iterator backwards because it will be incremented later
|
||||
ix--;
|
||||
|
||||
@@ -293,14 +293,14 @@ size_t ModbusController::create_register_ranges_() {
|
||||
// this register can extend the current range
|
||||
|
||||
// remove this sensore because start_address is changed (sort-order)
|
||||
ix = this->sensorset_.erase(ix);
|
||||
ix = sensorset_.erase(ix);
|
||||
|
||||
curr->start_address = r.start_address;
|
||||
curr->offset += buffer_offset;
|
||||
buffer_offset += curr->get_register_size();
|
||||
r.register_count += curr->register_count;
|
||||
|
||||
this->sensorset_.insert(curr);
|
||||
sensorset_.insert(curr);
|
||||
// move iterator backwards because it will be incremented later
|
||||
ix--;
|
||||
|
||||
@@ -327,7 +327,7 @@ size_t ModbusController::create_register_ranges_() {
|
||||
ix++;
|
||||
} else {
|
||||
ESP_LOGV(TAG, "Add range 0x%X %d skip:%d", r.start_address, r.register_count, r.skip_updates);
|
||||
this->register_ranges_.push_back(r);
|
||||
register_ranges_.push_back(r);
|
||||
r = {};
|
||||
buffer_offset = 0;
|
||||
// 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) {
|
||||
// Add the last range
|
||||
ESP_LOGV(TAG, "Add last range 0x%X %d skip:%d", r.start_address, r.register_count, r.skip_updates);
|
||||
this->register_ranges_.push_back(r);
|
||||
register_ranges_.push_back(r);
|
||||
}
|
||||
|
||||
return this->register_ranges_.size();
|
||||
return register_ranges_.size();
|
||||
}
|
||||
|
||||
void ModbusController::dump_config() {
|
||||
@@ -352,18 +352,18 @@ void ModbusController::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, " Offline Skip Updates: %d", this->offline_skip_updates_);
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
ESP_LOGCONFIG(TAG, "sensormap");
|
||||
for (auto &it : this->sensorset_) {
|
||||
for (auto &it : sensorset_) {
|
||||
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,
|
||||
it->get_register_size());
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, "ranges");
|
||||
for (auto &it : this->register_ranges_) {
|
||||
for (auto &it : register_ranges_) {
|
||||
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);
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, "server registers");
|
||||
for (auto &r : this->server_registers_) {
|
||||
for (auto &r : server_registers_) {
|
||||
ESP_LOGCONFIG(TAG, " Address=0x%02X value_type=%zu register_count=%u", r->address,
|
||||
static_cast<uint8_t>(r->value_type), r->register_count);
|
||||
}
|
||||
@@ -372,11 +372,11 @@ void ModbusController::dump_config() {
|
||||
|
||||
void ModbusController::loop() {
|
||||
// Incoming data to process?
|
||||
if (!this->incoming_queue_.empty()) {
|
||||
auto &message = this->incoming_queue_.front();
|
||||
if (!incoming_queue_.empty()) {
|
||||
auto &message = incoming_queue_.front();
|
||||
if (message != nullptr)
|
||||
process_modbus_data_(message.get());
|
||||
this->incoming_queue_.pop();
|
||||
incoming_queue_.pop();
|
||||
|
||||
} else {
|
||||
// all messages processed send pending commands
|
||||
@@ -391,7 +391,7 @@ void ModbusController::on_write_register_response(ModbusRegisterType register_ty
|
||||
|
||||
void ModbusController::dump_sensors_() {
|
||||
ESP_LOGV(TAG, "sensors");
|
||||
for (auto &it : this->sensorset_) {
|
||||
for (auto &it : sensorset_) {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -240,14 +240,14 @@ class SensorItem {
|
||||
}
|
||||
// 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; }
|
||||
ModbusRegisterType register_type{ModbusRegisterType::CUSTOM};
|
||||
SensorValueType sensor_value_type{SensorValueType::RAW};
|
||||
uint16_t start_address{0};
|
||||
uint32_t bitmask{0};
|
||||
uint8_t offset{0};
|
||||
uint8_t register_count{0};
|
||||
ModbusRegisterType register_type;
|
||||
SensorValueType sensor_value_type;
|
||||
uint16_t start_address;
|
||||
uint32_t bitmask;
|
||||
uint8_t offset;
|
||||
uint8_t register_count;
|
||||
uint8_t response_bytes{0};
|
||||
uint16_t skip_updates{0};
|
||||
uint16_t skip_updates;
|
||||
std::vector<uint8_t> custom_data{};
|
||||
bool force_new_range{false};
|
||||
};
|
||||
@@ -261,9 +261,9 @@ class ServerRegister {
|
||||
this->register_count = register_count;
|
||||
this->read_lambda = std::move(read_lambda);
|
||||
}
|
||||
uint16_t address{0};
|
||||
SensorValueType value_type{SensorValueType::RAW};
|
||||
uint8_t register_count{0};
|
||||
uint16_t address;
|
||||
SensorValueType value_type;
|
||||
uint8_t register_count;
|
||||
std::function<float()> read_lambda;
|
||||
};
|
||||
|
||||
@@ -312,11 +312,11 @@ struct RegisterRange {
|
||||
class ModbusCommandItem {
|
||||
public:
|
||||
static const size_t MAX_PAYLOAD_BYTES = 240;
|
||||
ModbusController *modbusdevice{nullptr};
|
||||
uint16_t register_address{0};
|
||||
uint16_t register_count{0};
|
||||
ModbusFunctionCode function_code{ModbusFunctionCode::CUSTOM};
|
||||
ModbusRegisterType register_type{ModbusRegisterType::CUSTOM};
|
||||
ModbusController *modbusdevice;
|
||||
uint16_t register_address;
|
||||
uint16_t register_count;
|
||||
ModbusFunctionCode function_code;
|
||||
ModbusRegisterType register_type;
|
||||
std::function<void(ModbusRegisterType register_type, uint16_t start_address, const std::vector<uint8_t> &data)>
|
||||
on_data_func;
|
||||
std::vector<uint8_t> payload = {};
|
||||
@@ -493,23 +493,23 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice {
|
||||
/// Collection of all sensors for this component
|
||||
SensorSet sensorset_;
|
||||
/// Collection of all server registers for this component
|
||||
std::vector<ServerRegister *> server_registers_{};
|
||||
std::vector<ServerRegister *> server_registers_;
|
||||
/// Continuous range of modbus registers
|
||||
std::vector<RegisterRange> register_ranges_{};
|
||||
std::vector<RegisterRange> register_ranges_;
|
||||
/// Hold the pending requests to be sent
|
||||
std::list<std::unique_ptr<ModbusCommandItem>> command_queue_;
|
||||
/// modbus response data waiting to get processed
|
||||
std::queue<std::unique_ptr<ModbusCommandItem>> incoming_queue_;
|
||||
/// if duplicate commands can be sent
|
||||
bool allow_duplicate_commands_{false};
|
||||
bool allow_duplicate_commands_;
|
||||
/// when was the last send operation
|
||||
uint32_t last_command_timestamp_{0};
|
||||
uint32_t last_command_timestamp_;
|
||||
/// min time in ms between sending modbus commands
|
||||
uint16_t command_throttle_{0};
|
||||
uint16_t command_throttle_;
|
||||
/// if module didn't respond the last command
|
||||
bool module_offline_{false};
|
||||
bool module_offline_;
|
||||
/// how many updates to skip if module is offline
|
||||
uint16_t offline_skip_updates_{0};
|
||||
uint16_t offline_skip_updates_;
|
||||
/// How many times we will retry a command if we get no response
|
||||
uint8_t max_cmd_retries_{4};
|
||||
/// Command sent callback
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace modbus_controller {
|
||||
static const char *const TAG = "modbus.number";
|
||||
|
||||
void ModbusNumber::parse_and_publish(const std::vector<uint8_t> &data) {
|
||||
float result = payload_to_float(data, *this) / this->multiply_by_;
|
||||
float result = payload_to_float(data, *this) / multiply_by_;
|
||||
|
||||
// Is there a lambda registered
|
||||
// call it with the pre converted value and the raw data array
|
||||
@@ -43,7 +43,7 @@ void ModbusNumber::control(float value) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
write_value = this->multiply_by_ * write_value;
|
||||
write_value = multiply_by_ * write_value;
|
||||
}
|
||||
|
||||
if (!data.empty()) {
|
||||
@@ -63,21 +63,21 @@ void ModbusNumber::control(float value) {
|
||||
// Create and send the write command
|
||||
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
|
||||
write_cmd = ModbusCommandItem::create_write_single_command(this->parent_, this->start_address + this->offset / 2,
|
||||
data[0]);
|
||||
write_cmd =
|
||||
ModbusCommandItem::create_write_single_command(parent_, this->start_address + this->offset / 2, data[0]);
|
||||
} else {
|
||||
write_cmd = ModbusCommandItem::create_write_multiple_command(
|
||||
this->parent_, this->start_address + this->offset / 2, this->register_count, data);
|
||||
write_cmd = ModbusCommandItem::create_write_multiple_command(parent_, this->start_address + this->offset / 2,
|
||||
this->register_count, data);
|
||||
}
|
||||
// publish new value
|
||||
write_cmd.on_data_func = [this, write_cmd, value](ModbusRegisterType register_type, uint16_t start_address,
|
||||
const std::vector<uint8_t> &data) {
|
||||
// gets called when the write command is ack'd from the device
|
||||
this->parent_->on_write_register_response(write_cmd.register_type, start_address, data);
|
||||
parent_->on_write_register_response(write_cmd.register_type, start_address, data);
|
||||
this->publish_state(value);
|
||||
};
|
||||
}
|
||||
this->parent_->queue_command(write_cmd);
|
||||
parent_->queue_command(write_cmd);
|
||||
this->publish_state(value);
|
||||
}
|
||||
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;
|
||||
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
||||
void set_parent(ModbusController *parent) { this->parent_ = parent; }
|
||||
void set_write_multiply(float factor) { this->multiply_by_ = factor; }
|
||||
void set_write_multiply(float factor) { multiply_by_ = factor; }
|
||||
|
||||
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> &)>;
|
||||
@@ -39,9 +39,9 @@ class ModbusNumber : public number::Number, public Component, public SensorItem
|
||||
|
||||
protected:
|
||||
void control(float value) override;
|
||||
optional<transform_func_t> transform_func_{nullopt};
|
||||
optional<write_transform_func_t> write_transform_func_{nullopt};
|
||||
ModbusController *parent_{nullptr};
|
||||
optional<transform_func_t> transform_func_;
|
||||
optional<write_transform_func_t> write_transform_func_;
|
||||
ModbusController *parent_;
|
||||
float multiply_by_{1.0};
|
||||
bool use_write_multiple_{false};
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ void ModbusFloatOutput::write_state(float value) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
value = this->multiply_by_ * value;
|
||||
value = multiply_by_ * value;
|
||||
}
|
||||
// lambda didn't set payload
|
||||
if (data.empty()) {
|
||||
@@ -40,13 +40,12 @@ void ModbusFloatOutput::write_state(float value) {
|
||||
// Create and send the write command
|
||||
ModbusCommandItem write_cmd;
|
||||
if (this->register_count == 1 && !this->use_write_multiple_) {
|
||||
write_cmd =
|
||||
ModbusCommandItem::create_write_single_command(this->parent_, this->start_address + this->offset, data[0]);
|
||||
write_cmd = ModbusCommandItem::create_write_single_command(parent_, this->start_address + this->offset, data[0]);
|
||||
} else {
|
||||
write_cmd = ModbusCommandItem::create_write_multiple_command(this->parent_, this->start_address + this->offset,
|
||||
write_cmd = ModbusCommandItem::create_write_multiple_command(parent_, this->start_address + this->offset,
|
||||
this->register_count, data);
|
||||
}
|
||||
this->parent_->queue_command(write_cmd);
|
||||
parent_->queue_command(write_cmd);
|
||||
}
|
||||
|
||||
void ModbusFloatOutput::dump_config() {
|
||||
@@ -91,9 +90,9 @@ void ModbusBinaryOutput::write_state(bool state) {
|
||||
// offset for coil and discrete inputs is the coil/register number not bytes
|
||||
if (this->use_write_multiple_) {
|
||||
std::vector<bool> states{state};
|
||||
cmd = ModbusCommandItem::create_write_multiple_coils(this->parent_, this->start_address + this->offset, states);
|
||||
cmd = ModbusCommandItem::create_write_multiple_coils(parent_, this->start_address + this->offset, states);
|
||||
} else {
|
||||
cmd = ModbusCommandItem::create_write_single_coil(this->parent_, this->start_address + this->offset, state);
|
||||
cmd = ModbusCommandItem::create_write_single_coil(parent_, this->start_address + this->offset, state);
|
||||
}
|
||||
}
|
||||
this->parent_->queue_command(cmd);
|
||||
|
||||
@@ -25,7 +25,7 @@ class ModbusFloatOutput : public output::FloatOutput, public Component, public S
|
||||
void dump_config() override;
|
||||
|
||||
void set_parent(ModbusController *parent) { this->parent_ = parent; }
|
||||
void set_write_multiply(float factor) { this->multiply_by_ = factor; }
|
||||
void set_write_multiply(float factor) { multiply_by_ = factor; }
|
||||
// Do nothing
|
||||
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;
|
||||
optional<write_transform_func_t> write_transform_func_{nullopt};
|
||||
|
||||
ModbusController *parent_{nullptr};
|
||||
ModbusController *parent_;
|
||||
float multiply_by_{1.0};
|
||||
bool use_write_multiple_{false};
|
||||
bool use_write_multiple_;
|
||||
};
|
||||
|
||||
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;
|
||||
optional<write_transform_func_t> write_transform_func_{nullopt};
|
||||
|
||||
ModbusController *parent_{nullptr};
|
||||
bool use_write_multiple_{false};
|
||||
ModbusController *parent_;
|
||||
bool use_write_multiple_;
|
||||
};
|
||||
|
||||
} // namespace modbus_controller
|
||||
|
||||
@@ -74,13 +74,12 @@ void ModbusSelect::control(const std::string &value) {
|
||||
const uint16_t write_address = this->start_address + this->offset / 2;
|
||||
ModbusCommandItem write_cmd;
|
||||
if ((this->register_count == 1) && (!this->use_write_multiple_)) {
|
||||
write_cmd = ModbusCommandItem::create_write_single_command(this->parent_, write_address, data[0]);
|
||||
write_cmd = ModbusCommandItem::create_write_single_command(parent_, write_address, data[0]);
|
||||
} else {
|
||||
write_cmd =
|
||||
ModbusCommandItem::create_write_multiple_command(this->parent_, write_address, this->register_count, data);
|
||||
write_cmd = ModbusCommandItem::create_write_multiple_command(parent_, write_address, this->register_count, data);
|
||||
}
|
||||
|
||||
this->parent_->queue_command(write_cmd);
|
||||
parent_->queue_command(write_cmd);
|
||||
|
||||
if (this->optimistic_)
|
||||
this->publish_state(value);
|
||||
|
||||
@@ -42,12 +42,12 @@ class ModbusSelect : public Component, public select::Select, public SensorItem
|
||||
void control(const std::string &value) override;
|
||||
|
||||
protected:
|
||||
std::vector<int64_t> mapping_{};
|
||||
ModbusController *parent_{nullptr};
|
||||
std::vector<int64_t> mapping_;
|
||||
ModbusController *parent_;
|
||||
bool use_write_multiple_{false};
|
||||
bool optimistic_{false};
|
||||
optional<transform_func_t> transform_func_{nullopt};
|
||||
optional<write_transform_func_t> write_transform_func_{nullopt};
|
||||
optional<transform_func_t> transform_func_;
|
||||
optional<write_transform_func_t> write_transform_func_;
|
||||
};
|
||||
|
||||
} // namespace modbus_controller
|
||||
|
||||
@@ -80,18 +80,18 @@ void ModbusSwitch::write_state(bool state) {
|
||||
// offset for coil and discrete inputs is the coil/register number not bytes
|
||||
if (this->use_write_multiple_) {
|
||||
std::vector<bool> states{state};
|
||||
cmd = ModbusCommandItem::create_write_multiple_coils(this->parent_, this->start_address + this->offset, states);
|
||||
cmd = ModbusCommandItem::create_write_multiple_coils(parent_, this->start_address + this->offset, states);
|
||||
} else {
|
||||
cmd = ModbusCommandItem::create_write_single_coil(this->parent_, this->start_address + this->offset, state);
|
||||
cmd = ModbusCommandItem::create_write_single_coil(parent_, this->start_address + this->offset, state);
|
||||
}
|
||||
} else {
|
||||
// since offset is in bytes and a register is 16 bits we get the start by adding offset/2
|
||||
if (this->use_write_multiple_) {
|
||||
std::vector<uint16_t> bool_states(1, state ? (0xFFFF & this->bitmask) : 0);
|
||||
cmd = ModbusCommandItem::create_write_multiple_command(this->parent_, this->start_address + this->offset / 2, 1,
|
||||
cmd = ModbusCommandItem::create_write_multiple_command(parent_, this->start_address + this->offset / 2, 1,
|
||||
bool_states);
|
||||
} else {
|
||||
cmd = ModbusCommandItem::create_write_single_command(this->parent_, this->start_address + this->offset / 2,
|
||||
cmd = ModbusCommandItem::create_write_single_command(parent_, this->start_address + this->offset / 2,
|
||||
state ? 0xFFFF & this->bitmask : 0u);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
protected:
|
||||
ModbusController *parent_{nullptr};
|
||||
bool use_write_multiple_{false};
|
||||
ModbusController *parent_;
|
||||
bool use_write_multiple_;
|
||||
optional<transform_func_t> publish_transform_func_{nullopt};
|
||||
optional<write_transform_func_t> write_transform_func_{nullopt};
|
||||
};
|
||||
|
||||
@@ -49,7 +49,6 @@ from esphome.const import (
|
||||
CONF_USE_ABBREVIATIONS,
|
||||
CONF_USERNAME,
|
||||
CONF_WILL_MESSAGE,
|
||||
CONF_PUBLISH_NAN_AS_NONE,
|
||||
PLATFORM_BK72XX,
|
||||
PLATFORM_ESP32,
|
||||
PLATFORM_ESP8266,
|
||||
@@ -297,7 +296,6 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Optional(CONF_QOS, default=0): cv.mqtt_qos,
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_PUBLISH_NAN_AS_NONE, default=False): cv.boolean,
|
||||
}
|
||||
),
|
||||
validate_config,
|
||||
@@ -451,8 +449,6 @@ async def to_code(config):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
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(
|
||||
{
|
||||
|
||||
@@ -80,7 +80,8 @@ const EntityBase *MQTTAlarmControlPanelComponent::get_entity() const { return th
|
||||
|
||||
bool MQTTAlarmControlPanelComponent::send_initial_state() { return this->publish_state(); }
|
||||
bool MQTTAlarmControlPanelComponent::publish_state() {
|
||||
const char *state_s;
|
||||
bool success = true;
|
||||
const char *state_s = "";
|
||||
switch (this->alarm_control_panel_->get_state()) {
|
||||
case ACP_STATE_DISARMED:
|
||||
state_s = "disarmed";
|
||||
@@ -115,7 +116,9 @@ bool MQTTAlarmControlPanelComponent::publish_state() {
|
||||
default:
|
||||
state_s = "unknown";
|
||||
}
|
||||
return this->publish(this->get_state_topic_(), state_s);
|
||||
if (!this->publish(this->get_state_topic_(), state_s))
|
||||
success = false;
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace mqtt
|
||||
|
||||
@@ -151,11 +151,11 @@ void MQTTBackendESP32::mqtt_event_handler_(const Event &event) {
|
||||
break;
|
||||
case MQTT_EVENT_DATA: {
|
||||
static std::string topic;
|
||||
if (!event.topic.empty()) {
|
||||
if (event.topic.length() > 0) {
|
||||
topic = event.topic;
|
||||
}
|
||||
ESP_LOGV(TAG, "MQTT_EVENT_DATA %s", topic.c_str());
|
||||
this->on_message_.call(!event.topic.empty() ? topic.c_str() : nullptr, event.data.data(), event.data.size(),
|
||||
this->on_message_.call(event.topic.length() > 0 ? topic.c_str() : nullptr, event.data.data(), event.data.size(),
|
||||
event.current_data_offset, event.total_data_len);
|
||||
} break;
|
||||
case MQTT_EVENT_ERROR:
|
||||
@@ -184,7 +184,7 @@ void MQTTBackendESP32::mqtt_event_handler(void *handler_args, esp_event_base_t b
|
||||
// queue event to decouple processing
|
||||
if (instance) {
|
||||
auto event = *static_cast<esp_mqtt_event_t *>(event_data);
|
||||
instance->mqtt_events_.emplace(event);
|
||||
instance->mqtt_events_.push(Event(event));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -608,10 +608,6 @@ void MQTTClientComponent::set_log_message_template(MQTTMessage &&message) { this
|
||||
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; }
|
||||
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() {
|
||||
this->birth_message_.topic = "";
|
||||
this->recalculate_availability_();
|
||||
|
||||
@@ -263,10 +263,6 @@ class MQTTClientComponent : public Component {
|
||||
void set_on_connect(mqtt_on_connect_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:
|
||||
void send_device_info_();
|
||||
|
||||
@@ -332,8 +328,6 @@ class MQTTClientComponent : public Component {
|
||||
uint32_t connect_begin_;
|
||||
uint32_t last_connected_{0};
|
||||
optional<MQTTClientDisconnectReason> disconnect_reason_{};
|
||||
|
||||
bool publish_nan_as_none_{false};
|
||||
};
|
||||
|
||||
extern MQTTClientComponent *global_mqtt_client; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
@@ -257,7 +257,7 @@ const EntityBase *MQTTClimateComponent::get_entity() const { return this->device
|
||||
bool MQTTClimateComponent::publish_state_() {
|
||||
auto traits = this->device_->get_traits();
|
||||
// mode
|
||||
const char *mode_s;
|
||||
const char *mode_s = "";
|
||||
switch (this->device_->mode) {
|
||||
case CLIMATE_MODE_OFF:
|
||||
mode_s = "off";
|
||||
@@ -280,8 +280,6 @@ bool MQTTClimateComponent::publish_state_() {
|
||||
case CLIMATE_MODE_HEAT_COOL:
|
||||
mode_s = "heat_cool";
|
||||
break;
|
||||
default:
|
||||
mode_s = "unknown";
|
||||
}
|
||||
bool success = true;
|
||||
if (!this->publish(this->get_mode_state_topic(), mode_s))
|
||||
@@ -345,8 +343,6 @@ bool MQTTClimateComponent::publish_state_() {
|
||||
case CLIMATE_PRESET_ACTIVITY:
|
||||
payload = "activity";
|
||||
break;
|
||||
default:
|
||||
payload = "unknown";
|
||||
}
|
||||
}
|
||||
if (this->device_->custom_preset.has_value())
|
||||
@@ -356,7 +352,7 @@ bool MQTTClimateComponent::publish_state_() {
|
||||
}
|
||||
|
||||
if (traits.get_supports_action()) {
|
||||
const char *payload;
|
||||
const char *payload = "unknown";
|
||||
switch (this->device_->action) {
|
||||
case CLIMATE_ACTION_OFF:
|
||||
payload = "off";
|
||||
@@ -376,8 +372,6 @@ bool MQTTClimateComponent::publish_state_() {
|
||||
case CLIMATE_ACTION_FAN:
|
||||
payload = "fan";
|
||||
break;
|
||||
default:
|
||||
payload = "unknown";
|
||||
}
|
||||
if (!this->publish(this->get_action_state_topic(), payload))
|
||||
success = false;
|
||||
@@ -417,8 +411,6 @@ bool MQTTClimateComponent::publish_state_() {
|
||||
case CLIMATE_FAN_QUIET:
|
||||
payload = "quiet";
|
||||
break;
|
||||
default:
|
||||
payload = "unknown";
|
||||
}
|
||||
}
|
||||
if (this->device_->custom_fan_mode.has_value())
|
||||
@@ -428,7 +420,7 @@ bool MQTTClimateComponent::publish_state_() {
|
||||
}
|
||||
|
||||
if (traits.get_supports_swing_modes()) {
|
||||
const char *payload;
|
||||
const char *payload = "";
|
||||
switch (this->device_->swing_mode) {
|
||||
case CLIMATE_SWING_OFF:
|
||||
payload = "off";
|
||||
@@ -442,8 +434,6 @@ bool MQTTClimateComponent::publish_state_() {
|
||||
case CLIMATE_SWING_HORIZONTAL:
|
||||
payload = "horizontal";
|
||||
break;
|
||||
default:
|
||||
payload = "unknown";
|
||||
}
|
||||
if (!this->publish(this->get_swing_mode_state_topic(), payload))
|
||||
success = false;
|
||||
|
||||
@@ -69,8 +69,6 @@ bool MQTTSensorComponent::send_initial_state() {
|
||||
}
|
||||
}
|
||||
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();
|
||||
return this->publish(this->get_state_topic_(), value_accuracy_to_string(value, accuracy));
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ struct IPAddress {
|
||||
operator arduino_ns::IPAddress() const { return ip_addr_get_ip4_u32(&ip_addr_); }
|
||||
#endif
|
||||
|
||||
bool is_set() { return !ip_addr_isany(&ip_addr_); } // NOLINT(readability-simplify-boolean-expr)
|
||||
bool is_set() { return !ip_addr_isany(&ip_addr_); }
|
||||
bool is_ip4() { return IP_IS_V4(&ip_addr_); }
|
||||
bool is_ip6() { return IP_IS_V6(&ip_addr_); }
|
||||
std::string str() const { return str_lower_case(ipaddr_ntoa(&ip_addr_)); }
|
||||
|
||||
@@ -6,5 +6,3 @@ Nextion = nextion_ns.class_("Nextion", cg.PollingComponent, uart.UARTDevice)
|
||||
nextion_ref = Nextion.operator("ref")
|
||||
|
||||
CONF_NEXTION_ID = "nextion_id"
|
||||
CONF_PUBLISH_STATE = "publish_state"
|
||||
CONF_SEND_TO_NEXTION = "send_to_nextion"
|
||||
|
||||
@@ -5,13 +5,6 @@
|
||||
namespace esphome {
|
||||
namespace nextion {
|
||||
|
||||
class BufferOverflowTrigger : public Trigger<> {
|
||||
public:
|
||||
explicit BufferOverflowTrigger(Nextion *nextion) {
|
||||
nextion->add_buffer_overflow_event_callback([this]() { this->trigger(); });
|
||||
}
|
||||
};
|
||||
|
||||
class SetupTrigger : public Trigger<> {
|
||||
public:
|
||||
explicit SetupTrigger(Nextion *nextion) {
|
||||
@@ -49,74 +42,5 @@ class TouchTrigger : public Trigger<uint8_t, uint8_t, bool> {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Ts> class NextionPublishFloatAction : public Action<Ts...> {
|
||||
public:
|
||||
explicit NextionPublishFloatAction(NextionComponent *component) : component_(component) {}
|
||||
|
||||
TEMPLATABLE_VALUE(float, state)
|
||||
TEMPLATABLE_VALUE(bool, publish_state)
|
||||
TEMPLATABLE_VALUE(bool, send_to_nextion)
|
||||
|
||||
void play(Ts... x) override {
|
||||
this->component_->set_state(this->state_.value(x...), this->publish_state_.value(x...),
|
||||
this->send_to_nextion_.value(x...));
|
||||
}
|
||||
|
||||
void set_state(std::function<void(Ts..., float)> state) { this->state_ = state; }
|
||||
void set_publish_state(std::function<void(Ts..., bool)> publish_state) { this->publish_state_ = publish_state; }
|
||||
void set_send_to_nextion(std::function<void(Ts..., bool)> send_to_nextion) {
|
||||
this->send_to_nextion_ = send_to_nextion;
|
||||
}
|
||||
|
||||
protected:
|
||||
NextionComponent *component_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class NextionPublishTextAction : public Action<Ts...> {
|
||||
public:
|
||||
explicit NextionPublishTextAction(NextionComponent *component) : component_(component) {}
|
||||
|
||||
TEMPLATABLE_VALUE(const char *, state)
|
||||
TEMPLATABLE_VALUE(bool, publish_state)
|
||||
TEMPLATABLE_VALUE(bool, send_to_nextion)
|
||||
|
||||
void play(Ts... x) override {
|
||||
this->component_->set_state(this->state_.value(x...), this->publish_state_.value(x...),
|
||||
this->send_to_nextion_.value(x...));
|
||||
}
|
||||
|
||||
void set_state(std::function<void(Ts..., const char *)> state) { this->state_ = state; }
|
||||
void set_publish_state(std::function<void(Ts..., bool)> publish_state) { this->publish_state_ = publish_state; }
|
||||
void set_send_to_nextion(std::function<void(Ts..., bool)> send_to_nextion) {
|
||||
this->send_to_nextion_ = send_to_nextion;
|
||||
}
|
||||
|
||||
protected:
|
||||
NextionComponent *component_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class NextionPublishBoolAction : public Action<Ts...> {
|
||||
public:
|
||||
explicit NextionPublishBoolAction(NextionComponent *component) : component_(component) {}
|
||||
|
||||
TEMPLATABLE_VALUE(bool, state)
|
||||
TEMPLATABLE_VALUE(bool, publish_state)
|
||||
TEMPLATABLE_VALUE(bool, send_to_nextion)
|
||||
|
||||
void play(Ts... x) override {
|
||||
this->component_->set_state(this->state_.value(x...), this->publish_state_.value(x...),
|
||||
this->send_to_nextion_.value(x...));
|
||||
}
|
||||
|
||||
void set_state(std::function<void(Ts..., bool)> state) { this->state_ = state; }
|
||||
void set_publish_state(std::function<void(Ts..., bool)> publish_state) { this->publish_state_ = publish_state; }
|
||||
void set_send_to_nextion(std::function<void(Ts..., bool)> send_to_nextion) {
|
||||
this->send_to_nextion_ = send_to_nextion;
|
||||
}
|
||||
|
||||
protected:
|
||||
NextionComponent *component_;
|
||||
};
|
||||
|
||||
} // namespace nextion
|
||||
} // namespace esphome
|
||||
|
||||
@@ -18,7 +18,6 @@ CONF_ON_SLEEP = "on_sleep"
|
||||
CONF_ON_WAKE = "on_wake"
|
||||
CONF_ON_SETUP = "on_setup"
|
||||
CONF_ON_PAGE = "on_page"
|
||||
CONF_ON_BUFFER_OVERFLOW = "on_buffer_overflow"
|
||||
CONF_TOUCH_SLEEP_TIMEOUT = "touch_sleep_timeout"
|
||||
CONF_WAKE_UP_PAGE = "wake_up_page"
|
||||
CONF_START_UP_PAGE = "start_up_page"
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import binary_sensor
|
||||
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_STATE,
|
||||
CONF_COMPONENT_ID,
|
||||
CONF_PAGE_ID,
|
||||
)
|
||||
|
||||
from .. import nextion_ns, CONF_NEXTION_ID, CONF_PUBLISH_STATE, CONF_SEND_TO_NEXTION
|
||||
from esphome.const import CONF_COMPONENT_ID, CONF_PAGE_ID, CONF_ID
|
||||
from .. import nextion_ns, CONF_NEXTION_ID
|
||||
|
||||
|
||||
from ..base_component import (
|
||||
@@ -26,10 +19,6 @@ NextionBinarySensor = nextion_ns.class_(
|
||||
"NextionBinarySensor", binary_sensor.BinarySensor, cg.PollingComponent
|
||||
)
|
||||
|
||||
NextionPublishBoolAction = nextion_ns.class_(
|
||||
"NextionPublishBoolAction", automation.Action
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
binary_sensor.binary_sensor_schema(NextionBinarySensor)
|
||||
.extend(
|
||||
@@ -63,33 +52,3 @@ async def to_code(config):
|
||||
if CONF_COMPONENT_NAME in config or CONF_VARIABLE_NAME in config:
|
||||
await setup_component_core_(var, config, ".val")
|
||||
cg.add(hub.register_binarysensor_component(var))
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"binary_sensor.nextion.publish",
|
||||
NextionPublishBoolAction,
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.use_id(NextionBinarySensor),
|
||||
cv.Required(CONF_STATE): cv.templatable(cv.boolean),
|
||||
cv.Optional(CONF_PUBLISH_STATE, default="true"): cv.templatable(cv.boolean),
|
||||
cv.Optional(CONF_SEND_TO_NEXTION, default="true"): cv.templatable(
|
||||
cv.boolean
|
||||
),
|
||||
}
|
||||
),
|
||||
)
|
||||
async def sensor_nextion_publish_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
template_ = await cg.templatable(config[CONF_STATE], args, bool)
|
||||
cg.add(var.set_state(template_))
|
||||
|
||||
template_ = await cg.templatable(config[CONF_PUBLISH_STATE], args, bool)
|
||||
cg.add(var.set_publish_state(template_))
|
||||
|
||||
template_ = await cg.templatable(config[CONF_SEND_TO_NEXTION], args, bool)
|
||||
cg.add(var.set_send_to_nextion(template_))
|
||||
|
||||
return var
|
||||
|
||||
@@ -13,7 +13,6 @@ from esphome.const import (
|
||||
from esphome.core import CORE
|
||||
from . import Nextion, nextion_ns, nextion_ref
|
||||
from .base_component import (
|
||||
CONF_ON_BUFFER_OVERFLOW,
|
||||
CONF_ON_SLEEP,
|
||||
CONF_ON_WAKE,
|
||||
CONF_ON_SETUP,
|
||||
@@ -37,9 +36,6 @@ SleepTrigger = nextion_ns.class_("SleepTrigger", automation.Trigger.template())
|
||||
WakeTrigger = nextion_ns.class_("WakeTrigger", automation.Trigger.template())
|
||||
PageTrigger = nextion_ns.class_("PageTrigger", automation.Trigger.template())
|
||||
TouchTrigger = nextion_ns.class_("TouchTrigger", automation.Trigger.template())
|
||||
BufferOverflowTrigger = nextion_ns.class_(
|
||||
"BufferOverflowTrigger", automation.Trigger.template()
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
display.BASIC_DISPLAY_SCHEMA.extend(
|
||||
@@ -72,13 +68,6 @@ CONFIG_SCHEMA = (
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(TouchTrigger),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_ON_BUFFER_OVERFLOW): automation.validate_automation(
|
||||
{
|
||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
||||
BufferOverflowTrigger
|
||||
),
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_TOUCH_SLEEP_TIMEOUT): cv.int_range(min=3, max=65535),
|
||||
cv.Optional(CONF_WAKE_UP_PAGE): cv.uint8_t,
|
||||
cv.Optional(CONF_START_UP_PAGE): cv.uint8_t,
|
||||
@@ -162,7 +151,3 @@ async def to_code(config):
|
||||
],
|
||||
conf,
|
||||
)
|
||||
|
||||
for conf in config.get(CONF_ON_BUFFER_OVERFLOW, []):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
||||
@@ -190,10 +190,6 @@ void Nextion::add_touch_event_callback(std::function<void(uint8_t, uint8_t, bool
|
||||
this->touch_callback_.add(std::move(callback));
|
||||
}
|
||||
|
||||
void Nextion::add_buffer_overflow_event_callback(std::function<void()> &&callback) {
|
||||
this->buffer_overflow_callback_.add(std::move(callback));
|
||||
}
|
||||
|
||||
void Nextion::update_all_components() {
|
||||
if ((!this->is_setup() && !this->ignore_is_setup_) || this->is_sleeping())
|
||||
return;
|
||||
@@ -343,7 +339,7 @@ void Nextion::process_serial_() {
|
||||
}
|
||||
// nextion.tech/instruction-set/
|
||||
void Nextion::process_nextion_commands_() {
|
||||
if (this->command_data_.empty()) {
|
||||
if (this->command_data_.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -462,9 +458,7 @@ void Nextion::process_nextion_commands_() {
|
||||
this->remove_from_q_();
|
||||
break;
|
||||
case 0x24: // Serial Buffer overflow occurs
|
||||
// Buffer will continue to receive the current instruction, all previous instructions are lost.
|
||||
ESP_LOGE(TAG, "Nextion reported Serial Buffer overflow!");
|
||||
this->buffer_overflow_callback_.call();
|
||||
ESP_LOGW(TAG, "Nextion reported Serial Buffer overflow!");
|
||||
break;
|
||||
case 0x65: { // touch event return data
|
||||
if (to_process_length != 3) {
|
||||
@@ -563,10 +557,13 @@ void Nextion::process_nextion_commands_() {
|
||||
break;
|
||||
}
|
||||
|
||||
int dataindex = 0;
|
||||
|
||||
int value = 0;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
value += to_process[i] << (8 * i);
|
||||
++dataindex;
|
||||
}
|
||||
|
||||
NextionQueue *nb = this->nextion_queue_.front();
|
||||
|
||||
@@ -1134,12 +1134,6 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
|
||||
*/
|
||||
void add_touch_event_callback(std::function<void(uint8_t, uint8_t, bool)> &&callback);
|
||||
|
||||
/** Add a callback to be notified when the nextion reports a buffer overflow.
|
||||
*
|
||||
* @param callback The void() callback.
|
||||
*/
|
||||
void add_buffer_overflow_event_callback(std::function<void()> &&callback);
|
||||
|
||||
void update_all_components();
|
||||
|
||||
/**
|
||||
@@ -1329,7 +1323,6 @@ class Nextion : public NextionBase, public PollingComponent, public uart::UARTDe
|
||||
CallbackManager<void()> wake_callback_{};
|
||||
CallbackManager<void(uint8_t)> page_callback_{};
|
||||
CallbackManager<void(uint8_t, uint8_t, bool)> touch_callback_{};
|
||||
CallbackManager<void()> buffer_overflow_callback_{};
|
||||
|
||||
optional<nextion_writer_t> writer_;
|
||||
float brightness_{1.0};
|
||||
|
||||
@@ -36,8 +36,8 @@ int Nextion::upload_by_chunks_(esp_http_client_handle_t http_client, uint32_t &r
|
||||
ESP_LOGV(TAG, "Requesting range: %s", range_header);
|
||||
esp_http_client_set_header(http_client, "Range", range_header);
|
||||
ESP_LOGV(TAG, "Opening HTTP connetion");
|
||||
esp_err_t err = esp_http_client_open(http_client, 0);
|
||||
if (err != ESP_OK) {
|
||||
esp_err_t err;
|
||||
if ((err = esp_http_client_open(http_client, 0)) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import sensor
|
||||
|
||||
from esphome.const import CONF_ID, CONF_COMPONENT_ID, CONF_STATE
|
||||
|
||||
from .. import nextion_ns, CONF_NEXTION_ID, CONF_PUBLISH_STATE, CONF_SEND_TO_NEXTION
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_COMPONENT_ID,
|
||||
)
|
||||
from .. import nextion_ns, CONF_NEXTION_ID
|
||||
|
||||
from ..base_component import (
|
||||
setup_component_core_,
|
||||
@@ -24,10 +25,6 @@ CODEOWNERS = ["@senexcrenshaw"]
|
||||
|
||||
NextionSensor = nextion_ns.class_("NextionSensor", sensor.Sensor, cg.PollingComponent)
|
||||
|
||||
NextionPublishFloatAction = nextion_ns.class_(
|
||||
"NextionPublishFloatAction", automation.Action
|
||||
)
|
||||
|
||||
|
||||
def CheckWaveID(value):
|
||||
value = cv.int_(value)
|
||||
@@ -98,33 +95,3 @@ async def to_code(config):
|
||||
|
||||
if CONF_WAVE_MAX_LENGTH in config:
|
||||
cg.add(var.set_wave_max_length(config[CONF_WAVE_MAX_LENGTH]))
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"sensor.nextion.publish",
|
||||
NextionPublishFloatAction,
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.use_id(NextionSensor),
|
||||
cv.Required(CONF_STATE): cv.templatable(cv.float_),
|
||||
cv.Optional(CONF_PUBLISH_STATE, default="true"): cv.templatable(cv.boolean),
|
||||
cv.Optional(CONF_SEND_TO_NEXTION, default="true"): cv.templatable(
|
||||
cv.boolean
|
||||
),
|
||||
}
|
||||
),
|
||||
)
|
||||
async def sensor_nextion_publish_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
template_ = await cg.templatable(config[CONF_STATE], args, float)
|
||||
cg.add(var.set_state(template_))
|
||||
|
||||
template_ = await cg.templatable(config[CONF_PUBLISH_STATE], args, bool)
|
||||
cg.add(var.set_publish_state(template_))
|
||||
|
||||
template_ = await cg.templatable(config[CONF_SEND_TO_NEXTION], args, bool)
|
||||
cg.add(var.set_send_to_nextion(template_))
|
||||
|
||||
return var
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import switch
|
||||
|
||||
from esphome.const import CONF_ID, CONF_STATE
|
||||
|
||||
from .. import nextion_ns, CONF_NEXTION_ID, CONF_PUBLISH_STATE, CONF_SEND_TO_NEXTION
|
||||
from esphome.const import CONF_ID
|
||||
from .. import nextion_ns, CONF_NEXTION_ID
|
||||
|
||||
from ..base_component import (
|
||||
setup_component_core_,
|
||||
@@ -18,10 +16,6 @@ CODEOWNERS = ["@senexcrenshaw"]
|
||||
|
||||
NextionSwitch = nextion_ns.class_("NextionSwitch", switch.Switch, cg.PollingComponent)
|
||||
|
||||
NextionPublishBoolAction = nextion_ns.class_(
|
||||
"NextionPublishBoolAction", automation.Action
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
switch.switch_schema(NextionSwitch)
|
||||
.extend(CONFIG_SWITCH_COMPONENT_SCHEMA)
|
||||
@@ -39,33 +33,3 @@ async def to_code(config):
|
||||
cg.add(hub.register_switch_component(var))
|
||||
|
||||
await setup_component_core_(var, config, ".val")
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"switch.nextion.publish",
|
||||
NextionPublishBoolAction,
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.use_id(NextionSwitch),
|
||||
cv.Required(CONF_STATE): cv.templatable(cv.boolean),
|
||||
cv.Optional(CONF_PUBLISH_STATE, default="true"): cv.templatable(cv.boolean),
|
||||
cv.Optional(CONF_SEND_TO_NEXTION, default="true"): cv.templatable(
|
||||
cv.boolean
|
||||
),
|
||||
}
|
||||
),
|
||||
)
|
||||
async def sensor_nextion_publish_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
template_ = await cg.templatable(config[CONF_STATE], args, bool)
|
||||
cg.add(var.set_state(template_))
|
||||
|
||||
template_ = await cg.templatable(config[CONF_PUBLISH_STATE], args, bool)
|
||||
cg.add(var.set_publish_state(template_))
|
||||
|
||||
template_ = await cg.templatable(config[CONF_SEND_TO_NEXTION], args, bool)
|
||||
cg.add(var.set_send_to_nextion(template_))
|
||||
|
||||
return var
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
from esphome import automation
|
||||
from esphome.components import text_sensor
|
||||
import esphome.config_validation as cv
|
||||
import esphome.codegen as cg
|
||||
from esphome.const import CONF_ID, CONF_STATE
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
from .. import nextion_ns, CONF_NEXTION_ID, CONF_PUBLISH_STATE, CONF_SEND_TO_NEXTION
|
||||
from .. import nextion_ns, CONF_NEXTION_ID
|
||||
|
||||
from ..base_component import (
|
||||
setup_component_core_,
|
||||
@@ -17,10 +16,6 @@ NextionTextSensor = nextion_ns.class_(
|
||||
"NextionTextSensor", text_sensor.TextSensor, cg.PollingComponent
|
||||
)
|
||||
|
||||
NextionPublishTextAction = nextion_ns.class_(
|
||||
"NextionPublishTextAction", automation.Action
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
text_sensor.text_sensor_schema(NextionTextSensor)
|
||||
.extend(CONFIG_TEXT_COMPONENT_SCHEMA)
|
||||
@@ -37,33 +32,3 @@ async def to_code(config):
|
||||
cg.add(hub.register_textsensor_component(var))
|
||||
|
||||
await setup_component_core_(var, config, ".txt")
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"text_sensor.nextion.publish",
|
||||
NextionPublishTextAction,
|
||||
cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.use_id(NextionTextSensor),
|
||||
cv.Required(CONF_STATE): cv.templatable(cv.string_strict),
|
||||
cv.Optional(CONF_PUBLISH_STATE, default="true"): cv.templatable(cv.boolean),
|
||||
cv.Optional(CONF_SEND_TO_NEXTION, default="true"): cv.templatable(
|
||||
cv.boolean
|
||||
),
|
||||
}
|
||||
),
|
||||
)
|
||||
async def sensor_nextion_publish_to_code(config, action_id, template_arg, args):
|
||||
paren = await cg.get_variable(config[CONF_ID])
|
||||
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||
|
||||
template_ = await cg.templatable(config[CONF_STATE], args, cg.const_char_ptr)
|
||||
cg.add(var.set_state(template_))
|
||||
|
||||
template_ = await cg.templatable(config[CONF_PUBLISH_STATE], args, cg.bool_)
|
||||
cg.add(var.set_publish_state(template_))
|
||||
|
||||
template_ = await cg.templatable(config[CONF_SEND_TO_NEXTION], args, cg.bool_)
|
||||
cg.add(var.set_send_to_nextion(template_))
|
||||
|
||||
return var
|
||||
|
||||
@@ -30,13 +30,13 @@ std::vector<uint8_t> NdefRecord::encode(bool first, bool last) {
|
||||
data.push_back(payload_length & 0xFF);
|
||||
}
|
||||
|
||||
if (!this->id_.empty()) {
|
||||
if (this->id_.length()) {
|
||||
data.push_back(this->id_.length());
|
||||
}
|
||||
|
||||
data.insert(data.end(), this->type_.begin(), this->type_.end());
|
||||
|
||||
if (!this->id_.empty()) {
|
||||
if (this->id_.length()) {
|
||||
data.insert(data.end(), this->id_.begin(), this->id_.end());
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ uint8_t NdefRecord::create_flag_byte(bool first, bool last, size_t payload_size)
|
||||
if (payload_size <= 255) {
|
||||
value = value | 0x10; // Set SR bit
|
||||
}
|
||||
if (!this->id_.empty()) {
|
||||
if (this->id_.length()) {
|
||||
value = value | 0x08; // Set IL bit
|
||||
}
|
||||
return value;
|
||||
|
||||
@@ -98,7 +98,6 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
# esp8266_arduino=cv.Version(2, 7, 0),
|
||||
esp32_arduino=cv.Version(0, 0, 0),
|
||||
esp_idf=cv.Version(4, 0, 0),
|
||||
rp2040_arduino=cv.Version(0, 0, 0),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -25,7 +25,7 @@ using std::to_string;
|
||||
static const char *const TAG = "opentherm";
|
||||
|
||||
#ifdef ESP8266
|
||||
OpenTherm *OpenTherm::instance = nullptr;
|
||||
OpenTherm *OpenTherm::instance_ = nullptr;
|
||||
#endif
|
||||
|
||||
OpenTherm::OpenTherm(InternalGPIOPin *in_pin, InternalGPIOPin *out_pin, int32_t device_timeout)
|
||||
@@ -49,7 +49,7 @@ OpenTherm::OpenTherm(InternalGPIOPin *in_pin, InternalGPIOPin *out_pin, int32_t
|
||||
|
||||
bool OpenTherm::initialize() {
|
||||
#ifdef ESP8266
|
||||
OpenTherm::instance = this;
|
||||
OpenTherm::instance_ = this;
|
||||
#endif
|
||||
this->in_pin_->pin_mode(gpio::FLAG_INPUT);
|
||||
this->out_pin_->pin_mode(gpio::FLAG_OUTPUT);
|
||||
@@ -212,7 +212,7 @@ bool IRAM_ATTR OpenTherm::timer_isr(OpenTherm *arg) {
|
||||
}
|
||||
|
||||
#ifdef ESP8266
|
||||
void IRAM_ATTR OpenTherm::esp8266_timer_isr() { OpenTherm::timer_isr(OpenTherm::instance); }
|
||||
void IRAM_ATTR OpenTherm::esp8266_timer_isr() { OpenTherm::timer_isr(OpenTherm::instance_); }
|
||||
#endif
|
||||
|
||||
void IRAM_ATTR OpenTherm::bit_read_(uint8_t value) {
|
||||
|
||||
@@ -370,7 +370,7 @@ class OpenTherm {
|
||||
|
||||
#ifdef ESP8266
|
||||
// ESP8266 timer can accept callback with no parameters, so we have this hack to save a static instance of OpenTherm
|
||||
static OpenTherm *instance; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
static OpenTherm *instance_;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ class OTAStateChangeTrigger : public Trigger<OTAState> {
|
||||
explicit OTAStateChangeTrigger(OTAComponent *parent) {
|
||||
parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) {
|
||||
if (!parent->is_failed()) {
|
||||
trigger(state);
|
||||
return trigger(state);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ void FloatOutput::set_level(float state) {
|
||||
}
|
||||
#endif
|
||||
|
||||
if (state != 0.0f || !this->zero_means_zero_) // regardless of min_power_, 0.0 means off
|
||||
if (!(state == 0.0f && this->zero_means_zero_)) // regardless of min_power_, 0.0 means off
|
||||
state = (state * (this->max_power_ - this->min_power_)) + this->min_power_;
|
||||
|
||||
if (this->is_inverted())
|
||||
|
||||
@@ -34,7 +34,7 @@ void PCA6416AComponent::setup() {
|
||||
}
|
||||
|
||||
// Test to see if the device supports pull-up resistors
|
||||
if (this->read_register(PCAL6416A_PULL_EN0, &value, 1, true) == i2c::ERROR_OK) {
|
||||
if (this->read_register(PCAL6416A_PULL_EN0, &value, 1, true) == esphome::i2c::ERROR_OK) {
|
||||
this->has_pullup_ = true;
|
||||
}
|
||||
|
||||
@@ -106,8 +106,7 @@ bool PCA6416AComponent::read_register_(uint8_t reg, uint8_t *value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this->last_error_ = this->read_register(reg, value, 1, true);
|
||||
if (this->last_error_ != i2c::ERROR_OK) {
|
||||
if ((this->last_error_ = this->read_register(reg, value, 1, true)) != esphome::i2c::ERROR_OK) {
|
||||
this->status_set_warning();
|
||||
ESP_LOGE(TAG, "read_register_(): I2C I/O error: %d", (int) this->last_error_);
|
||||
return false;
|
||||
@@ -123,8 +122,7 @@ bool PCA6416AComponent::write_register_(uint8_t reg, uint8_t value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this->last_error_ = this->write_register(reg, &value, 1, true);
|
||||
if (this->last_error_ != i2c::ERROR_OK) {
|
||||
if ((this->last_error_ = this->write_register(reg, &value, 1, true)) != esphome::i2c::ERROR_OK) {
|
||||
this->status_set_warning();
|
||||
ESP_LOGE(TAG, "write_register_(): I2C I/O error: %d", (int) this->last_error_);
|
||||
return false;
|
||||
|
||||
@@ -95,8 +95,8 @@ bool PCA9554Component::read_inputs_() {
|
||||
return false;
|
||||
}
|
||||
|
||||
this->last_error_ = this->read_register(INPUT_REG * this->reg_width_, inputs, this->reg_width_, true);
|
||||
if (this->last_error_ != i2c::ERROR_OK) {
|
||||
if ((this->last_error_ = this->read_register(INPUT_REG * this->reg_width_, inputs, this->reg_width_, true)) !=
|
||||
esphome::i2c::ERROR_OK) {
|
||||
this->status_set_warning();
|
||||
ESP_LOGE(TAG, "read_register_(): I2C I/O error: %d", (int) this->last_error_);
|
||||
return false;
|
||||
@@ -113,8 +113,8 @@ bool PCA9554Component::write_register_(uint8_t reg, uint16_t value) {
|
||||
uint8_t outputs[2];
|
||||
outputs[0] = (uint8_t) value;
|
||||
outputs[1] = (uint8_t) (value >> 8);
|
||||
this->last_error_ = this->write_register(reg * this->reg_width_, outputs, this->reg_width_, true);
|
||||
if (this->last_error_ != i2c::ERROR_OK) {
|
||||
if ((this->last_error_ = this->write_register(reg * this->reg_width_, outputs, this->reg_width_, true)) !=
|
||||
esphome::i2c::ERROR_OK) {
|
||||
this->status_set_warning();
|
||||
ESP_LOGE(TAG, "write_register_(): I2C I/O error: %d", (int) this->last_error_);
|
||||
return false;
|
||||
|
||||
@@ -790,7 +790,7 @@ uint8_t Pipsolar::check_incoming_crc_() {
|
||||
// send next command used
|
||||
uint8_t Pipsolar::send_next_command_() {
|
||||
uint16_t crc16;
|
||||
if (!this->command_queue_[this->command_queue_position_].empty()) {
|
||||
if (this->command_queue_[this->command_queue_position_].length() != 0) {
|
||||
const char *command = this->command_queue_[this->command_queue_position_].c_str();
|
||||
uint8_t byte_command[16];
|
||||
uint8_t length = this->command_queue_[this->command_queue_position_].length();
|
||||
@@ -846,7 +846,7 @@ void Pipsolar::queue_command_(const char *command, uint8_t length) {
|
||||
uint8_t next_position = command_queue_position_;
|
||||
for (uint8_t i = 0; i < COMMAND_QUEUE_LENGTH; i++) {
|
||||
uint8_t testposition = (next_position + i) % COMMAND_QUEUE_LENGTH;
|
||||
if (command_queue_[testposition].empty()) {
|
||||
if (command_queue_[testposition].length() == 0) {
|
||||
command_queue_[testposition] = command;
|
||||
ESP_LOGD(TAG, "Command queued successfully: %s with length %u at position %d", command,
|
||||
command_queue_[testposition].length(), testposition);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user