diff --git a/CODEOWNERS b/CODEOWNERS index cd11c7796f..f85993bd87 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -246,6 +246,7 @@ esphome/components/lcd_menu/* @numo68 esphome/components/ld2410/* @regevbr @sebcaps esphome/components/ld2420/* @descipher esphome/components/ld2450/* @hareeshmu +esphome/components/ld24xx/* @kbx81 esphome/components/ledc/* @OttoWinter esphome/components/libretiny/* @kuba2k2 esphome/components/libretiny_pwm/* @kuba2k2 diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 9bcd0e068a..ea87da4ce4 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -31,7 +31,7 @@ from esphome.const import ( KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, PLATFORM_ESP32, - CoreModel, + ThreadModel, __version__, ) from esphome.core import CORE, HexInt, TimePeriod @@ -98,16 +98,6 @@ ARDUINO_ALLOWED_VARIANTS = [ VARIANT_ESP32S3, ] -# Single-core ESP32 variants -SINGLE_CORE_VARIANTS = frozenset( - [ - VARIANT_ESP32S2, - VARIANT_ESP32C3, - VARIANT_ESP32C6, - VARIANT_ESP32H2, - ] -) - def get_cpu_frequencies(*frequencies): return [str(x) + "MHZ" for x in frequencies] @@ -732,11 +722,7 @@ async def to_code(config): cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) cg.add_build_flag(f"-DUSE_ESP32_VARIANT_{config[CONF_VARIANT]}") cg.add_define("ESPHOME_VARIANT", VARIANT_FRIENDLY[config[CONF_VARIANT]]) - # Set threading model based on core count - if config[CONF_VARIANT] in SINGLE_CORE_VARIANTS: - cg.add_define(CoreModel.SINGLE) - else: - cg.add_define(CoreModel.MULTI_ATOMICS) + cg.add_define(ThreadModel.MULTI_ATOMICS) cg.add_platformio_option("lib_ldf_mode", "off") cg.add_platformio_option("lib_compat_mode", "strict") diff --git a/esphome/components/esp8266/__init__.py b/esphome/components/esp8266/__init__.py index d08d7121b7..0184c25965 100644 --- a/esphome/components/esp8266/__init__.py +++ b/esphome/components/esp8266/__init__.py @@ -15,7 +15,7 @@ from esphome.const import ( KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, PLATFORM_ESP8266, - CoreModel, + ThreadModel, ) from esphome.core import CORE, coroutine_with_priority from esphome.helpers import copy_file_if_changed @@ -188,7 +188,7 @@ async def to_code(config): cg.set_cpp_standard("gnu++20") cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) cg.add_define("ESPHOME_VARIANT", "ESP8266") - cg.add_define(CoreModel.SINGLE) + cg.add_define(ThreadModel.SINGLE) cg.add_platformio_option("extra_scripts", ["post:post_build.py"]) diff --git a/esphome/components/host/__init__.py b/esphome/components/host/__init__.py index 2d77f2f7ab..ba05e497c8 100644 --- a/esphome/components/host/__init__.py +++ b/esphome/components/host/__init__.py @@ -7,7 +7,7 @@ from esphome.const import ( KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, PLATFORM_HOST, - CoreModel, + ThreadModel, ) from esphome.core import CORE @@ -44,7 +44,7 @@ async def to_code(config): cg.add_define("USE_ESPHOME_HOST_MAC_ADDRESS", config[CONF_MAC_ADDRESS].parts) cg.add_build_flag("-std=gnu++20") cg.add_define("ESPHOME_BOARD", "host") - cg.add_define(CoreModel.MULTI_ATOMICS) + cg.add_define(ThreadModel.MULTI_ATOMICS) cg.add_platformio_option("platform", "platformio/native") cg.add_platformio_option("lib_ldf_mode", "off") cg.add_platformio_option("lib_compat_mode", "strict") diff --git a/esphome/components/ld2410/__init__.py b/esphome/components/ld2410/__init__.py index c58b9a4017..4918190179 100644 --- a/esphome/components/ld2410/__init__.py +++ b/esphome/components/ld2410/__init__.py @@ -5,6 +5,7 @@ from esphome.components import uart import esphome.config_validation as cv from esphome.const import CONF_ID, CONF_PASSWORD, CONF_THROTTLE, CONF_TIMEOUT +AUTO_LOAD = ["ld24xx"] DEPENDENCIES = ["uart"] CODEOWNERS = ["@sebcaps", "@regevbr"] MULTI_CONF = True diff --git a/esphome/components/ld2410/ld2410.cpp b/esphome/components/ld2410/ld2410.cpp index 8f1fb0ee9d..bb6d63a963 100644 --- a/esphome/components/ld2410/ld2410.cpp +++ b/esphome/components/ld2410/ld2410.cpp @@ -1,6 +1,5 @@ #include "ld2410.h" -#include #ifdef USE_NUMBER #include "esphome/components/number/number.h" #endif @@ -10,10 +9,6 @@ #include "esphome/core/application.h" -#define CHECK_BIT(var, pos) (((var) >> (pos)) & 1) -#define highbyte(val) (uint8_t)((val) >> 8) -#define lowbyte(val) (uint8_t)((val) &0xff) - namespace esphome { namespace ld2410 { @@ -165,6 +160,9 @@ static constexpr uint8_t CMD_BLUETOOTH = 0xA4; static constexpr uint8_t CMD_MAX_MOVE_VALUE = 0x00; static constexpr uint8_t CMD_MAX_STILL_VALUE = 0x01; static constexpr uint8_t CMD_DURATION_VALUE = 0x02; +// Bitmasks for target states +static constexpr uint8_t MOVE_BITMASK = 0x01; +static constexpr uint8_t STILL_BITMASK = 0x02; // Header & Footer size static constexpr uint8_t HEADER_FOOTER_SIZE = 4; // Command Header & Footer @@ -202,17 +200,17 @@ void LD2410Component::dump_config() { #endif #ifdef USE_SENSOR ESP_LOGCONFIG(TAG, "Sensors:"); - LOG_SENSOR(" ", "Light", this->light_sensor_); - LOG_SENSOR(" ", "DetectionDistance", this->detection_distance_sensor_); - LOG_SENSOR(" ", "MovingTargetDistance", this->moving_target_distance_sensor_); - LOG_SENSOR(" ", "MovingTargetEnergy", this->moving_target_energy_sensor_); - LOG_SENSOR(" ", "StillTargetDistance", this->still_target_distance_sensor_); - LOG_SENSOR(" ", "StillTargetEnergy", this->still_target_energy_sensor_); - for (sensor::Sensor *s : this->gate_move_sensors_) { - LOG_SENSOR(" ", "GateMove", s); + LOG_SENSOR_WITH_DEDUP_SAFE(" ", "Light", this->light_sensor_); + LOG_SENSOR_WITH_DEDUP_SAFE(" ", "DetectionDistance", this->detection_distance_sensor_); + LOG_SENSOR_WITH_DEDUP_SAFE(" ", "MovingTargetDistance", this->moving_target_distance_sensor_); + LOG_SENSOR_WITH_DEDUP_SAFE(" ", "MovingTargetEnergy", this->moving_target_energy_sensor_); + LOG_SENSOR_WITH_DEDUP_SAFE(" ", "StillTargetDistance", this->still_target_distance_sensor_); + LOG_SENSOR_WITH_DEDUP_SAFE(" ", "StillTargetEnergy", this->still_target_energy_sensor_); + for (auto &s : this->gate_move_sensors_) { + LOG_SENSOR_WITH_DEDUP_SAFE(" ", "GateMove", s); } - for (sensor::Sensor *s : this->gate_still_sensors_) { - LOG_SENSOR(" ", "GateStill", s); + for (auto &s : this->gate_still_sensors_) { + LOG_SENSOR_WITH_DEDUP_SAFE(" ", "GateStill", s); } #endif #ifdef USE_TEXT_SENSOR @@ -304,8 +302,10 @@ void LD2410Component::send_command_(uint8_t command, const uint8_t *command_valu } // frame footer bytes this->write_array(CMD_FRAME_FOOTER, sizeof(CMD_FRAME_FOOTER)); - // FIXME to remove - delay(50); // NOLINT + + if (command != CMD_ENABLE_CONF && command != CMD_DISABLE_CONF) { + delay(50); // NOLINT + } } void LD2410Component::handle_periodic_data_() { @@ -348,10 +348,10 @@ void LD2410Component::handle_periodic_data_() { this->target_binary_sensor_->publish_state(target_state != 0x00); } if (this->moving_target_binary_sensor_ != nullptr) { - this->moving_target_binary_sensor_->publish_state(CHECK_BIT(target_state, 0)); + this->moving_target_binary_sensor_->publish_state(target_state & MOVE_BITMASK); } if (this->still_target_binary_sensor_ != nullptr) { - this->still_target_binary_sensor_->publish_state(CHECK_BIT(target_state, 1)); + this->still_target_binary_sensor_->publish_state(target_state & STILL_BITMASK); } #endif /* @@ -362,89 +362,51 @@ void LD2410Component::handle_periodic_data_() { Detect distance: 16~17th bytes */ #ifdef USE_SENSOR - if (this->moving_target_distance_sensor_ != nullptr) { - int new_moving_target_distance = - ld2410::two_byte_to_int(this->buffer_data_[MOVING_TARGET_LOW], this->buffer_data_[MOVING_TARGET_HIGH]); - if (this->moving_target_distance_sensor_->get_state() != new_moving_target_distance) - this->moving_target_distance_sensor_->publish_state(new_moving_target_distance); - } - if (this->moving_target_energy_sensor_ != nullptr) { - int new_moving_target_energy = this->buffer_data_[MOVING_ENERGY]; - if (this->moving_target_energy_sensor_->get_state() != new_moving_target_energy) - this->moving_target_energy_sensor_->publish_state(new_moving_target_energy); - } - if (this->still_target_distance_sensor_ != nullptr) { - int new_still_target_distance = - ld2410::two_byte_to_int(this->buffer_data_[STILL_TARGET_LOW], this->buffer_data_[STILL_TARGET_HIGH]); - if (this->still_target_distance_sensor_->get_state() != new_still_target_distance) - this->still_target_distance_sensor_->publish_state(new_still_target_distance); - } - if (this->still_target_energy_sensor_ != nullptr) { - int new_still_target_energy = this->buffer_data_[STILL_ENERGY]; - if (this->still_target_energy_sensor_->get_state() != new_still_target_energy) - this->still_target_energy_sensor_->publish_state(new_still_target_energy); - } - if (this->detection_distance_sensor_ != nullptr) { - int new_detect_distance = - ld2410::two_byte_to_int(this->buffer_data_[DETECT_DISTANCE_LOW], this->buffer_data_[DETECT_DISTANCE_HIGH]); - if (this->detection_distance_sensor_->get_state() != new_detect_distance) - this->detection_distance_sensor_->publish_state(new_detect_distance); - } + SAFE_PUBLISH_SENSOR( + this->moving_target_distance_sensor_, + ld2410::two_byte_to_int(this->buffer_data_[MOVING_TARGET_LOW], this->buffer_data_[MOVING_TARGET_HIGH])) + SAFE_PUBLISH_SENSOR(this->moving_target_energy_sensor_, this->buffer_data_[MOVING_ENERGY]) + SAFE_PUBLISH_SENSOR( + this->still_target_distance_sensor_, + ld2410::two_byte_to_int(this->buffer_data_[STILL_TARGET_LOW], this->buffer_data_[STILL_TARGET_HIGH])); + SAFE_PUBLISH_SENSOR(this->still_target_energy_sensor_, this->buffer_data_[STILL_ENERGY]); + SAFE_PUBLISH_SENSOR( + this->detection_distance_sensor_, + ld2410::two_byte_to_int(this->buffer_data_[DETECT_DISTANCE_LOW], this->buffer_data_[DETECT_DISTANCE_HIGH])); + if (engineering_mode) { /* Moving distance range: 18th byte Still distance range: 19th byte Moving energy: 20~28th bytes */ - for (std::vector::size_type i = 0; i != this->gate_move_sensors_.size(); i++) { - sensor::Sensor *s = this->gate_move_sensors_[i]; - if (s != nullptr) { - s->publish_state(this->buffer_data_[MOVING_SENSOR_START + i]); - } + for (uint8_t i = 0; i < TOTAL_GATES; i++) { + SAFE_PUBLISH_SENSOR(this->gate_move_sensors_[i], this->buffer_data_[MOVING_SENSOR_START + i]) } /* Still energy: 29~37th bytes */ - for (std::vector::size_type i = 0; i != this->gate_still_sensors_.size(); i++) { - sensor::Sensor *s = this->gate_still_sensors_[i]; - if (s != nullptr) { - s->publish_state(this->buffer_data_[STILL_SENSOR_START + i]); - } + for (uint8_t i = 0; i < TOTAL_GATES; i++) { + SAFE_PUBLISH_SENSOR(this->gate_still_sensors_[i], this->buffer_data_[STILL_SENSOR_START + i]) } /* Light sensor: 38th bytes */ - if (this->light_sensor_ != nullptr) { - int new_light_sensor = this->buffer_data_[LIGHT_SENSOR]; - if (this->light_sensor_->get_state() != new_light_sensor) { - this->light_sensor_->publish_state(new_light_sensor); - } - } + SAFE_PUBLISH_SENSOR(this->light_sensor_, this->buffer_data_[LIGHT_SENSOR]) } else { - for (auto *s : this->gate_move_sensors_) { - if (s != nullptr && !std::isnan(s->get_state())) { - s->publish_state(NAN); - } + for (auto &gate_move_sensor : this->gate_move_sensors_) { + SAFE_PUBLISH_SENSOR_UNKNOWN(gate_move_sensor) } - for (auto *s : this->gate_still_sensors_) { - if (s != nullptr && !std::isnan(s->get_state())) { - s->publish_state(NAN); - } - } - if (this->light_sensor_ != nullptr && !std::isnan(this->light_sensor_->get_state())) { - this->light_sensor_->publish_state(NAN); + for (auto &gate_still_sensor : this->gate_still_sensors_) { + SAFE_PUBLISH_SENSOR_UNKNOWN(gate_still_sensor) } + SAFE_PUBLISH_SENSOR_UNKNOWN(this->light_sensor_) } #endif #ifdef USE_BINARY_SENSOR - if (engineering_mode) { - if (this->out_pin_presence_status_binary_sensor_ != nullptr) { - this->out_pin_presence_status_binary_sensor_->publish_state(this->buffer_data_[OUT_PIN_SENSOR] == 0x01); - } - } else { - if (this->out_pin_presence_status_binary_sensor_ != nullptr) { - this->out_pin_presence_status_binary_sensor_->publish_state(false); - } + if (this->out_pin_presence_status_binary_sensor_ != nullptr) { + this->out_pin_presence_status_binary_sensor_->publish_state( + engineering_mode ? this->buffer_data_[OUT_PIN_SENSOR] == 0x01 : false); } #endif } @@ -824,8 +786,14 @@ void LD2410Component::set_light_out_control() { } #ifdef USE_SENSOR -void LD2410Component::set_gate_move_sensor(uint8_t gate, sensor::Sensor *s) { this->gate_move_sensors_[gate] = s; } -void LD2410Component::set_gate_still_sensor(uint8_t gate, sensor::Sensor *s) { this->gate_still_sensors_[gate] = s; } +// These could leak memory, but they are only set once prior to 'setup()' and should never be used again. +void LD2410Component::set_gate_move_sensor(uint8_t gate, sensor::Sensor *s) { + this->gate_move_sensors_[gate] = new SensorWithDedup(s); +} + +void LD2410Component::set_gate_still_sensor(uint8_t gate, sensor::Sensor *s) { + this->gate_still_sensors_[gate] = new SensorWithDedup(s); +} #endif } // namespace ld2410 diff --git a/esphome/components/ld2410/ld2410.h b/esphome/components/ld2410/ld2410.h index 8bd1dbcb5a..e9225ccfe4 100644 --- a/esphome/components/ld2410/ld2410.h +++ b/esphome/components/ld2410/ld2410.h @@ -22,15 +22,20 @@ #ifdef USE_TEXT_SENSOR #include "esphome/components/text_sensor/text_sensor.h" #endif +#include "esphome/components/ld24xx/ld24xx.h" #include "esphome/components/uart/uart.h" #include "esphome/core/automation.h" #include "esphome/core/helpers.h" +#include + namespace esphome { namespace ld2410 { -static const uint8_t MAX_LINE_LENGTH = 46; // Max characters for serial buffer -static const uint8_t TOTAL_GATES = 9; // Total number of gates supported by the LD2410 +using namespace ld24xx; + +static constexpr uint8_t MAX_LINE_LENGTH = 46; // Max characters for serial buffer +static constexpr uint8_t TOTAL_GATES = 9; // Total number of gates supported by the LD2410 class LD2410Component : public Component, public uart::UARTDevice { #ifdef USE_BINARY_SENSOR @@ -40,12 +45,12 @@ class LD2410Component : public Component, public uart::UARTDevice { SUB_BINARY_SENSOR(target) #endif #ifdef USE_SENSOR - SUB_SENSOR(light) - SUB_SENSOR(detection_distance) - SUB_SENSOR(moving_target_distance) - SUB_SENSOR(moving_target_energy) - SUB_SENSOR(still_target_distance) - SUB_SENSOR(still_target_energy) + SUB_SENSOR_WITH_DEDUP(light, uint8_t) + SUB_SENSOR_WITH_DEDUP(detection_distance, int) + SUB_SENSOR_WITH_DEDUP(moving_target_distance, int) + SUB_SENSOR_WITH_DEDUP(moving_target_energy, uint8_t) + SUB_SENSOR_WITH_DEDUP(still_target_distance, int) + SUB_SENSOR_WITH_DEDUP(still_target_energy, uint8_t) #endif #ifdef USE_TEXT_SENSOR SUB_TEXT_SENSOR(version) @@ -122,12 +127,12 @@ class LD2410Component : public Component, public uart::UARTDevice { uint8_t version_[6] = {0, 0, 0, 0, 0, 0}; bool bluetooth_on_{false}; #ifdef USE_NUMBER - std::vector gate_move_threshold_numbers_ = std::vector(TOTAL_GATES); - std::vector gate_still_threshold_numbers_ = std::vector(TOTAL_GATES); + std::array gate_move_threshold_numbers_{}; + std::array gate_still_threshold_numbers_{}; #endif #ifdef USE_SENSOR - std::vector gate_move_sensors_ = std::vector(TOTAL_GATES); - std::vector gate_still_sensors_ = std::vector(TOTAL_GATES); + std::array *, TOTAL_GATES> gate_move_sensors_{}; + std::array *, TOTAL_GATES> gate_still_sensors_{}; #endif }; diff --git a/esphome/components/ld24xx/__init__.py b/esphome/components/ld24xx/__init__.py new file mode 100644 index 0000000000..516af84856 --- /dev/null +++ b/esphome/components/ld24xx/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@kbx81"] diff --git a/esphome/components/ld24xx/ld24xx.h b/esphome/components/ld24xx/ld24xx.h new file mode 100644 index 0000000000..1cd5e01163 --- /dev/null +++ b/esphome/components/ld24xx/ld24xx.h @@ -0,0 +1,65 @@ +#pragma once + +#include "esphome/core/defines.h" + +#include + +#ifdef USE_SENSOR +#include "esphome/core/helpers.h" +#include "esphome/components/sensor/sensor.h" + +#define SUB_SENSOR_WITH_DEDUP(name, dedup_type) \ + protected: \ + ld24xx::SensorWithDedup *name##_sensor_{nullptr}; \ +\ + public: \ + void set_##name##_sensor(sensor::Sensor *sensor) { \ + this->name##_sensor_ = new ld24xx::SensorWithDedup(sensor); \ + } +#endif + +#define LOG_SENSOR_WITH_DEDUP_SAFE(tag, name, sensor) \ + if ((sensor) != nullptr) { \ + LOG_SENSOR(tag, name, (sensor)->sens); \ + } + +#define SAFE_PUBLISH_SENSOR(sensor, value) \ + if ((sensor) != nullptr) { \ + (sensor)->publish_state_if_not_dup(value); \ + } + +#define SAFE_PUBLISH_SENSOR_UNKNOWN(sensor) \ + if ((sensor) != nullptr) { \ + (sensor)->publish_state_unknown(); \ + } + +#define highbyte(val) (uint8_t)((val) >> 8) +#define lowbyte(val) (uint8_t)((val) &0xff) + +namespace esphome { +namespace ld24xx { + +#ifdef USE_SENSOR +// Helper class to store a sensor with a deduplicator & publish state only when the value changes +template class SensorWithDedup { + public: + SensorWithDedup(sensor::Sensor *sens) : sens(sens) {} + + void publish_state_if_not_dup(T state) { + if (this->publish_dedup.next(state)) { + this->sens->publish_state(static_cast(state)); + } + } + + void publish_state_unknown() { + if (this->publish_dedup.next_unknown()) { + this->sens->publish_state(NAN); + } + } + + sensor::Sensor *sens; + Deduplicator publish_dedup; +}; +#endif +} // namespace ld24xx +} // namespace esphome diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index 7f2a0bc0a5..178660cb40 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -20,7 +20,7 @@ from esphome.const import ( KEY_FRAMEWORK_VERSION, KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, - CoreModel, + ThreadModel, __version__, ) from esphome.core import CORE @@ -261,7 +261,7 @@ async def component_to_code(config): cg.add_build_flag(f"-DUSE_LIBRETINY_VARIANT_{config[CONF_FAMILY]}") cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) cg.add_define("ESPHOME_VARIANT", FAMILY_FRIENDLY[config[CONF_FAMILY]]) - cg.add_define(CoreModel.MULTI_NO_ATOMICS) + cg.add_define(ThreadModel.MULTI_NO_ATOMICS) # force using arduino framework cg.add_platformio_option("framework", "arduino") diff --git a/esphome/components/nrf52/__init__.py b/esphome/components/nrf52/__init__.py index 870c51066c..17807b9e2b 100644 --- a/esphome/components/nrf52/__init__.py +++ b/esphome/components/nrf52/__init__.py @@ -23,7 +23,7 @@ from esphome.const import ( KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, PLATFORM_NRF52, - CoreModel, + ThreadModel, ) from esphome.core import CORE, EsphomeError, coroutine_with_priority from esphome.storage_json import StorageJSON @@ -110,7 +110,7 @@ async def to_code(config: ConfigType) -> None: cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) cg.add_define("ESPHOME_VARIANT", "NRF52") # nRF52 processors are single-core - cg.add_define(CoreModel.SINGLE) + cg.add_define(ThreadModel.SINGLE) cg.add_platformio_option(CONF_FRAMEWORK, CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK]) cg.add_platformio_option( "platform", diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index 28c3bbd70c..46eabb5325 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -16,7 +16,7 @@ from esphome.const import ( KEY_TARGET_FRAMEWORK, KEY_TARGET_PLATFORM, PLATFORM_RP2040, - CoreModel, + ThreadModel, ) from esphome.core import CORE, EsphomeError, coroutine_with_priority from esphome.helpers import copy_file_if_changed, mkdir_p, read_file, write_file @@ -172,7 +172,7 @@ async def to_code(config): cg.set_cpp_standard("gnu++20") cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) cg.add_define("ESPHOME_VARIANT", "RP2040") - cg.add_define(CoreModel.SINGLE) + cg.add_define(ThreadModel.SINGLE) cg.add_platformio_option("extra_scripts", ["post:post_build.py"]) diff --git a/esphome/const.py b/esphome/const.py index 627b6bac18..7d373ff26c 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -35,12 +35,12 @@ class Framework(StrEnum): ZEPHYR = "zephyr" -class CoreModel(StrEnum): - """Core model identifiers for ESPHome scheduler.""" +class ThreadModel(StrEnum): + """Threading model identifiers for ESPHome scheduler.""" - SINGLE = "ESPHOME_CORES_SINGLE" - MULTI_NO_ATOMICS = "ESPHOME_CORES_MULTI_NO_ATOMICS" - MULTI_ATOMICS = "ESPHOME_CORES_MULTI_ATOMICS" + SINGLE = "ESPHOME_THREAD_SINGLE" + MULTI_NO_ATOMICS = "ESPHOME_THREAD_MULTI_NO_ATOMICS" + MULTI_ATOMICS = "ESPHOME_THREAD_MULTI_ATOMICS" class PlatformFramework(Enum): diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 9355d56084..348f288863 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -15,8 +15,8 @@ #define ESPHOME_VARIANT "ESP32" #define ESPHOME_DEBUG_SCHEDULER -// Default threading model for static analysis (ESP32 is multi-core with atomics) -#define ESPHOME_CORES_MULTI_ATOMICS +// Default threading model for static analysis (ESP32 is multi-threaded with atomics) +#define ESPHOME_THREAD_MULTI_ATOMICS // logger #define ESPHOME_LOG_LEVEL ESPHOME_LOG_LEVEL_VERY_VERBOSE diff --git a/esphome/core/scheduler.cpp b/esphome/core/scheduler.cpp index fc5d43d262..dd80199dc0 100644 --- a/esphome/core/scheduler.cpp +++ b/esphome/core/scheduler.cpp @@ -84,7 +84,7 @@ void HOT Scheduler::set_timer_common_(Component *component, SchedulerItem::Type item->callback = std::move(func); item->remove = false; -#ifndef ESPHOME_CORES_SINGLE +#ifndef ESPHOME_THREAD_SINGLE // Special handling for defer() (delay = 0, type = TIMEOUT) // Single-core platforms don't need thread-safe defer handling if (delay == 0 && type == SchedulerItem::TIMEOUT) { @@ -94,7 +94,7 @@ void HOT Scheduler::set_timer_common_(Component *component, SchedulerItem::Type this->defer_queue_.push_back(std::move(item)); return; } -#endif /* not ESPHOME_CORES_SINGLE */ +#endif /* not ESPHOME_THREAD_SINGLE */ // Get fresh timestamp for new timer/interval - ensures accurate scheduling const auto now = this->millis_64_(millis()); // Fresh millis() call @@ -238,7 +238,7 @@ optional HOT Scheduler::next_schedule_in(uint32_t now) { return item->next_execution_ - now_64; } void HOT Scheduler::call(uint32_t now) { -#ifndef ESPHOME_CORES_SINGLE +#ifndef ESPHOME_THREAD_SINGLE // Process defer queue first to guarantee FIFO execution order for deferred items. // Previously, defer() used the heap which gave undefined order for equal timestamps, // causing race conditions on multi-core systems (ESP32, BK7200). @@ -268,7 +268,7 @@ void HOT Scheduler::call(uint32_t now) { this->execute_item_(item.get(), now); } } -#endif /* not ESPHOME_CORES_SINGLE */ +#endif /* not ESPHOME_THREAD_SINGLE */ // Convert the fresh timestamp from main loop to 64-bit for scheduler operations const auto now_64 = this->millis_64_(now); // 'now' from parameter - fresh from Application::loop() @@ -280,15 +280,15 @@ void HOT Scheduler::call(uint32_t now) { if (now_64 - last_print > 2000) { last_print = now_64; std::vector> old_items; -#ifdef ESPHOME_CORES_MULTI_ATOMICS +#ifdef ESPHOME_THREAD_MULTI_ATOMICS const auto last_dbg = this->last_millis_.load(std::memory_order_relaxed); const auto major_dbg = this->millis_major_.load(std::memory_order_relaxed); ESP_LOGD(TAG, "Items: count=%zu, now=%" PRIu64 " (%" PRIu16 ", %" PRIu32 ")", this->items_.size(), now_64, major_dbg, last_dbg); -#else /* not ESPHOME_CORES_MULTI_ATOMICS */ +#else /* not ESPHOME_THREAD_MULTI_ATOMICS */ ESP_LOGD(TAG, "Items: count=%zu, now=%" PRIu64 " (%" PRIu16 ", %" PRIu32 ")", this->items_.size(), now_64, this->millis_major_, this->last_millis_); -#endif /* else ESPHOME_CORES_MULTI_ATOMICS */ +#endif /* else ESPHOME_THREAD_MULTI_ATOMICS */ // Cleanup before debug output this->cleanup_(); while (!this->items_.empty()) { @@ -473,7 +473,7 @@ bool HOT Scheduler::cancel_item_locked_(Component *component, const char *name_c size_t total_cancelled = 0; // Check all containers for matching items -#ifndef ESPHOME_CORES_SINGLE +#ifndef ESPHOME_THREAD_SINGLE // Only check defer queue for timeouts (intervals never go there) if (type == SchedulerItem::TIMEOUT) { for (auto &item : this->defer_queue_) { @@ -483,7 +483,7 @@ bool HOT Scheduler::cancel_item_locked_(Component *component, const char *name_c } } } -#endif /* not ESPHOME_CORES_SINGLE */ +#endif /* not ESPHOME_THREAD_SINGLE */ // Cancel items in the main heap for (auto &item : this->items_) { @@ -509,9 +509,9 @@ bool HOT Scheduler::cancel_item_locked_(Component *component, const char *name_c uint64_t Scheduler::millis_64_(uint32_t now) { // THREAD SAFETY NOTE: // This function has three implementations, based on the precompiler flags - // - ESPHOME_CORES_SINGLE - Runs on single-core platforms (ESP8266, RP2040, etc.) - // - ESPHOME_CORES_MULTI_NO_ATOMICS - Runs on multi-core platforms without atomics (LibreTiny) - // - ESPHOME_CORES_MULTI_ATOMICS - Runs on multi-core platforms with atomics (ESP32, HOST, etc.) + // - ESPHOME_THREAD_SINGLE - Runs on single-threaded platforms (ESP8266, RP2040, etc.) + // - ESPHOME_THREAD_MULTI_NO_ATOMICS - Runs on multi-threaded platforms without atomics (LibreTiny) + // - ESPHOME_THREAD_MULTI_ATOMICS - Runs on multi-threaded platforms with atomics (ESP32, HOST, etc.) // // Make sure all changes are synchronized if you edit this function. // @@ -520,7 +520,7 @@ uint64_t Scheduler::millis_64_(uint32_t now) { // helps maintain accuracy. // -#ifdef ESPHOME_CORES_SINGLE +#ifdef ESPHOME_THREAD_SINGLE // This is the single core implementation. // // Single-core platforms have no concurrency, so this is a simple implementation @@ -546,7 +546,7 @@ uint64_t Scheduler::millis_64_(uint32_t now) { // Combine major (high 32 bits) and now (low 32 bits) into 64-bit time return now + (static_cast(major) << 32); -#elif defined(ESPHOME_CORES_MULTI_NO_ATOMICS) +#elif defined(ESPHOME_THREAD_MULTI_NO_ATOMICS) // This is the multi core no atomics implementation. // // Without atomics, this implementation uses locks more aggressively: @@ -595,7 +595,7 @@ uint64_t Scheduler::millis_64_(uint32_t now) { // Combine major (high 32 bits) and now (low 32 bits) into 64-bit time return now + (static_cast(major) << 32); -#elif defined(ESPHOME_CORES_MULTI_ATOMICS) +#elif defined(ESPHOME_THREAD_MULTI_ATOMICS) // This is the multi core with atomics implementation. // // Uses atomic operations with acquire/release semantics to ensure coherent @@ -660,7 +660,7 @@ uint64_t Scheduler::millis_64_(uint32_t now) { #else #error \ - "No platform threading model defined. One of ESPHOME_CORES_SINGLE, ESPHOME_CORES_MULTI_NO_ATOMICS, or ESPHOME_CORES_MULTI_ATOMICS must be defined." + "No platform threading model defined. One of ESPHOME_THREAD_SINGLE, ESPHOME_THREAD_MULTI_NO_ATOMICS, or ESPHOME_THREAD_MULTI_ATOMICS must be defined." #endif } diff --git a/esphome/core/scheduler.h b/esphome/core/scheduler.h index c14b7debe4..7bf83f7877 100644 --- a/esphome/core/scheduler.h +++ b/esphome/core/scheduler.h @@ -5,7 +5,7 @@ #include #include #include -#ifdef ESPHOME_CORES_MULTI_ATOMICS +#ifdef ESPHOME_THREAD_MULTI_ATOMICS #include #endif @@ -200,13 +200,13 @@ class Scheduler { Mutex lock_; std::vector> items_; std::vector> to_add_; -#ifndef ESPHOME_CORES_SINGLE +#ifndef ESPHOME_THREAD_SINGLE // Single-core platforms don't need the defer queue and save 40 bytes of RAM std::deque> defer_queue_; // FIFO queue for defer() calls -#endif /* ESPHOME_CORES_SINGLE */ +#endif /* ESPHOME_THREAD_SINGLE */ uint32_t to_remove_{0}; -#ifdef ESPHOME_CORES_MULTI_ATOMICS +#ifdef ESPHOME_THREAD_MULTI_ATOMICS /* * Multi-threaded platforms with atomic support: last_millis_ needs atomic for lock-free updates * @@ -218,10 +218,10 @@ class Scheduler { * it also observes the corresponding increment of `millis_major_`. */ std::atomic last_millis_{0}; -#else /* not ESPHOME_CORES_MULTI_ATOMICS */ +#else /* not ESPHOME_THREAD_MULTI_ATOMICS */ // Platforms without atomic support or single-threaded platforms uint32_t last_millis_{0}; -#endif /* else ESPHOME_CORES_MULTI_ATOMICS */ +#endif /* else ESPHOME_THREAD_MULTI_ATOMICS */ /* * Upper 16 bits of the 64-bit millis counter. Incremented only while holding @@ -229,11 +229,11 @@ class Scheduler { * Ordering relative to `last_millis_` is provided by its release store and the * corresponding acquire loads. */ -#ifdef ESPHOME_CORES_MULTI_ATOMICS +#ifdef ESPHOME_THREAD_MULTI_ATOMICS std::atomic millis_major_{0}; -#else /* not ESPHOME_CORES_MULTI_ATOMICS */ +#else /* not ESPHOME_THREAD_MULTI_ATOMICS */ uint16_t millis_major_{0}; -#endif /* else ESPHOME_CORES_MULTI_ATOMICS */ +#endif /* else ESPHOME_THREAD_MULTI_ATOMICS */ }; } // namespace esphome