From 12c35c15451c9038c0ca8b4311a3589cd0771a98 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 12 Oct 2026 16:53:49 -1000 Subject: [PATCH] Compute the object id hash when an external caller passes 0 --- esphome/core/entity_base.cpp | 9 ++++++++- esphome/core/helpers.h | 12 ++++++++++++ tests/components/core/test_entity_base_name.cpp | 17 +++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/esphome/core/entity_base.cpp b/esphome/core/entity_base.cpp index e1ba7593d3..7bf55c0354 100644 --- a/esphome/core/entity_base.cpp +++ b/esphome/core/entity_base.cpp @@ -68,7 +68,14 @@ void EntityBase::configure_entity_(const char *name, uint32_t object_id_hash, ui this->object_id_hash_ = fnv1_hash_object_id(fallback.c_str(), fallback.size()); } else { this->flags_.has_own_name = true; - // Static name - codegen precomputes the hash + // Static name - codegen precomputes the hash; external register_* callers may pass 0 + if (object_id_hash == 0) { +#ifdef USE_ESP8266 + object_id_hash = fnv1_hash_object_id_P(this->name_.progmem_ptr(), this->name_.size()); +#else + object_id_hash = fnv1_hash_object_id(this->name_.progmem_ptr(), this->name_.size()); +#endif + } this->object_id_hash_ = object_id_hash; } // Unpack entity string table indices and flags from entity_fields. diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index bcb03b010f..2d6cd1a96d 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -1145,6 +1145,18 @@ inline uint32_t fnv1_hash_object_id(const char *str, size_t len) { return hash; } +#ifdef USE_ESP8266 +/// fnv1_hash_object_id() for a string in flash (PROGMEM). +inline uint32_t fnv1_hash_object_id_P(PGM_P str, size_t len) { + uint32_t hash = FNV1_OFFSET_BASIS; + for (size_t i = 0; i < len; i++) { + hash *= FNV1_PRIME; + hash ^= static_cast(to_sanitized_char(to_snake_case_char(static_cast(pgm_read_byte(str + i))))); + } + return hash; +} +#endif + #ifdef USE_ESP8266 // ESP8266: Use vsnprintf_P to keep format strings in flash (PROGMEM) // Format strings must be wrapped with PSTR() macro diff --git a/tests/components/core/test_entity_base_name.cpp b/tests/components/core/test_entity_base_name.cpp index 18af5278a1..cf2af3e7ca 100644 --- a/tests/components/core/test_entity_base_name.cpp +++ b/tests/components/core/test_entity_base_name.cpp @@ -13,4 +13,21 @@ namespace esphome::core::testing { static_assert(std::is_same_v().get_name()), const StringRef &>); #pragma GCC diagnostic pop +class TestEntity : public EntityBase { + public: + void configure(const char *name, uint32_t object_id_hash) { this->configure_entity_(name, object_id_hash, 0); } +}; + +TEST(EntityBaseName, ZeroHashIsComputedFromTheName) { + TestEntity entity; + entity.configure("Living Room Temp", 0); + EXPECT_EQ(entity.get_object_id_hash(), fnv1_hash_object_id("Living Room Temp", 16)); +} + +TEST(EntityBaseName, PrecomputedHashIsKept) { + TestEntity entity; + entity.configure("Living Room Temp", 0x1234); + EXPECT_EQ(entity.get_object_id_hash(), 0x1234u); +} + } // namespace esphome::core::testing