diff --git a/esphome/core/entity_base.cpp b/esphome/core/entity_base.cpp index 17254c78c8..dc27c1e56a 100644 --- a/esphome/core/entity_base.cpp +++ b/esphome/core/entity_base.cpp @@ -57,9 +57,10 @@ void EntityBase::configure_entity_(const char *name, uint32_t object_id_hash, ui } void EntityBase::set_internal(bool internal) { + // Remove the after-setup path in 2027.3.0 and ignore the call instead. if (App.is_setup_complete()) { - ESP_LOGE(TAG, "'%s': set_internal() called after setup, ignored", this->get_name().c_str()); - return; + ESP_LOGE(TAG, "'%s': set_internal() after setup is undefined behavior, stops working in 2027.3.0", + this->get_name().c_str()); } this->flags_.internal = internal; } diff --git a/esphome/core/entity_base.h b/esphome/core/entity_base.h index c95d7184d3..d383466fee 100644 --- a/esphome/core/entity_base.h +++ b/esphome/core/entity_base.h @@ -92,7 +92,8 @@ class EntityBase { // whenever possible: it is guaranteed and has none of the limitations below. Use this only when // the decision can only be made at boot. Must be called before MQTT and the API read the flag: // from on_boot at the default priority, or a setup() that runs above setup_priority::AFTER_WIFI. - // Calls after setup finishes are ignored and log an error. + // Calls after setup finishes are undefined behavior: the flag is still written and an error is + // logged, and from 2027.3.0 the call will be ignored. // // Known limitations. Not bugs, so no issue reports please; a PR that removes one with no RAM // or performance cost would be considered. diff --git a/tests/integration/test_set_internal_at_boot.py b/tests/integration/test_set_internal_at_boot.py index b2c1cc670e..68b0bd1080 100644 --- a/tests/integration/test_set_internal_at_boot.py +++ b/tests/integration/test_set_internal_at_boot.py @@ -14,7 +14,7 @@ async def test_set_internal_at_boot( run_compiled: RunCompiledFunction, api_client_connected: APIClientConnectedFactory, ) -> None: - """set_internal() in on_boot changes API exposure, later calls are rejected.""" + """set_internal() in on_boot changes API exposure, later calls log an error.""" waiter = LineWaiter() async with ( @@ -31,8 +31,11 @@ async def test_set_internal_at_boot( late = next(s for s in services if s.name == "set_internal_late") await client.execute_service(late, {}) await waiter.wait_for( - "'Untouched'", "set_internal() called after setup", timeout=5.0 + "'Untouched'", + "set_internal() after setup is undefined behavior", + timeout=5.0, ) + # Still written during the deprecation window, ignored from 2027.3.0 entities, _ = await client.list_entities_services() - assert "Untouched" in {entity.name for entity in entities} + assert "Untouched" not in {entity.name for entity in entities}