diff --git a/.github/actions/restore-python/action.yml b/.github/actions/restore-python/action.yml index 6d7d4f8c12..af54175c01 100644 --- a/.github/actions/restore-python/action.yml +++ b/.github/actions/restore-python/action.yml @@ -22,7 +22,7 @@ runs: python-version: ${{ inputs.python-version }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: venv # yamllint disable-line rule:line-length diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0a03579abc..ead87ad087 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,7 +47,7 @@ jobs: python-version: ${{ env.DEFAULT_PYTHON }} - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: venv # yamllint disable-line rule:line-length @@ -154,12 +154,12 @@ jobs: . venv/bin/activate pytest -vv --cov-report=xml --tb=native -n auto tests --ignore=tests/integration/ - name: Upload coverage to Codecov - uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 + uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5.5.3 with: token: ${{ secrets.CODECOV_TOKEN }} - name: Save Python virtual environment cache if: github.ref == 'refs/heads/dev' - uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: venv key: ${{ runner.os }}-${{ steps.restore-python.outputs.python-version }}-venv-${{ needs.common.outputs.cache-key }} @@ -198,7 +198,7 @@ jobs: python-version: ${{ env.DEFAULT_PYTHON }} cache-key: ${{ needs.common.outputs.cache-key }} - name: Restore components graph cache - uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: .temp/components_graph.json key: components-graph-${{ hashFiles('esphome/components/**/*.py') }} @@ -231,7 +231,7 @@ jobs: echo "benchmarks=$(echo "$output" | jq -r '.benchmarks')" >> $GITHUB_OUTPUT - name: Save components graph cache if: github.ref == 'refs/heads/dev' - uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: .temp/components_graph.json key: components-graph-${{ hashFiles('esphome/components/**/*.py') }} @@ -253,7 +253,7 @@ jobs: python-version: "3.13" - name: Restore Python virtual environment id: cache-venv - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: venv key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{ needs.common.outputs.cache-key }} @@ -387,14 +387,14 @@ jobs: - name: Cache platformio if: github.ref == 'refs/heads/dev' - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: ~/.platformio key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }} - name: Cache platformio if: github.ref != 'refs/heads/dev' - uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: ~/.platformio key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }} @@ -466,14 +466,14 @@ jobs: - name: Cache platformio if: github.ref == 'refs/heads/dev' - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: ~/.platformio key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }} - name: Cache platformio if: github.ref != 'refs/heads/dev' - uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: ~/.platformio key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }} @@ -555,14 +555,14 @@ jobs: - name: Cache platformio if: github.ref == 'refs/heads/dev' - uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: ~/.platformio key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }} - name: Cache platformio if: github.ref != 'refs/heads/dev' - uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: ~/.platformio key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }} @@ -817,7 +817,7 @@ jobs: - name: Restore cached memory analysis id: cache-memory-analysis if: steps.check-script.outputs.skip != 'true' && steps.check-tests.outputs.skip != 'true' - uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: memory-analysis-target.json key: ${{ steps.cache-key.outputs.cache-key }} @@ -841,7 +841,7 @@ jobs: - name: Cache platformio if: steps.check-script.outputs.skip != 'true' && steps.check-tests.outputs.skip != 'true' && steps.cache-memory-analysis.outputs.cache-hit != 'true' - uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: ~/.platformio key: platformio-memory-${{ fromJSON(needs.determine-jobs.outputs.memory_impact).platform }}-${{ hashFiles('platformio.ini') }} @@ -882,7 +882,7 @@ jobs: - name: Save memory analysis to cache if: steps.check-script.outputs.skip != 'true' && steps.check-tests.outputs.skip != 'true' && steps.cache-memory-analysis.outputs.cache-hit != 'true' && steps.build.outcome == 'success' - uses: actions/cache/save@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: memory-analysis-target.json key: ${{ steps.cache-key.outputs.cache-key }} @@ -929,7 +929,7 @@ jobs: python-version: ${{ env.DEFAULT_PYTHON }} cache-key: ${{ needs.common.outputs.cache-key }} - name: Cache platformio - uses: actions/cache/restore@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3 + uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: ~/.platformio key: platformio-memory-${{ fromJSON(needs.determine-jobs.outputs.memory_impact).platform }}-${{ hashFiles('platformio.ini') }} diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index b0d966555b..a71e5ef4ca 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -24,7 +24,7 @@ jobs: - name: Setup Python uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: - python-version: 3.13 + python-version: "3.14" - name: Install Home Assistant run: | diff --git a/esphome/components/apds9960/apds9960.cpp b/esphome/components/apds9960/apds9960.cpp index 260de82d14..a07175f2c9 100644 --- a/esphome/components/apds9960/apds9960.cpp +++ b/esphome/components/apds9960/apds9960.cpp @@ -251,11 +251,11 @@ void APDS9960::read_gesture_data_() { uint8_t buf[128]; for (uint8_t pos = 0; pos < fifo_level * 4; pos += 32) { - // The ESP's i2c driver has a limited buffer size. - // This way of retrieving the data should be wrong according to the datasheet - // but it seems to work. + // Read in 32-byte chunks due to ESP8266 I2C buffer limit. + // Always read from 0xFC — the FIFO auto-increments through 0xFC-0xFF + // and advances its internal pointer after every 4th byte. uint8_t read = std::min(32, fifo_level * 4 - pos); - APDS9960_WARNING_CHECK(this->read_bytes(0xFC + pos, buf + pos, read), "Reading FIFO buffer failed."); + APDS9960_WARNING_CHECK(this->read_bytes(0xFC, buf + pos, read), "Reading FIFO buffer failed."); } if (millis() - this->gesture_start_ > 500) { diff --git a/esphome/components/esp32/core.cpp b/esphome/components/esp32/core.cpp index cba25bca2b..83bd09b643 100644 --- a/esphome/components/esp32/core.cpp +++ b/esphome/components/esp32/core.cpp @@ -53,9 +53,6 @@ void arch_init() { } void HOT arch_feed_wdt() { esp_task_wdt_reset(); } -uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; } -const char *progmem_read_ptr(const char *const *addr) { return *addr; } -uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; } uint32_t arch_get_cpu_cycle_count() { return esp_cpu_get_cycle_count(); } uint32_t arch_get_cpu_freq_hz() { uint32_t freq = 0; diff --git a/esphome/components/host/core.cpp b/esphome/components/host/core.cpp index d5c61ec986..a662e842ee 100644 --- a/esphome/components/host/core.cpp +++ b/esphome/components/host/core.cpp @@ -58,9 +58,6 @@ void HOT arch_feed_wdt() { // pass } -uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; } -const char *progmem_read_ptr(const char *const *addr) { return *addr; } -uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; } uint32_t arch_get_cpu_cycle_count() { struct timespec spec; clock_gettime(CLOCK_MONOTONIC, &spec); diff --git a/esphome/components/libretiny/core.cpp b/esphome/components/libretiny/core.cpp index 6bb2d9dcc1..1cfe68e924 100644 --- a/esphome/components/libretiny/core.cpp +++ b/esphome/components/libretiny/core.cpp @@ -54,9 +54,6 @@ void arch_restart() { void HOT arch_feed_wdt() { lt_wdt_feed(); } uint32_t arch_get_cpu_cycle_count() { return lt_cpu_get_cycle_count(); } uint32_t arch_get_cpu_freq_hz() { return lt_cpu_get_freq(); } -uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; } -const char *progmem_read_ptr(const char *const *addr) { return *addr; } -uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; } } // namespace esphome diff --git a/esphome/components/opentherm/__init__.py b/esphome/components/opentherm/__init__.py index 36f85a9766..85632d0bf8 100644 --- a/esphome/components/opentherm/__init__.py +++ b/esphome/components/opentherm/__init__.py @@ -81,10 +81,7 @@ CONFIG_SCHEMA = cv.All( async def to_code(config: dict[str, Any]) -> None: if CORE.is_esp32: - # Re-enable ESP-IDF's legacy driver component (excluded by default to save compile time) - # Provides driver/timer.h header for hardware timer API - # TODO: Remove this once opentherm migrates to GPTimer API (driver/gptimer.h) - include_builtin_idf_component("driver") + include_builtin_idf_component("esp_driver_gptimer") var = cg.new_Pvariable(config[CONF_ID]) await cg.register_component(var, config) diff --git a/esphome/components/opentherm/opentherm.cpp b/esphome/components/opentherm/opentherm.cpp index cdf89207bc..97cf83a5aa 100644 --- a/esphome/components/opentherm/opentherm.cpp +++ b/esphome/components/opentherm/opentherm.cpp @@ -8,10 +8,7 @@ #include "opentherm.h" #include "esphome/core/helpers.h" #include -// TODO: Migrate from legacy timer API (driver/timer.h) to GPTimer API (driver/gptimer.h) -// The legacy timer API is deprecated in ESP-IDF 5.x. See opentherm.h for details. #ifdef USE_ESP32 -#include "driver/timer.h" #include "esp_err.h" #endif #ifdef ESP8266 @@ -33,10 +30,6 @@ OpenTherm *OpenTherm::instance = nullptr; OpenTherm::OpenTherm(InternalGPIOPin *in_pin, InternalGPIOPin *out_pin, int32_t device_timeout) : in_pin_(in_pin), out_pin_(out_pin), -#ifdef USE_ESP32 - timer_group_(TIMER_GROUP_0), - timer_idx_(TIMER_0), -#endif mode_(OperationMode::IDLE), error_type_(ProtocolErrorType::NO_ERROR), capture_(0), @@ -134,7 +127,12 @@ void IRAM_ATTR OpenTherm::read_() { // period in OpenTherm. } +#ifdef USE_ESP32 +bool IRAM_ATTR OpenTherm::timer_isr(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx) { + auto *arg = static_cast(user_ctx); +#else bool IRAM_ATTR OpenTherm::timer_isr(OpenTherm *arg) { +#endif if (arg->mode_ == OperationMode::LISTEN) { if (arg->timeout_counter_ == 0) { arg->mode_ = OperationMode::ERROR_TIMEOUT; @@ -243,67 +241,35 @@ void IRAM_ATTR OpenTherm::write_bit_(uint8_t high, uint8_t clock) { #ifdef USE_ESP32 bool OpenTherm::init_esp32_timer_() { - // Search for a free timer. Maybe unstable, we'll see. - int cur_timer = 0; - timer_group_t timer_group = TIMER_GROUP_0; - timer_idx_t timer_idx = TIMER_0; - bool timer_found = false; - - for (; cur_timer < SOC_TIMER_GROUP_TOTAL_TIMERS; cur_timer++) { - timer_config_t temp_config; - timer_group = cur_timer < 2 ? TIMER_GROUP_0 : TIMER_GROUP_1; - timer_idx = cur_timer < 2 ? (timer_idx_t) cur_timer : (timer_idx_t) (cur_timer - 2); - - auto err = timer_get_config(timer_group, timer_idx, &temp_config); - if (err == ESP_ERR_INVALID_ARG) { - // Error means timer was not initialized (or other things, but we are careful with our args) - timer_found = true; - break; - } - - ESP_LOGD(TAG, "Timer %d:%d seems to be occupied, will try another", timer_group, timer_idx); - } - - if (!timer_found) { - ESP_LOGE(TAG, "No free timer was found! OpenTherm cannot function without a timer."); - return false; - } - - ESP_LOGD(TAG, "Found free timer %d:%d", timer_group, timer_idx); - this->timer_group_ = timer_group; - this->timer_idx_ = timer_idx; - - timer_config_t const config = { - .alarm_en = TIMER_ALARM_EN, - .counter_en = TIMER_PAUSE, - .intr_type = TIMER_INTR_LEVEL, - .counter_dir = TIMER_COUNT_UP, - .auto_reload = TIMER_AUTORELOAD_EN, - .clk_src = TIMER_SRC_CLK_DEFAULT, - .divider = 80, + // 80MHz / 80 = 1MHz resolution (1µs per tick) + gptimer_config_t config = { + .clk_src = GPTIMER_CLK_SRC_DEFAULT, + .direction = GPTIMER_COUNT_UP, + .resolution_hz = 1000000, }; - esp_err_t result; - - result = timer_init(this->timer_group_, this->timer_idx_, &config); + esp_err_t result = gptimer_new_timer(&config, &this->timer_handle_); if (result != ESP_OK) { - const auto *error = esp_err_to_name(result); - ESP_LOGE(TAG, "Failed to init timer. Error: %s", error); + ESP_LOGE(TAG, "Failed to create timer: %s", esp_err_to_name(result)); return false; } - result = timer_set_counter_value(this->timer_group_, this->timer_idx_, 0); + gptimer_event_callbacks_t cbs = { + .on_alarm = OpenTherm::timer_isr, + }; + result = gptimer_register_event_callbacks(this->timer_handle_, &cbs, this); if (result != ESP_OK) { - const auto *error = esp_err_to_name(result); - ESP_LOGE(TAG, "Failed to set counter value. Error: %s", error); + ESP_LOGE(TAG, "Failed to register timer callback: %s", esp_err_to_name(result)); + gptimer_del_timer(this->timer_handle_); + this->timer_handle_ = nullptr; return false; } - result = timer_isr_callback_add(this->timer_group_, this->timer_idx_, reinterpret_cast(timer_isr), - this, 0); + result = gptimer_enable(this->timer_handle_); if (result != ESP_OK) { - const auto *error = esp_err_to_name(result); - ESP_LOGE(TAG, "Failed to register timer interrupt. Error: %s", error); + ESP_LOGE(TAG, "Failed to enable timer: %s", esp_err_to_name(result)); + gptimer_del_timer(this->timer_handle_); + this->timer_handle_ = nullptr; return false; } @@ -315,12 +281,13 @@ void IRAM_ATTR OpenTherm::start_esp32_timer_(uint64_t alarm_value) { this->timer_error_ = ESP_OK; this->timer_error_type_ = TimerErrorType::NO_TIMER_ERROR; - this->timer_error_ = timer_set_alarm_value(this->timer_group_, this->timer_idx_, alarm_value); + this->alarm_config_.alarm_count = alarm_value; + this->timer_error_ = gptimer_set_alarm_action(this->timer_handle_, &this->alarm_config_); if (this->timer_error_ != ESP_OK) { this->timer_error_type_ = TimerErrorType::SET_ALARM_VALUE_ERROR; return; } - this->timer_error_ = timer_start(this->timer_group_, this->timer_idx_); + this->timer_error_ = gptimer_start(this->timer_handle_); if (this->timer_error_ != ESP_OK) { this->timer_error_type_ = TimerErrorType::TIMER_START_ERROR; } @@ -356,12 +323,12 @@ void IRAM_ATTR OpenTherm::stop_timer_() { this->timer_error_ = ESP_OK; this->timer_error_type_ = TimerErrorType::NO_TIMER_ERROR; - this->timer_error_ = timer_pause(this->timer_group_, this->timer_idx_); + this->timer_error_ = gptimer_stop(this->timer_handle_); if (this->timer_error_ != ESP_OK) { this->timer_error_type_ = TimerErrorType::TIMER_PAUSE_ERROR; return; } - this->timer_error_ = timer_set_counter_value(this->timer_group_, this->timer_idx_, 0); + this->timer_error_ = gptimer_set_raw_count(this->timer_handle_, 0); if (this->timer_error_ != ESP_OK) { this->timer_error_type_ = TimerErrorType::SET_COUNTER_VALUE_ERROR; } diff --git a/esphome/components/opentherm/opentherm.h b/esphome/components/opentherm/opentherm.h index a2c347d0d8..eb8c5b3ad6 100644 --- a/esphome/components/opentherm/opentherm.h +++ b/esphome/components/opentherm/opentherm.h @@ -12,12 +12,8 @@ #include "esphome/core/helpers.h" #include "esphome/core/log.h" -// TODO: Migrate from legacy timer API (driver/timer.h) to GPTimer API (driver/gptimer.h) -// The legacy timer API is deprecated in ESP-IDF 5.x. Migration would allow removing the -// "driver" IDF component dependency. See: -// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/migration-guides/release-5.x/5.0/peripherals.html#id4 #ifdef USE_ESP32 -#include "driver/timer.h" +#include "driver/gptimer.h" #endif namespace esphome { @@ -348,7 +344,11 @@ class OpenTherm { const char *operation_mode_to_str(OperationMode mode); const char *message_id_to_str(MessageId id); +#ifdef USE_ESP32 + static bool timer_isr(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *user_ctx); +#else static bool timer_isr(OpenTherm *arg); +#endif #ifdef ESP8266 static void esp8266_timer_isr(); @@ -361,8 +361,12 @@ class OpenTherm { ISRInternalGPIOPin isr_out_pin_; #ifdef USE_ESP32 - timer_group_t timer_group_; - timer_idx_t timer_idx_; + gptimer_handle_t timer_handle_{nullptr}; + gptimer_alarm_config_t alarm_config_{ + .alarm_count = 0, + .reload_count = 0, + .flags = {.auto_reload_on_alarm = true}, + }; #endif OperationMode mode_; diff --git a/esphome/components/rp2040/core.cpp b/esphome/components/rp2040/core.cpp index 7079cbca15..b7a9000612 100644 --- a/esphome/components/rp2040/core.cpp +++ b/esphome/components/rp2040/core.cpp @@ -37,13 +37,6 @@ void arch_init() { void HOT arch_feed_wdt() { watchdog_update(); } -uint8_t progmem_read_byte(const uint8_t *addr) { - return pgm_read_byte(addr); // NOLINT -} -const char *progmem_read_ptr(const char *const *addr) { - return reinterpret_cast(pgm_read_ptr(addr)); // NOLINT -} -uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; } uint32_t HOT arch_get_cpu_cycle_count() { return ulMainGetRunTimeCounterValue(); } uint32_t arch_get_cpu_freq_hz() { return RP2040::f_cpu(); } diff --git a/esphome/components/tc74/tc74.cpp b/esphome/components/tc74/tc74.cpp index 969ef3671e..cb58e583dc 100644 --- a/esphome/components/tc74/tc74.cpp +++ b/esphome/components/tc74/tc74.cpp @@ -50,8 +50,9 @@ void TC74Component::read_temperature_() { } } - uint8_t temperature_reg; - if (this->read_register(TC74_REGISTER_TEMPERATURE, &temperature_reg, 1) != i2c::ERROR_OK) { + int8_t temperature_reg; + if (this->read_register(TC74_REGISTER_TEMPERATURE, reinterpret_cast(&temperature_reg), 1) != + i2c::ERROR_OK) { this->status_set_warning(); return; } diff --git a/esphome/components/zephyr/core.cpp b/esphome/components/zephyr/core.cpp index 1d105a1057..d7c77fdd2c 100644 --- a/esphome/components/zephyr/core.cpp +++ b/esphome/components/zephyr/core.cpp @@ -59,9 +59,6 @@ void arch_feed_wdt() { void arch_restart() { sys_reboot(SYS_REBOOT_COLD); } uint32_t arch_get_cpu_cycle_count() { return k_cycle_get_32(); } uint32_t arch_get_cpu_freq_hz() { return sys_clock_hw_cycles_per_sec(); } -uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; } -const char *progmem_read_ptr(const char *const *addr) { return *addr; } -uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; } Mutex::Mutex() { auto *mutex = new k_mutex(); diff --git a/esphome/core/hal.h b/esphome/core/hal.h index c2c9b1a325..03a30b7459 100644 --- a/esphome/core/hal.h +++ b/esphome/core/hal.h @@ -41,8 +41,17 @@ void arch_init(); void arch_feed_wdt(); uint32_t arch_get_cpu_cycle_count(); uint32_t arch_get_cpu_freq_hz(); + +#ifdef USE_ESP8266 +// ESP8266: pgm_read_* does real flash reads on Harvard architecture uint8_t progmem_read_byte(const uint8_t *addr); const char *progmem_read_ptr(const char *const *addr); uint16_t progmem_read_uint16(const uint16_t *addr); +#else +// All other platforms: PROGMEM is a no-op, so these are direct dereferences +inline uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; } +inline const char *progmem_read_ptr(const char *const *addr) { return *addr; } +inline uint16_t progmem_read_uint16(const uint16_t *addr) { return *addr; } +#endif } // namespace esphome diff --git a/requirements.txt b/requirements.txt index da95dd5a13..f8f60f1932 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ platformio==6.1.19 esptool==5.2.0 click==8.3.1 esphome-dashboard==20260210.0 -aioesphomeapi==44.5.2 +aioesphomeapi==44.6.0 zeroconf==0.148.0 puremagic==1.30 ruamel.yaml==0.19.1 # dashboard_import