[core] Expand component source index to 9 bits (511 max)

Bitfield component_source_index_ (9 bits) and warn_if_blocking_over_
(7 bits) into the same 16 bits. This doubles the max unique component
source names from 255 to 511 without increasing Component size.

The blocking warn threshold max drops from 2550ms to 1270ms which is
more than sufficient since it starts at 50ms and ratchets up.

Fixes test warnings when many components are compiled together:
WARNING Too many unique component source names (max 255)
This commit is contained in:
J. Nick Koston
2026-03-30 08:30:55 -10:00
parent 8688ef7125
commit fcfcb4ed72
4 changed files with 12 additions and 11 deletions
+3 -3
View File
@@ -280,8 +280,8 @@ bool Component::should_warn_of_blocking(uint32_t blocking_time) {
// Set new threshold: blocking_time + increment, converted back to centiseconds
uint32_t new_threshold_ms = blocking_time + WARN_IF_BLOCKING_INCREMENT_MS;
uint32_t new_cs = new_threshold_ms / 10U;
// Saturate at uint8_t max (255 = 2550ms)
this->warn_if_blocking_over_ = static_cast<uint8_t>(new_cs > 255U ? 255U : new_cs);
// Saturate at 7-bit max (127 = 1270ms)
this->warn_if_blocking_over_ = static_cast<uint16_t>(new_cs > 127U ? 127U : new_cs);
return true;
}
return false;
@@ -543,6 +543,6 @@ void clear_setup_priority_overrides() {
#endif
// Weak default for component_source_lookup - overridden by generated code
__attribute__((weak)) const LogString *component_source_lookup(uint8_t) { return LOG_STR("<unknown>"); }
__attribute__((weak)) const LogString *component_source_lookup(uint16_t) { return LOG_STR("<unknown>"); }
} // namespace esphome
+5 -4
View File
@@ -90,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 "<unknown>" so builds without codegen still link.
const LogString *component_source_lookup(uint8_t index);
const LogString *component_source_lookup(uint16_t index);
class Component {
public:
@@ -300,7 +300,7 @@ class Component {
* 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_(uint8_t index) { this->component_source_index_ = index; }
void set_component_source_(uint16_t index) { this->component_source_index_ = index; }
virtual void call_setup();
void call_dump_config_();
@@ -519,8 +519,9 @@ class Component {
void status_clear_error_slow_path_();
// Ordered for optimal packing on 32-bit systems (8 bytes total with vtable)
uint8_t component_source_index_{0}; ///< Index into component source PROGMEM lookup table (0 = not set)
uint8_t warn_if_blocking_over_{WARN_IF_BLOCKING_OVER_CS}; ///< Warn threshold in centiseconds (max 2550ms)
// Bitfield packs into 16 bits: 9-bit source index (0-511) + 7-bit blocking threshold (0-127 centiseconds)
uint16_t component_source_index_ : 9 {0}; ///< Index into component source PROGMEM lookup table (0 = not set)
uint16_t warn_if_blocking_over_ : 7 {WARN_IF_BLOCKING_OVER_CS}; ///< Warn threshold in centiseconds (max 1270ms)
/// State of this component - each bit has a purpose:
/// Bits 0-2: Component state (0x00=CONSTRUCTION, 0x01=SETUP, 0x02=LOOP, 0x03=FAILED, 0x04=LOOP_DONE)
/// Bit 3: STATUS_LED_WARNING
+3 -3
View File
@@ -26,8 +26,8 @@ _LOGGER = logging.getLogger(__name__)
_COMPONENT_SOURCE_DOMAIN = "component_source_pool"
# Maximum unique component source names (8-bit index, 0 = not set)
_MAX_COMPONENT_SOURCES = 0xFF # 255
# Maximum unique component source names (9-bit index, 0 = not set)
_MAX_COMPONENT_SOURCES = 0x1FF # 511
@dataclass
@@ -110,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}(uint8_t index) {{")
lines.append(f"const LogString *{lookup_fn}(uint16_t index) {{")
lines.append(f' if (index == 0 || index > {count}) return LOG_STR("<unknown>");')
lines.append(" return reinterpret_cast<const LogString *>(")
lines.append(f" progmem_read_ptr(&{table_var}[index - 1]));")
+1 -1
View File
@@ -137,7 +137,7 @@ def test_register_component_source_overflow_warns(
) -> None:
# Pre-fill pool to max
pool = ComponentSourcePool(
sources={f"comp_{i}": i + 1 for i in range(0xFF)},
sources={f"comp_{i}": i + 1 for i in range(0x1FF)},
table_registered=True,
)
monkeypatch.setattr(ch, "CORE", Mock(data={ch._COMPONENT_SOURCE_DOMAIN: pool}))