From abb2669f0fb94c72deb55781bb087c86fe2e382c Mon Sep 17 00:00:00 2001 From: tomaszduda23 Date: Thu, 15 Aug 2024 23:16:06 +0200 Subject: [PATCH 01/13] [code-quality] fix clang-tidy captive_portal (#7280) --- esphome/components/captive_portal/captive_portal.cpp | 2 ++ esphome/components/captive_portal/captive_portal.h | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/esphome/components/captive_portal/captive_portal.cpp b/esphome/components/captive_portal/captive_portal.cpp index 630e00f0b7..d1960e9a93 100644 --- a/esphome/components/captive_portal/captive_portal.cpp +++ b/esphome/components/captive_portal/captive_portal.cpp @@ -1,4 +1,5 @@ #include "captive_portal.h" +#ifdef USE_CAPTIVE_PORTAL #include "esphome/core/log.h" #include "esphome/core/application.h" #include "esphome/components/wifi/wifi_component.h" @@ -91,3 +92,4 @@ CaptivePortal *global_captive_portal = nullptr; // NOLINT(cppcoreguidelines-avo } // namespace captive_portal } // namespace esphome +#endif diff --git a/esphome/components/captive_portal/captive_portal.h b/esphome/components/captive_portal/captive_portal.h index df45d40d12..24d1295e6a 100644 --- a/esphome/components/captive_portal/captive_portal.h +++ b/esphome/components/captive_portal/captive_portal.h @@ -1,5 +1,6 @@ #pragma once - +#include "esphome/core/defines.h" +#ifdef USE_CAPTIVE_PORTAL #include #ifdef USE_ARDUINO #include @@ -71,3 +72,4 @@ extern CaptivePortal *global_captive_portal; // NOLINT(cppcoreguidelines-avoid- } // namespace captive_portal } // namespace esphome +#endif From 9001d1c0d46cf214f989baac9c1f05f4ed321804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Kiss?= <70820303+g-kiss@users.noreply.github.com> Date: Fri, 16 Aug 2024 00:35:00 +0200 Subject: [PATCH 02/13] Fix overflow in ESPColorCorrection object (#7268) --- esphome/components/light/esp_color_correction.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/esphome/components/light/esp_color_correction.h b/esphome/components/light/esp_color_correction.h index eedd71ab27..979a1acb07 100644 --- a/esphome/components/light/esp_color_correction.h +++ b/esphome/components/light/esp_color_correction.h @@ -41,29 +41,29 @@ class ESPColorCorrection { if (this->max_brightness_.red == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[red] * 255UL; - uint8_t res = ((uncorrected / this->max_brightness_.red) * 255UL) / this->local_brightness_; - return res; + uint16_t res = ((uncorrected / this->max_brightness_.red) * 255UL) / this->local_brightness_; + return (uint8_t) std::min(res, uint16_t(255)); } inline uint8_t color_uncorrect_green(uint8_t green) const ESPHOME_ALWAYS_INLINE { if (this->max_brightness_.green == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[green] * 255UL; - uint8_t res = ((uncorrected / this->max_brightness_.green) * 255UL) / this->local_brightness_; - return res; + uint16_t res = ((uncorrected / this->max_brightness_.green) * 255UL) / this->local_brightness_; + return (uint8_t) std::min(res, uint16_t(255)); } inline uint8_t color_uncorrect_blue(uint8_t blue) const ESPHOME_ALWAYS_INLINE { if (this->max_brightness_.blue == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[blue] * 255UL; - uint8_t res = ((uncorrected / this->max_brightness_.blue) * 255UL) / this->local_brightness_; - return res; + uint16_t res = ((uncorrected / this->max_brightness_.blue) * 255UL) / this->local_brightness_; + return (uint8_t) std::min(res, uint16_t(255)); } inline uint8_t color_uncorrect_white(uint8_t white) const ESPHOME_ALWAYS_INLINE { if (this->max_brightness_.white == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[white] * 255UL; - uint8_t res = ((uncorrected / this->max_brightness_.white) * 255UL) / this->local_brightness_; - return res; + uint16_t res = ((uncorrected / this->max_brightness_.white) * 255UL) / this->local_brightness_; + return (uint8_t) std::min(res, uint16_t(255)); } protected: From c3668b9a4de8408c28089c8c0652e0c36119cdcd Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 16 Aug 2024 11:05:26 +1200 Subject: [PATCH 03/13] [validation] Allow ``maybe_simple_value`` to not have default key in complex value (#7294) --- esphome/config_validation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index ef60d6e0d6..1c00e0699b 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1850,7 +1850,7 @@ def maybe_simple_value(*validators, **kwargs): if value == SCHEMA_EXTRACT: return (validator, key) - if isinstance(value, dict) and key in value: + if isinstance(value, dict): return validator(value) return validator({key: value}) From a0c54504cdc54521309364609883c002f88ae137 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 16 Aug 2024 00:27:23 +0100 Subject: [PATCH 04/13] Add HMAC-MD5 support for authenticating OTA updates (#7200) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/hmac_md5/__init__.py | 2 + esphome/components/hmac_md5/hmac_md5.cpp | 56 ++++++++++++++++++++++++ esphome/components/hmac_md5/hmac_md5.h | 48 ++++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 esphome/components/hmac_md5/__init__.py create mode 100644 esphome/components/hmac_md5/hmac_md5.cpp create mode 100644 esphome/components/hmac_md5/hmac_md5.h diff --git a/CODEOWNERS b/CODEOWNERS index 1236c8d842..9159f5f843 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -169,6 +169,7 @@ esphome/components/he60r/* @clydebarrow esphome/components/heatpumpir/* @rob-deutsch esphome/components/hitachi_ac424/* @sourabhjaiswal esphome/components/hm3301/* @freekode +esphome/components/hmac_md5/* @dwmw2 esphome/components/homeassistant/* @OttoWinter @esphome/core esphome/components/homeassistant/number/* @landonr esphome/components/homeassistant/switch/* @Links2004 diff --git a/esphome/components/hmac_md5/__init__.py b/esphome/components/hmac_md5/__init__.py new file mode 100644 index 0000000000..fe245c0cfd --- /dev/null +++ b/esphome/components/hmac_md5/__init__.py @@ -0,0 +1,2 @@ +AUTO_LOAD = ["md5"] +CODEOWNERS = ["@dwmw2"] diff --git a/esphome/components/hmac_md5/hmac_md5.cpp b/esphome/components/hmac_md5/hmac_md5.cpp new file mode 100644 index 0000000000..90bf91882f --- /dev/null +++ b/esphome/components/hmac_md5/hmac_md5.cpp @@ -0,0 +1,56 @@ +#include +#include +#include "hmac_md5.h" +#include "esphome/core/helpers.h" + +namespace esphome { +namespace hmac_md5 { +void HmacMD5::init(const uint8_t *key, size_t len) { + uint8_t ipad[64], opad[64]; + + memset(ipad, 0, sizeof(ipad)); + if (len > 64) { + md5::MD5Digest keymd5; + keymd5.init(); + keymd5.add(key, len); + keymd5.calculate(); + keymd5.get_bytes(ipad); + } else { + memcpy(ipad, key, len); + } + memcpy(opad, ipad, sizeof(opad)); + + for (int i = 0; i < 64; i++) { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + + this->ihash_.init(); + this->ihash_.add(ipad, sizeof(ipad)); + + this->ohash_.init(); + this->ohash_.add(opad, sizeof(opad)); +} + +void HmacMD5::add(const uint8_t *data, size_t len) { this->ihash_.add(data, len); } + +void HmacMD5::calculate() { + uint8_t ibytes[16]; + + this->ihash_.calculate(); + this->ihash_.get_bytes(ibytes); + + this->ohash_.add(ibytes, sizeof(ibytes)); + this->ohash_.calculate(); +} + +void HmacMD5::get_bytes(uint8_t *output) { this->ohash_.get_bytes(output); } + +void HmacMD5::get_hex(char *output) { this->ohash_.get_hex(output); } + +bool HmacMD5::equals_bytes(const uint8_t *expected) { return this->ohash_.equals_bytes(expected); } + +bool HmacMD5::equals_hex(const char *expected) { return this->ohash_.equals_hex(expected); } + +} // namespace hmac_md5 +} // namespace esphome diff --git a/esphome/components/hmac_md5/hmac_md5.h b/esphome/components/hmac_md5/hmac_md5.h new file mode 100644 index 0000000000..e6a97ad2e3 --- /dev/null +++ b/esphome/components/hmac_md5/hmac_md5.h @@ -0,0 +1,48 @@ +#pragma once + +#include "esphome/core/defines.h" +#include "esphome/components/md5/md5.h" + +#include + +namespace esphome { +namespace hmac_md5 { + +class HmacMD5 { + public: + HmacMD5() = default; + ~HmacMD5() = default; + + /// Initialize a new MD5 digest computation. + void init(const uint8_t *key, size_t len); + void init(const char *key, size_t len) { this->init((const uint8_t *) key, len); } + void init(const std::string &key) { this->init(key.c_str(), key.length()); } + + /// Add bytes of data for the digest. + void add(const uint8_t *data, size_t len); + void add(const char *data, size_t len) { this->add((const uint8_t *) data, len); } + + /// Compute the digest, based on the provided data. + void calculate(); + + /// Retrieve the HMAC-MD5 digest as bytes. + /// The output must be able to hold 16 bytes or more. + void get_bytes(uint8_t *output); + + /// Retrieve the HMAC-MD5 digest as hex characters. + /// The output must be able to hold 32 bytes or more. + void get_hex(char *output); + + /// Compare the digest against a provided byte-encoded digest (16 bytes). + bool equals_bytes(const uint8_t *expected); + + /// Compare the digest against a provided hex-encoded digest (32 bytes). + bool equals_hex(const char *expected); + + protected: + md5::MD5Digest ihash_; + md5::MD5Digest ohash_; +}; + +} // namespace hmac_md5 +} // namespace esphome From a7167ec3bf1adaec467944586c71d442a93a68d2 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 16 Aug 2024 02:32:00 +0100 Subject: [PATCH 05/13] [network] Always allow ``enable_ipv6: false`` (#7291) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/network/__init__.py | 6 +++++- esphome/config_validation.py | 14 ++++++++++++++ tests/components/network/test-ipv6.bk72xx-ard.yaml | 4 ++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/components/network/test-ipv6.bk72xx-ard.yaml diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 96db322bde..caa873a746 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -24,7 +24,11 @@ CONFIG_SCHEMA = cv.Schema( esp32=False, rp2040=False, ): cv.All( - cv.boolean, cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]) + cv.boolean, + cv.Any( + cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]), + cv.boolean_false, + ), ), cv.Optional(CONF_MIN_IPV6_ADDR_COUNT, default=0): cv.positive_int, } diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 1c00e0699b..6d6cb451d6 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -370,6 +370,20 @@ def boolean(value): ) +def boolean_false(value): + """Validate the given config option to be a boolean, set to False. + + This option allows a bunch of different ways of expressing boolean values: + - instance of boolean + - 'true'/'false' + - 'yes'/'no' + - 'enable'/disable + """ + if boolean(value): + raise Invalid("Expected boolean value to be false") + return False + + @schema_extractor_list def ensure_list(*validators): """Validate this configuration option to be a list. diff --git a/tests/components/network/test-ipv6.bk72xx-ard.yaml b/tests/components/network/test-ipv6.bk72xx-ard.yaml new file mode 100644 index 0000000000..361ca09977 --- /dev/null +++ b/tests/components/network/test-ipv6.bk72xx-ard.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "false" + +<<: !include common.yaml From bc20fd57fe3bdd52a5ed5000d29b90063f76dd0a Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 14 Aug 2024 00:55:23 -0700 Subject: [PATCH 06/13] remove extra number from pronto (#7263) --- esphome/components/remote_base/pronto_protocol.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/esphome/components/remote_base/pronto_protocol.cpp b/esphome/components/remote_base/pronto_protocol.cpp index 625af76235..35fd782248 100644 --- a/esphome/components/remote_base/pronto_protocol.cpp +++ b/esphome/components/remote_base/pronto_protocol.cpp @@ -201,9 +201,6 @@ std::string ProntoProtocol::compensate_and_dump_sequence_(const RawTimings &data out += dump_duration_(t_duration, timebase); } - // append minimum gap - out += dump_duration_(PRONTO_DEFAULT_GAP, timebase, true); - return out; } From e3bfbebb8fd3368ac3c351af33407cf77956910d Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 15 Aug 2024 13:35:03 +1000 Subject: [PATCH 07/13] [api] Bump noise-c library version (#7288) --- .github/workflows/ci.yml | 4 ++-- esphome/components/api/__init__.py | 2 +- esphome/components/host/__init__.py | 10 +++------- tests/components/api/common.yaml | 4 ---- tests/components/api/test.esp32-ard.yaml | 4 ++++ tests/components/api/test.esp32-c3-ard.yaml | 4 ++++ tests/components/api/test.esp32-c3-idf.yaml | 4 ++++ tests/components/api/test.esp32-idf.yaml | 4 ++++ tests/components/api/test.esp8266-ard.yaml | 4 ++++ tests/components/api/test.host.yaml | 3 +++ tests/components/api/test.rp2040-ard.yaml | 4 ++++ 11 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 tests/components/api/test.host.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 126a541b3d..2437dd5b8d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -397,7 +397,7 @@ jobs: file: ${{ fromJson(needs.list-components.outputs.components) }} steps: - name: Install dependencies - run: sudo apt-get install libsodium-dev libsdl2-dev + run: sudo apt-get install libsdl2-dev - name: Check out code from GitHub uses: actions/checkout@v4.1.7 @@ -451,7 +451,7 @@ jobs: run: echo ${{ matrix.components }} - name: Install dependencies - run: sudo apt-get install libsodium-dev libsdl2-dev + run: sudo apt-get install libsdl2-dev - name: Check out code from GitHub uses: actions/checkout@v4.1.7 diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index 38b50d4b9d..27de5c873b 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -155,7 +155,7 @@ async def to_code(config): decoded = base64.b64decode(encryption_config[CONF_KEY]) cg.add(var.set_noise_psk(list(decoded))) cg.add_define("USE_API_NOISE") - cg.add_library("esphome/noise-c", "0.1.4") + cg.add_library("esphome/noise-c", "0.1.6") else: cg.add_define("USE_API_PLAINTEXT") diff --git a/esphome/components/host/__init__.py b/esphome/components/host/__init__.py index 39e418c9ea..e83bf2dba8 100644 --- a/esphome/components/host/__init__.py +++ b/esphome/components/host/__init__.py @@ -1,15 +1,14 @@ +import esphome.codegen as cg +import esphome.config_validation as cv from esphome.const import ( + CONF_MAC_ADDRESS, KEY_CORE, KEY_FRAMEWORK_VERSION, KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, PLATFORM_HOST, - CONF_MAC_ADDRESS, ) from esphome.core import CORE -from esphome.helpers import IS_MACOS -import esphome.config_validation as cv -import esphome.codegen as cg from .const import KEY_HOST @@ -42,8 +41,5 @@ async def to_code(config): cg.add_build_flag("-DUSE_HOST") cg.add_define("USE_ESPHOME_HOST_MAC_ADDRESS", config[CONF_MAC_ADDRESS].parts) cg.add_build_flag("-std=c++17") - cg.add_build_flag("-lsodium") - if IS_MACOS: - cg.add_build_flag("-L/opt/homebrew/lib") cg.add_define("ESPHOME_BOARD", "host") cg.add_platformio_option("platform", "platformio/native") diff --git a/tests/components/api/common.yaml b/tests/components/api/common.yaml index 6c2a333598..7ac11e4da6 100644 --- a/tests/components/api/common.yaml +++ b/tests/components/api/common.yaml @@ -11,10 +11,6 @@ esphome: message: Button was pressed - homeassistant.tag_scanned: pulse -wifi: - ssid: MySSID - password: password1 - api: port: 8000 password: pwd diff --git a/tests/components/api/test.esp32-ard.yaml b/tests/components/api/test.esp32-ard.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.esp32-ard.yaml +++ b/tests/components/api/test.esp32-ard.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/api/test.esp32-c3-ard.yaml b/tests/components/api/test.esp32-c3-ard.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.esp32-c3-ard.yaml +++ b/tests/components/api/test.esp32-c3-ard.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/api/test.esp32-c3-idf.yaml b/tests/components/api/test.esp32-c3-idf.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.esp32-c3-idf.yaml +++ b/tests/components/api/test.esp32-c3-idf.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/api/test.esp32-idf.yaml b/tests/components/api/test.esp32-idf.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.esp32-idf.yaml +++ b/tests/components/api/test.esp32-idf.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/api/test.esp8266-ard.yaml b/tests/components/api/test.esp8266-ard.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.esp8266-ard.yaml +++ b/tests/components/api/test.esp8266-ard.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 diff --git a/tests/components/api/test.host.yaml b/tests/components/api/test.host.yaml new file mode 100644 index 0000000000..1ecafeab77 --- /dev/null +++ b/tests/components/api/test.host.yaml @@ -0,0 +1,3 @@ +<<: !include common.yaml + +network: diff --git a/tests/components/api/test.rp2040-ard.yaml b/tests/components/api/test.rp2040-ard.yaml index dade44d145..46c01d926f 100644 --- a/tests/components/api/test.rp2040-ard.yaml +++ b/tests/components/api/test.rp2040-ard.yaml @@ -1 +1,5 @@ <<: !include common.yaml + +wifi: + ssid: MySSID + password: password1 From e17c7124f48ac3fc2fbc2c45bbe01b23a203f65a Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Thu, 15 Aug 2024 06:51:44 +0200 Subject: [PATCH 08/13] fix some small rtttl issues (#6817) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/rtttl/rtttl.cpp | 127 ++++++++++++++++++++++++----- esphome/components/rtttl/rtttl.h | 21 +++-- 2 files changed, 121 insertions(+), 27 deletions(-) diff --git a/esphome/components/rtttl/rtttl.cpp b/esphome/components/rtttl/rtttl.cpp index 0bdf65b7bd..a97120499d 100644 --- a/esphome/components/rtttl/rtttl.cpp +++ b/esphome/components/rtttl/rtttl.cpp @@ -29,6 +29,13 @@ inline double deg2rad(double degrees) { void Rtttl::dump_config() { ESP_LOGCONFIG(TAG, "Rtttl"); } void Rtttl::play(std::string rtttl) { + if (this->state_ != State::STATE_STOPPED && this->state_ != State::STATE_STOPPING) { + int pos = this->rtttl_.find(':'); + auto name = this->rtttl_.substr(0, pos); + ESP_LOGW(TAG, "RTTL Component is already playing: %s", name.c_str()); + return; + } + this->rtttl_ = std::move(rtttl); this->default_duration_ = 4; @@ -98,13 +105,20 @@ void Rtttl::play(std::string rtttl) { this->note_duration_ = 1; #ifdef USE_SPEAKER - this->samples_sent_ = 0; - this->samples_count_ = 0; + if (this->speaker_ != nullptr) { + this->set_state_(State::STATE_INIT); + this->samples_sent_ = 0; + this->samples_count_ = 0; + } +#endif +#ifdef USE_OUTPUT + if (this->output_ != nullptr) { + this->set_state_(State::STATE_RUNNING); + } #endif } void Rtttl::stop() { - this->note_duration_ = 0; #ifdef USE_OUTPUT if (this->output_ != nullptr) { this->output_->set_level(0.0); @@ -117,16 +131,35 @@ void Rtttl::stop() { } } #endif + this->note_duration_ = 0; + this->set_state_(STATE_STOPPING); } void Rtttl::loop() { - if (this->note_duration_ == 0) + if (this->note_duration_ == 0 || this->state_ == State::STATE_STOPPED) return; #ifdef USE_SPEAKER if (this->speaker_ != nullptr) { + if (this->state_ == State::STATE_STOPPING) { + if (this->speaker_->is_stopped()) { + this->set_state_(State::STATE_STOPPED); + } + } else if (this->state_ == State::STATE_INIT) { + if (this->speaker_->is_stopped()) { + this->speaker_->start(); + this->set_state_(State::STATE_STARTING); + } + } else if (this->state_ == State::STATE_STARTING) { + if (this->speaker_->is_running()) { + this->set_state_(State::STATE_RUNNING); + } + } + if (!this->speaker_->is_running()) { + return; + } if (this->samples_sent_ != this->samples_count_) { - SpeakerSample sample[SAMPLE_BUFFER_SIZE + 1]; + SpeakerSample sample[SAMPLE_BUFFER_SIZE + 2]; int x = 0; double rem = 0.0; @@ -136,7 +169,7 @@ void Rtttl::loop() { if (this->samples_per_wave_ != 0 && this->samples_sent_ >= this->samples_gap_) { // Play note// rem = ((this->samples_sent_ << 10) % this->samples_per_wave_) * (360.0 / this->samples_per_wave_); - int16_t val = (49152 * this->gain_) * sin(deg2rad(rem)); + int16_t val = (127 * this->gain_) * sin(deg2rad(rem)); // 16bit = 49152 sample[x].left = val; sample[x].right = val; @@ -153,9 +186,9 @@ void Rtttl::loop() { x++; } if (x > 0) { - int send = this->speaker_->play((uint8_t *) (&sample), x * 4); + int send = this->speaker_->play((uint8_t *) (&sample), x * 2); if (send != x * 4) { - this->samples_sent_ -= (x - (send / 4)); + this->samples_sent_ -= (x - (send / 2)); } return; } @@ -167,14 +200,7 @@ void Rtttl::loop() { return; #endif if (!this->rtttl_[position_]) { - this->note_duration_ = 0; -#ifdef USE_OUTPUT - if (this->output_ != nullptr) { - this->output_->set_level(0.0); - } -#endif - ESP_LOGD(TAG, "Playback finished"); - this->on_finished_playback_callback_.call(); + this->finish_(); return; } @@ -213,6 +239,7 @@ void Rtttl::loop() { case 'a': note = 10; break; + case 'h': case 'b': note = 12; break; @@ -238,14 +265,21 @@ void Rtttl::loop() { uint8_t scale = get_integer_(); if (scale == 0) scale = this->default_octave_; + + if (scale < 4 || scale > 7) { + ESP_LOGE(TAG, "Octave out of valid range. Should be between 4 and 7. (Octave: %d)", scale); + this->finish_(); + return; + } bool need_note_gap = false; // Now play the note if (note) { auto note_index = (scale - 4) * 12 + note; if (note_index < 0 || note_index >= (int) sizeof(NOTES)) { - ESP_LOGE(TAG, "Note out of valid range"); - this->note_duration_ = 0; + ESP_LOGE(TAG, "Note out of valid range (note: %d, scale: %d, index: %d, max: %d)", note, scale, note_index, + (int) sizeof(NOTES)); + this->finish_(); return; } auto freq = NOTES[note_index]; @@ -285,14 +319,17 @@ void Rtttl::loop() { this->samples_gap_ = (this->sample_rate_ * DOUBLE_NOTE_GAP_MS) / 1600; //(ms); } if (this->output_freq_ != 0) { + // make sure there is enough samples to add a full last sinus. + + uint16_t samples_wish = this->samples_count_; this->samples_per_wave_ = (this->sample_rate_ << 10) / this->output_freq_; - // make sure there is enough samples to add a full last sinus. uint16_t division = ((this->samples_count_ << 10) / this->samples_per_wave_) + 1; - uint16_t x = this->samples_count_; + this->samples_count_ = (division * this->samples_per_wave_); - ESP_LOGD(TAG, "play time old: %d div: %d new: %d %d", x, division, this->samples_count_, this->samples_per_wave_); this->samples_count_ = this->samples_count_ >> 10; + ESP_LOGVV(TAG, "- Calc play time: wish: %d gets: %d (div: %d spw: %d)", samples_wish, this->samples_count_, + division, this->samples_per_wave_); } // Convert from frequency in Hz to high and low samples in fixed point } @@ -301,5 +338,53 @@ void Rtttl::loop() { this->last_note_ = millis(); } +void Rtttl::finish_() { +#ifdef USE_OUTPUT + if (this->output_ != nullptr) { + this->output_->set_level(0.0); + } +#endif +#ifdef USE_SPEAKER + if (this->speaker_ != nullptr) { + SpeakerSample sample[2]; + sample[0].left = 0; + sample[0].right = 0; + sample[1].left = 0; + sample[1].right = 0; + this->speaker_->play((uint8_t *) (&sample), 8); + + this->speaker_->finish(); + } +#endif + this->set_state_(State::STATE_STOPPING); + this->note_duration_ = 0; + this->on_finished_playback_callback_.call(); + ESP_LOGD(TAG, "Playback finished"); +} + +static const LogString *state_to_string(State state) { + switch (state) { + case STATE_STOPPED: + return LOG_STR("STATE_STOPPED"); + case STATE_STARTING: + return LOG_STR("STATE_STARTING"); + case STATE_RUNNING: + return LOG_STR("STATE_RUNNING"); + case STATE_STOPPING: + return LOG_STR("STATE_STOPPING"); + case STATE_INIT: + return LOG_STR("STATE_INIT"); + default: + return LOG_STR("UNKNOWN"); + } +}; + +void Rtttl::set_state_(State state) { + State old_state = this->state_; + this->state_ = state; + ESP_LOGD(TAG, "State changed from %s to %s", LOG_STR_ARG(state_to_string(old_state)), + LOG_STR_ARG(state_to_string(state))); +} + } // namespace rtttl } // namespace esphome diff --git a/esphome/components/rtttl/rtttl.h b/esphome/components/rtttl/rtttl.h index bf089ce980..3cb6e3f5fb 100644 --- a/esphome/components/rtttl/rtttl.h +++ b/esphome/components/rtttl/rtttl.h @@ -14,12 +14,20 @@ namespace esphome { namespace rtttl { +enum State : uint8_t { + STATE_STOPPED = 0, + STATE_INIT, + STATE_STARTING, + STATE_RUNNING, + STATE_STOPPING, +}; + #ifdef USE_SPEAKER -static const size_t SAMPLE_BUFFER_SIZE = 512; +static const size_t SAMPLE_BUFFER_SIZE = 2048; struct SpeakerSample { - int16_t left{0}; - int16_t right{0}; + int8_t left{0}; + int8_t right{0}; }; #endif @@ -42,7 +50,7 @@ class Rtttl : public Component { void stop(); void dump_config() override; - bool is_playing() { return this->note_duration_ != 0; } + bool is_playing() { return this->state_ != State::STATE_STOPPED; } void loop() override; void add_on_finished_playback_callback(std::function callback) { @@ -57,6 +65,8 @@ class Rtttl : public Component { } return ret; } + void finish_(); + void set_state_(State state); std::string rtttl_{""}; size_t position_{0}; @@ -68,13 +78,12 @@ class Rtttl : public Component { uint32_t output_freq_; float gain_{0.6f}; + State state_{State::STATE_STOPPED}; #ifdef USE_OUTPUT output::FloatOutput *output_; #endif - void play_output_(); - #ifdef USE_SPEAKER speaker::Speaker *speaker_{nullptr}; int sample_rate_{16000}; From 033ab552068374f4ad06dca122a250f18ba2a979 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Kiss?= <70820303+g-kiss@users.noreply.github.com> Date: Fri, 16 Aug 2024 00:35:00 +0200 Subject: [PATCH 09/13] Fix overflow in ESPColorCorrection object (#7268) --- esphome/components/light/esp_color_correction.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/esphome/components/light/esp_color_correction.h b/esphome/components/light/esp_color_correction.h index eedd71ab27..979a1acb07 100644 --- a/esphome/components/light/esp_color_correction.h +++ b/esphome/components/light/esp_color_correction.h @@ -41,29 +41,29 @@ class ESPColorCorrection { if (this->max_brightness_.red == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[red] * 255UL; - uint8_t res = ((uncorrected / this->max_brightness_.red) * 255UL) / this->local_brightness_; - return res; + uint16_t res = ((uncorrected / this->max_brightness_.red) * 255UL) / this->local_brightness_; + return (uint8_t) std::min(res, uint16_t(255)); } inline uint8_t color_uncorrect_green(uint8_t green) const ESPHOME_ALWAYS_INLINE { if (this->max_brightness_.green == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[green] * 255UL; - uint8_t res = ((uncorrected / this->max_brightness_.green) * 255UL) / this->local_brightness_; - return res; + uint16_t res = ((uncorrected / this->max_brightness_.green) * 255UL) / this->local_brightness_; + return (uint8_t) std::min(res, uint16_t(255)); } inline uint8_t color_uncorrect_blue(uint8_t blue) const ESPHOME_ALWAYS_INLINE { if (this->max_brightness_.blue == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[blue] * 255UL; - uint8_t res = ((uncorrected / this->max_brightness_.blue) * 255UL) / this->local_brightness_; - return res; + uint16_t res = ((uncorrected / this->max_brightness_.blue) * 255UL) / this->local_brightness_; + return (uint8_t) std::min(res, uint16_t(255)); } inline uint8_t color_uncorrect_white(uint8_t white) const ESPHOME_ALWAYS_INLINE { if (this->max_brightness_.white == 0 || this->local_brightness_ == 0) return 0; uint16_t uncorrected = this->gamma_reverse_table_[white] * 255UL; - uint8_t res = ((uncorrected / this->max_brightness_.white) * 255UL) / this->local_brightness_; - return res; + uint16_t res = ((uncorrected / this->max_brightness_.white) * 255UL) / this->local_brightness_; + return (uint8_t) std::min(res, uint16_t(255)); } protected: From 2c47eb62a7f1060be9fc727c8a5fc70ed92c1fd8 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 16 Aug 2024 11:05:26 +1200 Subject: [PATCH 10/13] [validation] Allow ``maybe_simple_value`` to not have default key in complex value (#7294) --- esphome/config_validation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index ef60d6e0d6..1c00e0699b 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1850,7 +1850,7 @@ def maybe_simple_value(*validators, **kwargs): if value == SCHEMA_EXTRACT: return (validator, key) - if isinstance(value, dict) and key in value: + if isinstance(value, dict): return validator(value) return validator({key: value}) From 343650e37d29058a5f2ef7caf8c7f868c9b1746c Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 16 Aug 2024 02:32:00 +0100 Subject: [PATCH 11/13] [network] Always allow ``enable_ipv6: false`` (#7291) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/network/__init__.py | 6 +++++- esphome/config_validation.py | 14 ++++++++++++++ tests/components/network/test-ipv6.bk72xx-ard.yaml | 4 ++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/components/network/test-ipv6.bk72xx-ard.yaml diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 96db322bde..caa873a746 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -24,7 +24,11 @@ CONFIG_SCHEMA = cv.Schema( esp32=False, rp2040=False, ): cv.All( - cv.boolean, cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]) + cv.boolean, + cv.Any( + cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]), + cv.boolean_false, + ), ), cv.Optional(CONF_MIN_IPV6_ADDR_COUNT, default=0): cv.positive_int, } diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 1c00e0699b..6d6cb451d6 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -370,6 +370,20 @@ def boolean(value): ) +def boolean_false(value): + """Validate the given config option to be a boolean, set to False. + + This option allows a bunch of different ways of expressing boolean values: + - instance of boolean + - 'true'/'false' + - 'yes'/'no' + - 'enable'/disable + """ + if boolean(value): + raise Invalid("Expected boolean value to be false") + return False + + @schema_extractor_list def ensure_list(*validators): """Validate this configuration option to be a list. diff --git a/tests/components/network/test-ipv6.bk72xx-ard.yaml b/tests/components/network/test-ipv6.bk72xx-ard.yaml new file mode 100644 index 0000000000..361ca09977 --- /dev/null +++ b/tests/components/network/test-ipv6.bk72xx-ard.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "false" + +<<: !include common.yaml From e779a09586e16f03f4544dff36044e6e1318e4a3 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 16 Aug 2024 13:38:06 +1200 Subject: [PATCH 12/13] Bump version to 2024.8.0b2 --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 47aacd6452..39d2ee74a1 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2024.8.0b1" +__version__ = "2024.8.0b2" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 56aa58780da5fe73637ed9f583fafbd0b3a26db7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Sun, 18 Aug 2024 20:27:03 +1200 Subject: [PATCH 13/13] Revert "[validation] Allow ``maybe_simple_value`` to not have default key in complex value" (#7305) --- esphome/config_validation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 6d6cb451d6..719cc43b31 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1864,7 +1864,7 @@ def maybe_simple_value(*validators, **kwargs): if value == SCHEMA_EXTRACT: return (validator, key) - if isinstance(value, dict): + if isinstance(value, dict) and key in value: return validator(value) return validator({key: value})