From 9440138ac786368f9a2bf7ecbf4f195e3de6e02e Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 9 Feb 2026 11:54:07 -0600 Subject: [PATCH 1/3] fix --- esphome/components/api/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index da75133a8ab..f4c1b2b0bd9 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -540,7 +540,8 @@ async def homeassistant_service_to_code( cg.add(var.init_variables(len(config[CONF_VARIABLES]))) for key, value in config[CONF_VARIABLES].items(): - templ = await cg.templatable(value, args, cg.std_string) + # Variables can return any type (float, int, etc.), not just strings + templ = await cg.templatable(value, args, None) cg.add(var.add_variable(cg.FlashStringLiteral(key), templ)) if on_error := config.get(CONF_ON_ERROR): @@ -625,7 +626,8 @@ async def homeassistant_event_to_code(config, action_id, template_arg, args): cg.add(var.init_variables(len(config[CONF_VARIABLES]))) for key, value in config[CONF_VARIABLES].items(): - templ = await cg.templatable(value, args, cg.std_string) + # Variables can return any type (float, int, etc.), not just strings + templ = await cg.templatable(value, args, None) cg.add(var.add_variable(cg.FlashStringLiteral(key), templ)) return var From dbef2e24b302a6ee5728cee9bd39316318839088 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 9 Feb 2026 11:58:40 -0600 Subject: [PATCH 2/3] 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). --- esphome/components/api/homeassistant_service.h | 9 +++++---- esphome/cpp_generator.py | 9 +++++++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/esphome/components/api/homeassistant_service.h b/esphome/components/api/homeassistant_service.h index cb19dd19a4f..1b8dfbe4121 100644 --- a/esphome/components/api/homeassistant_service.h +++ b/esphome/components/api/homeassistant_service.h @@ -232,10 +232,11 @@ template class HomeAssistantServiceCallAction : public Action 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] From cf7da8e86d6d88ce045d1012904becb7d6254147 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 9 Feb 2026 12:34:16 -0600 Subject: [PATCH 3/3] fix --- esphome/components/api/__init__.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index f4c1b2b0bd9..4d6a116e676 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -530,17 +530,23 @@ async def homeassistant_service_to_code( # Initialize FixedVectors with exact sizes from config cg.add(var.init_data(len(config[CONF_DATA]))) for key, value in config[CONF_DATA].items(): - templ = await cg.templatable(value, args, cg.std_string) + # output_type=None because lambdas can return non-string types (int, + # float, char*) that TemplatableStringValue converts via to_string. + # Static strings are manually wrapped for PROGMEM on ESP8266. + templ = await cg.templatable(value, args, None) + if isinstance(templ, str): + templ = cg.FlashStringLiteral(templ) cg.add(var.add_data(cg.FlashStringLiteral(key), templ)) cg.add(var.init_data_template(len(config[CONF_DATA_TEMPLATE]))) for key, value in config[CONF_DATA_TEMPLATE].items(): - templ = await cg.templatable(value, args, cg.std_string) + templ = await cg.templatable(value, args, None) + if isinstance(templ, str): + templ = cg.FlashStringLiteral(templ) cg.add(var.add_data_template(cg.FlashStringLiteral(key), templ)) cg.add(var.init_variables(len(config[CONF_VARIABLES]))) for key, value in config[CONF_VARIABLES].items(): - # Variables can return any type (float, int, etc.), not just strings templ = await cg.templatable(value, args, None) cg.add(var.add_variable(cg.FlashStringLiteral(key), templ)) @@ -616,17 +622,23 @@ async def homeassistant_event_to_code(config, action_id, template_arg, args): # Initialize FixedVectors with exact sizes from config cg.add(var.init_data(len(config[CONF_DATA]))) for key, value in config[CONF_DATA].items(): - templ = await cg.templatable(value, args, cg.std_string) + # output_type=None because lambdas can return non-string types (int, + # float, char*) that TemplatableStringValue converts via to_string. + # Static strings are manually wrapped for PROGMEM on ESP8266. + templ = await cg.templatable(value, args, None) + if isinstance(templ, str): + templ = cg.FlashStringLiteral(templ) cg.add(var.add_data(cg.FlashStringLiteral(key), templ)) cg.add(var.init_data_template(len(config[CONF_DATA_TEMPLATE]))) for key, value in config[CONF_DATA_TEMPLATE].items(): - templ = await cg.templatable(value, args, cg.std_string) + templ = await cg.templatable(value, args, None) + if isinstance(templ, str): + templ = cg.FlashStringLiteral(templ) cg.add(var.add_data_template(cg.FlashStringLiteral(key), templ)) cg.add(var.init_variables(len(config[CONF_VARIABLES]))) for key, value in config[CONF_VARIABLES].items(): - # Variables can return any type (float, int, etc.), not just strings templ = await cg.templatable(value, args, None) cg.add(var.add_variable(cg.FlashStringLiteral(key), templ))