Fix variables returning non-string types, use identity check for std_string

- Revert variables templatable output_type back to None since variable
  lambdas can return any type (float, int, etc.), not just strings.
- Use lazy import identity check (output_type is std_string) instead of
  brittle string comparison in templatable().
- Clarify ESP8266 populate_service_map comment explaining why STATIC_STRING
  fast path is not needed (all codegen strings are FLASH_STRING on ESP8266).
This commit is contained in:
J. Nick Koston
2026-02-09 11:58:55 -06:00
parent 9440138ac7
commit dbef2e24b3
2 changed files with 12 additions and 6 deletions
@@ -232,10 +232,11 @@ template<typename... Ts> class HomeAssistantServiceCallAction : public Action<Ts
dest.init(source.size());
#ifdef USE_ESP8266
// On ESP8266, keys may be in PROGMEM (from ESPHOME_F in codegen) and
// FLASH_STRING values need copying via _P functions.
// Allocate storage for all keys + all values (2 entries per source item).
// strlen_P/memcpy_P handle both RAM and PROGMEM pointers safely.
// On ESP8266, all static strings from codegen are FLASH_STRING (PROGMEM),
// so is_static_string() is always false — the zero-copy STATIC_STRING fast
// path from the non-ESP8266 branch cannot trigger. We copy all keys and
// values unconditionally: keys via _P functions (may be in PROGMEM), values
// via value() which handles FLASH_STRING internally.
value_storage.init(source.size() * 2);
for (auto &it : source) {
+7 -2
View File
@@ -780,8 +780,13 @@ async def templatable(
if to_exp is None:
# Automatically wrap static strings in ESPHOME_F() for PROGMEM storage on ESP8266.
# On other platforms ESPHOME_F() is a no-op returning const char*.
if isinstance(value, str) and str(output_type) == "std::string":
return FlashStringLiteral(value)
# Lazy import to avoid circular dependency (cpp_generator <-> cpp_types).
# Identity check (is) avoids brittle string comparison.
if isinstance(value, str) and output_type is not None:
from esphome.cpp_types import std_string
if output_type is std_string:
return FlashStringLiteral(value)
return value
if isinstance(to_exp, dict):
return to_exp[value]