diff --git a/esphome/core/component.cpp b/esphome/core/component.cpp index d3e9389efc..44194a18a8 100644 --- a/esphome/core/component.cpp +++ b/esphome/core/component.cpp @@ -274,6 +274,10 @@ void Component::call() { break; } } +const LogString *Component::get_component_log_str() const { + return this->component_source_index_ == 0 ? LOG_STR("") + : component_source_lookup(this->component_source_index_); +} bool Component::should_warn_of_blocking(uint32_t blocking_time) { // Convert centisecond threshold to milliseconds for comparison uint32_t threshold_ms = static_cast(this->warn_if_blocking_over_) * 10U; @@ -544,6 +548,6 @@ void clear_setup_priority_overrides() { #endif // Weak default for component_source_lookup - overridden by generated code -__attribute__((weak)) const LogString *component_source_lookup(uint16_t) { return LOG_STR(""); } +__attribute__((weak)) const LogString *component_source_lookup(uint8_t) { return LOG_STR(""); } } // namespace esphome diff --git a/esphome/core/component.h b/esphome/core/component.h index 6b69190d07..81824d9b8f 100644 --- a/esphome/core/component.h +++ b/esphome/core/component.h @@ -11,6 +11,10 @@ #include "esphome/core/log.h" #include "esphome/core/optional.h" +// Forward declarations for friend access from codegen-generated setup() +void setup(); // NOLINT(readability-redundant-declaration) - may be declared in Arduino.h +void original_setup(); // NOLINT(readability-redundant-declaration) + namespace esphome { // Forward declaration for LogString @@ -79,11 +83,6 @@ inline constexpr uint8_t STATUS_LED_WARNING = 0x08; inline constexpr uint8_t STATUS_LED_ERROR = 0x10; // Component loop override flag uses bit 5 (set at registration time) inline constexpr uint8_t COMPONENT_HAS_LOOP = 0x20; -// High bit of 9-bit component_source index (bit 6 of component_state_) -inline constexpr uint8_t COMPONENT_SOURCE_HIGH_BIT = 0x40; -// Mask for the 9th bit of the component source index (bit 8) -inline constexpr uint16_t COMPONENT_SOURCE_INDEX_HIGH = 0x100; - // Remove before 2026.8.0 enum class RetryResult { DONE, RETRY }; @@ -91,7 +90,7 @@ inline constexpr uint8_t WARN_IF_BLOCKING_OVER_CS = 5U; // 50ms in centiseconds /// Lookup component source name by index (1-based). Generated by Python codegen. /// Weak default returns "" so builds without codegen still link. -const LogString *component_source_lookup(uint16_t index); +const LogString *component_source_lookup(uint8_t index); class Component { public: @@ -151,10 +150,7 @@ class Component { */ virtual void on_powerdown() {} - uint8_t get_component_state() const { - // Mask out COMPONENT_SOURCE_HIGH_BIT — it's internal to component source indexing - return this->component_state_ & ~COMPONENT_SOURCE_HIGH_BIT; - } + uint8_t get_component_state() const { return this->component_state_; } /** Reset this component back to the construction state to allow setup to run again. * @@ -300,31 +296,21 @@ class Component { * * Returns LOG_STR("") if source not set */ - const LogString *get_component_log_str() const { - uint16_t idx = this->component_source_index_; - if (this->component_state_ & COMPONENT_SOURCE_HIGH_BIT) - idx |= COMPONENT_SOURCE_INDEX_HIGH; - return idx == 0 ? LOG_STR("") : component_source_lookup(idx); - } + const LogString *get_component_log_str() const; bool should_warn_of_blocking(uint32_t blocking_time); protected: friend class Application; + friend void ::setup(); + friend void ::original_setup(); /** Set where this component was loaded from for some debug messages. * * This is set by the ESPHome core during setup, and should not be called manually. * @param index 1-based index into the component source lookup table (0 = not set) */ - void set_component_source_(uint16_t index) { - this->component_source_index_ = static_cast(index & 0xFF); - if (index & COMPONENT_SOURCE_INDEX_HIGH) { - this->component_state_ |= COMPONENT_SOURCE_HIGH_BIT; - } else { - this->component_state_ &= ~COMPONENT_SOURCE_HIGH_BIT; - } - } + void set_component_source_(uint8_t index) { this->component_source_index_ = index; } virtual void call_setup(); void call_dump_config_(); @@ -550,8 +536,7 @@ class Component { /// Bit 3: STATUS_LED_WARNING /// Bit 4: STATUS_LED_ERROR /// Bit 5: Has overridden loop() (set at registration time) - /// Bit 6: High bit of 9-bit component_source index - /// Bit 7: Unused - reserved for future expansion + /// Bits 6-7: Unused - reserved for future expansion uint8_t component_state_{0x00}; volatile bool pending_enable_loop_{false}; ///< ISR-safe flag for enable_loop_soon_any_context }; diff --git a/esphome/cpp_helpers.py b/esphome/cpp_helpers.py index 22d26ef3ba..a688dbdb20 100644 --- a/esphome/cpp_helpers.py +++ b/esphome/cpp_helpers.py @@ -26,8 +26,8 @@ _LOGGER = logging.getLogger(__name__) _COMPONENT_SOURCE_DOMAIN = "component_source_pool" -# Maximum unique component source names (9-bit index, 0 = not set) -_MAX_COMPONENT_SOURCES = 510 +# Maximum unique component source names (8-bit index, 0 = not set) +_MAX_COMPONENT_SOURCES = 0xFF # 255 @dataclass @@ -71,9 +71,12 @@ def register_component_source(name: str) -> int: return pool.sources[name] idx = len(pool.sources) + 1 if idx > _MAX_COMPONENT_SOURCES: - raise ValueError( - f"Too many unique component source names (max {_MAX_COMPONENT_SOURCES}), got {idx}: '{name}'" + _LOGGER.warning( + "Too many unique component source names (max %d), '%s' will show as ''", + _MAX_COMPONENT_SOURCES, + name, ) + return 0 pool.sources[name] = idx _ensure_source_table_registered() return idx @@ -107,7 +110,7 @@ def _generate_source_table_code( entries = ", ".join(var_names) lines.append(f"static const char *const {table_var}[] PROGMEM = {{{entries}}};") - lines.append(f"const LogString *{lookup_fn}(uint16_t index) {{") + lines.append(f"const LogString *{lookup_fn}(uint8_t index) {{") lines.append(f' if (index == 0 || index > {count}) return LOG_STR("");') lines.append(" return reinterpret_cast(") lines.append(f" progmem_read_ptr(&{table_var}[index - 1]));") diff --git a/tests/unit_tests/test_cpp_helpers.py b/tests/unit_tests/test_cpp_helpers.py index 5b6eed156f..b2b0d14a3d 100644 --- a/tests/unit_tests/test_cpp_helpers.py +++ b/tests/unit_tests/test_cpp_helpers.py @@ -23,7 +23,7 @@ async def test_register_component(monkeypatch): app_mock = Mock(register_component_=Mock(return_value=var)) monkeypatch.setattr(ch, "App", app_mock) - core_mock = Mock(component_ids=["foo.bar"]) + core_mock = Mock(component_ids=["foo.bar"], data={}) monkeypatch.setattr(ch, "CORE", core_mock) add_mock = Mock() @@ -59,7 +59,7 @@ async def test_register_component__with_setup_priority(monkeypatch): app_mock = Mock(register_component_=Mock(return_value=var)) monkeypatch.setattr(ch, "App", app_mock) - core_mock = Mock(component_ids=["foo.bar"]) + core_mock = Mock(component_ids=["foo.bar"], data={}) monkeypatch.setattr(ch, "CORE", core_mock) add_mock = Mock()