From 1c229947a862f4e47c6341ce6a92bc1107e28c09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 14:34:23 -0500 Subject: [PATCH 1/7] Bump github/codeql-action from 3.30.3 to 3.30.4 (#10886) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 943a35b32a..e31e547b75 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -58,7 +58,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 + uses: github/codeql-action/init@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3.30.4 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} @@ -86,6 +86,6 @@ jobs: exit 1 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3.30.3 + uses: github/codeql-action/analyze@303c0aef88fc2fe5ff6d63d3b1596bfd83dfa1f9 # v3.30.4 with: category: "/language:${{matrix.language}}" From 7af77d0f827aed421e3a9bba001b3786e8b6f0e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 19:39:14 +0000 Subject: [PATCH 2/7] Bump ruff from 0.13.1 to 0.13.2 (#10885) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: J. Nick Koston --- .pre-commit-config.yaml | 2 +- requirements_test.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cab433c7f9..818f360860 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.13.1 + rev: v0.13.2 hooks: # Run the linter. - id: ruff diff --git a/requirements_test.txt b/requirements_test.txt index 2c78eadf45..59ea77fd2d 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,6 +1,6 @@ pylint==3.3.8 flake8==7.3.0 # also change in .pre-commit-config.yaml when updating -ruff==0.13.1 # also change in .pre-commit-config.yaml when updating +ruff==0.13.2 # also change in .pre-commit-config.yaml when updating pyupgrade==3.20.0 # also change in .pre-commit-config.yaml when updating pre-commit From 3eb502b32868ba17763e5925f9c9c84be12917a5 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 25 Sep 2025 15:53:21 -0500 Subject: [PATCH 3/7] Add sha256 support (#10882) --- CODEOWNERS | 1 + esphome/components/md5/md5.cpp | 26 ------ esphome/components/md5/md5.h | 30 +++---- esphome/components/sha256/__init__.py | 22 +++++ esphome/components/sha256/sha256.cpp | 83 +++++++++++++++++++ esphome/components/sha256/sha256.h | 56 +++++++++++++ esphome/core/defines.h | 1 + esphome/core/hash_base.h | 56 +++++++++++++ esphome/core/helpers.h | 11 +++ tests/components/sha256/common.yaml | 32 +++++++ tests/components/sha256/test.bk72xx-ard.yaml | 1 + tests/components/sha256/test.esp32-idf.yaml | 1 + tests/components/sha256/test.esp8266-ard.yaml | 1 + tests/components/sha256/test.host.yaml | 1 + tests/components/sha256/test.rp2040-ard.yaml | 1 + 15 files changed, 277 insertions(+), 46 deletions(-) create mode 100644 esphome/components/sha256/__init__.py create mode 100644 esphome/components/sha256/sha256.cpp create mode 100644 esphome/components/sha256/sha256.h create mode 100644 esphome/core/hash_base.h create mode 100644 tests/components/sha256/common.yaml create mode 100644 tests/components/sha256/test.bk72xx-ard.yaml create mode 100644 tests/components/sha256/test.esp32-idf.yaml create mode 100644 tests/components/sha256/test.esp8266-ard.yaml create mode 100644 tests/components/sha256/test.host.yaml create mode 100644 tests/components/sha256/test.rp2040-ard.yaml diff --git a/CODEOWNERS b/CODEOWNERS index b35b11c705..3747acd2b5 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -407,6 +407,7 @@ esphome/components/sensor/* @esphome/core esphome/components/sfa30/* @ghsensdev esphome/components/sgp40/* @SenexCrenshaw esphome/components/sgp4x/* @martgras @SenexCrenshaw +esphome/components/sha256/* @esphome/core esphome/components/shelly_dimmer/* @edge90 @rnauber esphome/components/sht3xd/* @mrtoy-me esphome/components/sht4x/* @sjtrny diff --git a/esphome/components/md5/md5.cpp b/esphome/components/md5/md5.cpp index 21bd2e1cab..866f00eda4 100644 --- a/esphome/components/md5/md5.cpp +++ b/esphome/components/md5/md5.cpp @@ -39,32 +39,6 @@ void MD5Digest::add(const uint8_t *data, size_t len) { br_md5_update(&this->ctx_ void MD5Digest::calculate() { br_md5_out(&this->ctx_, this->digest_); } #endif // USE_RP2040 -void MD5Digest::get_bytes(uint8_t *output) { memcpy(output, this->digest_, 16); } - -void MD5Digest::get_hex(char *output) { - for (size_t i = 0; i < 16; i++) { - uint8_t byte = this->digest_[i]; - output[i * 2] = format_hex_char(byte >> 4); - output[i * 2 + 1] = format_hex_char(byte & 0x0F); - } -} - -bool MD5Digest::equals_bytes(const uint8_t *expected) { - for (size_t i = 0; i < 16; i++) { - if (expected[i] != this->digest_[i]) { - return false; - } - } - return true; -} - -bool MD5Digest::equals_hex(const char *expected) { - uint8_t parsed[16]; - if (!parse_hex(expected, parsed, 16)) - return false; - return equals_bytes(parsed); -} - } // namespace md5 } // namespace esphome #endif diff --git a/esphome/components/md5/md5.h b/esphome/components/md5/md5.h index be1df40423..b0da2c0a3b 100644 --- a/esphome/components/md5/md5.h +++ b/esphome/components/md5/md5.h @@ -3,6 +3,8 @@ #include "esphome/core/defines.h" #ifdef USE_MD5 +#include "esphome/core/hash_base.h" + #ifdef USE_ESP32 #include "esp_rom_md5.h" #define MD5_CTX_TYPE md5_context_t @@ -26,38 +28,26 @@ namespace esphome { namespace md5 { -class MD5Digest { +class MD5Digest : public HashBase { public: MD5Digest() = default; - ~MD5Digest() = default; + ~MD5Digest() override = default; /// Initialize a new MD5 digest computation. - void init(); + void init() override; /// 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); } + void add(const uint8_t *data, size_t len) override; + using HashBase::add; // Bring base class overload into scope /// Compute the digest, based on the provided data. - void calculate(); + void calculate() override; - /// Retrieve the MD5 digest as bytes. - /// The output must be able to hold 16 bytes or more. - void get_bytes(uint8_t *output); - - /// Retrieve the 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); + /// Get the size of the hash in bytes (16 for MD5) + size_t get_size() const override { return 16; } protected: MD5_CTX_TYPE ctx_{}; - uint8_t digest_[16]; }; } // namespace md5 diff --git a/esphome/components/sha256/__init__.py b/esphome/components/sha256/__init__.py new file mode 100644 index 0000000000..f07157416d --- /dev/null +++ b/esphome/components/sha256/__init__.py @@ -0,0 +1,22 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.core import CORE +from esphome.helpers import IS_MACOS +from esphome.types import ConfigType + +CODEOWNERS = ["@esphome/core"] + +sha256_ns = cg.esphome_ns.namespace("sha256") + +CONFIG_SCHEMA = cv.Schema({}) + + +async def to_code(config: ConfigType) -> None: + # Add OpenSSL library for host platform + if not CORE.is_host: + return + if IS_MACOS: + # macOS needs special handling for Homebrew OpenSSL + cg.add_build_flag("-I/opt/homebrew/opt/openssl/include") + cg.add_build_flag("-L/opt/homebrew/opt/openssl/lib") + cg.add_build_flag("-lcrypto") diff --git a/esphome/components/sha256/sha256.cpp b/esphome/components/sha256/sha256.cpp new file mode 100644 index 0000000000..199460acbc --- /dev/null +++ b/esphome/components/sha256/sha256.cpp @@ -0,0 +1,83 @@ +#include "sha256.h" + +// Only compile SHA256 implementation on platforms that support it +#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) || defined(USE_HOST) + +#include "esphome/core/helpers.h" +#include + +namespace esphome::sha256 { + +#if defined(USE_ESP32) || defined(USE_LIBRETINY) + +SHA256::~SHA256() { mbedtls_sha256_free(&this->ctx_); } + +void SHA256::init() { + mbedtls_sha256_init(&this->ctx_); + mbedtls_sha256_starts(&this->ctx_, 0); // 0 = SHA256, not SHA224 +} + +void SHA256::add(const uint8_t *data, size_t len) { mbedtls_sha256_update(&this->ctx_, data, len); } + +void SHA256::calculate() { mbedtls_sha256_finish(&this->ctx_, this->digest_); } + +#elif defined(USE_ESP8266) || defined(USE_RP2040) + +SHA256::~SHA256() = default; + +void SHA256::init() { + br_sha256_init(&this->ctx_); + this->calculated_ = false; +} + +void SHA256::add(const uint8_t *data, size_t len) { br_sha256_update(&this->ctx_, data, len); } + +void SHA256::calculate() { + if (!this->calculated_) { + br_sha256_out(&this->ctx_, this->digest_); + this->calculated_ = true; + } +} + +#elif defined(USE_HOST) + +SHA256::~SHA256() { + if (this->ctx_) { + EVP_MD_CTX_free(this->ctx_); + } +} + +void SHA256::init() { + if (this->ctx_) { + EVP_MD_CTX_free(this->ctx_); + } + this->ctx_ = EVP_MD_CTX_new(); + EVP_DigestInit_ex(this->ctx_, EVP_sha256(), nullptr); + this->calculated_ = false; +} + +void SHA256::add(const uint8_t *data, size_t len) { + if (!this->ctx_) { + this->init(); + } + EVP_DigestUpdate(this->ctx_, data, len); +} + +void SHA256::calculate() { + if (!this->ctx_) { + this->init(); + } + if (!this->calculated_) { + unsigned int len = 32; + EVP_DigestFinal_ex(this->ctx_, this->digest_, &len); + this->calculated_ = true; + } +} + +#else +#error "SHA256 not supported on this platform" +#endif + +} // namespace esphome::sha256 + +#endif // Platform check diff --git a/esphome/components/sha256/sha256.h b/esphome/components/sha256/sha256.h new file mode 100644 index 0000000000..bb089bc314 --- /dev/null +++ b/esphome/components/sha256/sha256.h @@ -0,0 +1,56 @@ +#pragma once + +#include "esphome/core/defines.h" + +// Only define SHA256 on platforms that support it +#if defined(USE_ESP32) || defined(USE_ESP8266) || defined(USE_RP2040) || defined(USE_LIBRETINY) || defined(USE_HOST) + +#include +#include +#include +#include "esphome/core/hash_base.h" + +#if defined(USE_ESP32) || defined(USE_LIBRETINY) +#include "mbedtls/sha256.h" +#elif defined(USE_ESP8266) || defined(USE_RP2040) +#include +#elif defined(USE_HOST) +#include +#else +#error "SHA256 not supported on this platform" +#endif + +namespace esphome::sha256 { + +class SHA256 : public esphome::HashBase { + public: + SHA256() = default; + ~SHA256() override; + + void init() override; + void add(const uint8_t *data, size_t len) override; + using HashBase::add; // Bring base class overload into scope + void add(const std::string &data) { this->add((const uint8_t *) data.c_str(), data.length()); } + + void calculate() override; + + /// Get the size of the hash in bytes (32 for SHA256) + size_t get_size() const override { return 32; } + + protected: +#if defined(USE_ESP32) || defined(USE_LIBRETINY) + mbedtls_sha256_context ctx_{}; +#elif defined(USE_ESP8266) || defined(USE_RP2040) + br_sha256_context ctx_{}; + bool calculated_{false}; +#elif defined(USE_HOST) + EVP_MD_CTX *ctx_{nullptr}; + bool calculated_{false}; +#else +#error "SHA256 not supported on this platform" +#endif +}; + +} // namespace esphome::sha256 + +#endif // Platform check diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 784e8cd2b3..ef93fd0b65 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -116,6 +116,7 @@ #define USE_API_PLAINTEXT #define USE_API_SERVICES #define USE_MD5 +#define USE_SHA256 #define USE_MQTT #define USE_NETWORK #define USE_ONLINE_IMAGE_BMP_SUPPORT diff --git a/esphome/core/hash_base.h b/esphome/core/hash_base.h new file mode 100644 index 0000000000..4eb6a89f53 --- /dev/null +++ b/esphome/core/hash_base.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include +#include +#include "esphome/core/helpers.h" + +namespace esphome { + +/// Base class for hash algorithms +class HashBase { + public: + virtual ~HashBase() = default; + + /// Initialize a new hash computation + virtual void init() = 0; + + /// Add bytes of data for the hash + virtual void add(const uint8_t *data, size_t len) = 0; + void add(const char *data, size_t len) { this->add((const uint8_t *) data, len); } + + /// Compute the hash based on provided data + virtual void calculate() = 0; + + /// Retrieve the hash as bytes + void get_bytes(uint8_t *output) { memcpy(output, this->digest_, this->get_size()); } + + /// Retrieve the hash as hex characters + void get_hex(char *output) { + for (size_t i = 0; i < this->get_size(); i++) { + uint8_t byte = this->digest_[i]; + output[i * 2] = format_hex_char(byte >> 4); + output[i * 2 + 1] = format_hex_char(byte & 0x0F); + } + } + + /// Compare the hash against a provided byte-encoded hash + bool equals_bytes(const uint8_t *expected) { return memcmp(this->digest_, expected, this->get_size()) == 0; } + + /// Compare the hash against a provided hex-encoded hash + bool equals_hex(const char *expected) { + uint8_t parsed[this->get_size()]; + if (!parse_hex(expected, parsed, this->get_size())) { + return false; + } + return this->equals_bytes(parsed); + } + + /// Get the size of the hash in bytes (16 for MD5, 32 for SHA256) + virtual size_t get_size() const = 0; + + protected: + uint8_t digest_[32]; // Storage sized for max(MD5=16, SHA256=32) bytes +}; + +} // namespace esphome diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 21aa159b25..a28718de5a 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -82,6 +82,16 @@ template constexpr T byteswap(T n) { return m; } template<> constexpr uint8_t byteswap(uint8_t n) { return n; } +#ifdef USE_LIBRETINY +// LibreTiny's Beken framework redefines __builtin_bswap functions as non-constexpr +template<> inline uint16_t byteswap(uint16_t n) { return __builtin_bswap16(n); } +template<> inline uint32_t byteswap(uint32_t n) { return __builtin_bswap32(n); } +template<> inline uint64_t byteswap(uint64_t n) { return __builtin_bswap64(n); } +template<> inline int8_t byteswap(int8_t n) { return n; } +template<> inline int16_t byteswap(int16_t n) { return __builtin_bswap16(n); } +template<> inline int32_t byteswap(int32_t n) { return __builtin_bswap32(n); } +template<> inline int64_t byteswap(int64_t n) { return __builtin_bswap64(n); } +#else template<> constexpr uint16_t byteswap(uint16_t n) { return __builtin_bswap16(n); } template<> constexpr uint32_t byteswap(uint32_t n) { return __builtin_bswap32(n); } template<> constexpr uint64_t byteswap(uint64_t n) { return __builtin_bswap64(n); } @@ -89,6 +99,7 @@ template<> constexpr int8_t byteswap(int8_t n) { return n; } template<> constexpr int16_t byteswap(int16_t n) { return __builtin_bswap16(n); } template<> constexpr int32_t byteswap(int32_t n) { return __builtin_bswap32(n); } template<> constexpr int64_t byteswap(int64_t n) { return __builtin_bswap64(n); } +#endif ///@} diff --git a/tests/components/sha256/common.yaml b/tests/components/sha256/common.yaml new file mode 100644 index 0000000000..fa884c1958 --- /dev/null +++ b/tests/components/sha256/common.yaml @@ -0,0 +1,32 @@ +esphome: + on_boot: + - lambda: |- + // Test SHA256 functionality + #ifdef USE_SHA256 + using esphome::sha256::SHA256; + SHA256 hasher; + hasher.init(); + + // Test with "Hello World" - known SHA256 + const char* test_string = "Hello World"; + hasher.add(test_string, strlen(test_string)); + hasher.calculate(); + + char hex_output[65]; + hasher.get_hex(hex_output); + hex_output[64] = '\0'; + + ESP_LOGD("SHA256", "SHA256('Hello World') = %s", hex_output); + + // Expected: a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e + const char* expected = "a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e"; + if (strcmp(hex_output, expected) == 0) { + ESP_LOGI("SHA256", "Test PASSED"); + } else { + ESP_LOGE("SHA256", "Test FAILED. Expected %s", expected); + } + #else + ESP_LOGW("SHA256", "SHA256 not available on this platform"); + #endif + +sha256: diff --git a/tests/components/sha256/test.bk72xx-ard.yaml b/tests/components/sha256/test.bk72xx-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/sha256/test.bk72xx-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/sha256/test.esp32-idf.yaml b/tests/components/sha256/test.esp32-idf.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/sha256/test.esp32-idf.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/sha256/test.esp8266-ard.yaml b/tests/components/sha256/test.esp8266-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/sha256/test.esp8266-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/sha256/test.host.yaml b/tests/components/sha256/test.host.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/sha256/test.host.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/sha256/test.rp2040-ard.yaml b/tests/components/sha256/test.rp2040-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/sha256/test.rp2040-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml From 28f09f9ed172a45d6e5a3f7bc9d1587174385762 Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Thu, 25 Sep 2025 16:53:34 -0400 Subject: [PATCH 4/7] [dashboard] Fix progress bars on Windows (#10858) --- esphome/dashboard/web_server.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/esphome/dashboard/web_server.py b/esphome/dashboard/web_server.py index e3a0013e2f..b5601c9e0f 100644 --- a/esphome/dashboard/web_server.py +++ b/esphome/dashboard/web_server.py @@ -283,11 +283,23 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler): def _stdout_thread(self) -> None: if not self._use_popen: return + line = b"" + cr = False while True: - data = self._proc.stdout.readline() + data = self._proc.stdout.read(1) if data: - data = data.replace(b"\r", b"") - self._queue.put_nowait(data) + if data == b"\r": + cr = True + elif data == b"\n": + self._queue.put_nowait(line + b"\n") + line = b"" + cr = False + elif cr: + self._queue.put_nowait(line + b"\r") + line = data + cr = False + else: + line += data if self._proc.poll() is not None: break self._proc.wait(1.0) From cef9cf49bf4f1a7037c5c3e7bb5e160be150dece Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Thu, 25 Sep 2025 16:54:38 -0400 Subject: [PATCH 5/7] [htu21d] Fix I2C NACK issue and buffer overrun (#10801) --- esphome/components/htu21d/htu21d.cpp | 31 ++++++++++++---------------- esphome/components/htu21d/htu21d.h | 2 +- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/esphome/components/htu21d/htu21d.cpp b/esphome/components/htu21d/htu21d.cpp index f2e7ae93cb..a7aae16f17 100644 --- a/esphome/components/htu21d/htu21d.cpp +++ b/esphome/components/htu21d/htu21d.cpp @@ -9,8 +9,8 @@ static const char *const TAG = "htu21d"; static const uint8_t HTU21D_ADDRESS = 0x40; static const uint8_t HTU21D_REGISTER_RESET = 0xFE; -static const uint8_t HTU21D_REGISTER_TEMPERATURE = 0xF3; -static const uint8_t HTU21D_REGISTER_HUMIDITY = 0xF5; +static const uint8_t HTU21D_REGISTER_TEMPERATURE = 0xE3; +static const uint8_t HTU21D_REGISTER_HUMIDITY = 0xE5; static const uint8_t HTU21D_WRITERHT_REG_CMD = 0xE6; /**< Write RH/T User Register 1 */ static const uint8_t HTU21D_REGISTER_STATUS = 0xE7; static const uint8_t HTU21D_WRITEHEATER_REG_CMD = 0x51; /**< Write Heater Control Register */ @@ -57,7 +57,6 @@ void HTU21DComponent::update() { if (this->temperature_ != nullptr) this->temperature_->publish_state(temperature); - this->status_clear_warning(); if (this->write(&HTU21D_REGISTER_HUMIDITY, 1) != i2c::ERROR_OK) { this->status_set_warning(); @@ -79,10 +78,11 @@ void HTU21DComponent::update() { if (this->humidity_ != nullptr) this->humidity_->publish_state(humidity); - int8_t heater_level; + this->status_clear_warning(); // HTU21D does have a heater module but does not have heater level // Setting heater level to 1 in case the heater is ON + uint8_t heater_level = 0; if (this->sensor_model_ == HTU21D_SENSOR_MODEL_HTU21D) { if (this->is_heater_enabled()) { heater_level = 1; @@ -97,34 +97,30 @@ void HTU21DComponent::update() { if (this->heater_ != nullptr) this->heater_->publish_state(heater_level); - this->status_clear_warning(); }); }); } bool HTU21DComponent::is_heater_enabled() { uint8_t raw_heater; - if (this->read_register(HTU21D_REGISTER_STATUS, reinterpret_cast(&raw_heater), 2) != i2c::ERROR_OK) { + if (this->read_register(HTU21D_REGISTER_STATUS, &raw_heater, 1) != i2c::ERROR_OK) { this->status_set_warning(); return false; } - raw_heater = i2c::i2ctohs(raw_heater); - return (bool) (((raw_heater) >> (HTU21D_REG_HTRE_BIT)) & 0x01); + return (bool) ((raw_heater >> HTU21D_REG_HTRE_BIT) & 0x01); } void HTU21DComponent::set_heater(bool status) { uint8_t raw_heater; - if (this->read_register(HTU21D_REGISTER_STATUS, reinterpret_cast(&raw_heater), 2) != i2c::ERROR_OK) { + if (this->read_register(HTU21D_REGISTER_STATUS, &raw_heater, 1) != i2c::ERROR_OK) { this->status_set_warning(); return; } - raw_heater = i2c::i2ctohs(raw_heater); if (status) { - raw_heater |= (1 << (HTU21D_REG_HTRE_BIT)); + raw_heater |= (1 << HTU21D_REG_HTRE_BIT); } else { - raw_heater &= ~(1 << (HTU21D_REG_HTRE_BIT)); + raw_heater &= ~(1 << HTU21D_REG_HTRE_BIT); } - if (this->write_register(HTU21D_WRITERHT_REG_CMD, &raw_heater, 1) != i2c::ERROR_OK) { this->status_set_warning(); return; @@ -138,14 +134,13 @@ void HTU21DComponent::set_heater_level(uint8_t level) { } } -int8_t HTU21DComponent::get_heater_level() { - int8_t raw_heater; - if (this->read_register(HTU21D_READHEATER_REG_CMD, reinterpret_cast(&raw_heater), 2) != i2c::ERROR_OK) { +uint8_t HTU21DComponent::get_heater_level() { + uint8_t raw_heater; + if (this->read_register(HTU21D_READHEATER_REG_CMD, &raw_heater, 1) != i2c::ERROR_OK) { this->status_set_warning(); return 0; } - raw_heater = i2c::i2ctohs(raw_heater); - return raw_heater; + return raw_heater & 0xF; } float HTU21DComponent::get_setup_priority() const { return setup_priority::DATA; } diff --git a/esphome/components/htu21d/htu21d.h b/esphome/components/htu21d/htu21d.h index 8533875d43..9b3831b784 100644 --- a/esphome/components/htu21d/htu21d.h +++ b/esphome/components/htu21d/htu21d.h @@ -26,7 +26,7 @@ class HTU21DComponent : public PollingComponent, public i2c::I2CDevice { bool is_heater_enabled(); void set_heater(bool status); void set_heater_level(uint8_t level); - int8_t get_heater_level(); + uint8_t get_heater_level(); float get_setup_priority() const override; From f33819bb8e3b5aeeb51c1288789b69c54a99a25b Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Fri, 26 Sep 2025 13:12:24 +1200 Subject: [PATCH 6/7] Add some more defines for dev/ci --- esphome/core/defines.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/core/defines.h b/esphome/core/defines.h index ef93fd0b65..067ef4a4d0 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -123,7 +123,9 @@ #define USE_ONLINE_IMAGE_PNG_SUPPORT #define USE_ONLINE_IMAGE_JPEG_SUPPORT #define USE_OTA +#define USE_OTA_MD5 #define USE_OTA_PASSWORD +#define USE_OTA_SHA256 #define USE_OTA_STATE_CALLBACK #define USE_OTA_VERSION 2 #define USE_TIME_TIMEZONE From ba73061a4f8a948d518328d19a35804d97ac9efb Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 25 Sep 2025 20:36:04 -0500 Subject: [PATCH 7/7] random_bytes --- esphome/components/esphome/ota/ota_esphome.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/esphome/components/esphome/ota/ota_esphome.cpp b/esphome/components/esphome/ota/ota_esphome.cpp index 405633b990..6ffeeedb1a 100644 --- a/esphome/components/esphome/ota/ota_esphome.cpp +++ b/esphome/components/esphome/ota/ota_esphome.cpp @@ -15,6 +15,7 @@ #include "esphome/components/ota/ota_backend_esp_idf.h" #include "esphome/core/application.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" #include "esphome/core/util.h" @@ -528,14 +529,6 @@ void ESPHomeOTAComponent::log_auth_warning_(const LogString *action, const LogSt ESP_LOGW(TAG, "Auth: %s %s failed", LOG_STR_ARG(action), LOG_STR_ARG(hash_name)); } -// Helper to convert uint32 to big-endian bytes -static inline void uint32_to_bytes(uint32_t value, uint8_t *bytes) { - bytes[0] = (value >> 24) & 0xFF; - bytes[1] = (value >> 16) & 0xFF; - bytes[2] = (value >> 8) & 0xFF; - bytes[3] = value & 0xFF; -} - // Non-template function definition to reduce binary size bool ESPHomeOTAComponent::perform_hash_auth_(HashBase *hasher, const std::string &password, uint8_t auth_request, const LogString *name, char *buf) { @@ -553,10 +546,10 @@ bool ESPHomeOTAComponent::perform_hash_auth_(HashBase *hasher, const std::string hasher->init(); - // Generate nonce seed bytes - uint32_to_bytes(random_uint32(), nonce_bytes); - if (nonce_len > 4) { - uint32_to_bytes(random_uint32(), nonce_bytes + 4); + // Generate nonce seed bytes using random_bytes + if (!random_bytes(nonce_bytes, nonce_len)) { + this->log_auth_warning_(LOG_STR("Random bytes generation failed"), name); + return false; } hasher->add(nonce_bytes, nonce_len); hasher->calculate();