diff --git a/esphome/components/api/__init__.py b/esphome/components/api/__init__.py index 918f56349aa..dd99862cc27 100644 --- a/esphome/components/api/__init__.py +++ b/esphome/components/api/__init__.py @@ -541,17 +541,24 @@ 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(): - templ = await cg.templatable(value, args, cg.std_string) + templ = await cg.templatable(value, args, None) cg.add(var.add_variable(cg.FlashStringLiteral(key), templ)) if on_error := config.get(CONF_ON_ERROR): @@ -627,17 +634,24 @@ 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(): - templ = await cg.templatable(value, args, cg.std_string) + templ = await cg.templatable(value, args, None) cg.add(var.add_variable(cg.FlashStringLiteral(key), templ)) return var diff --git a/esphome/components/api/homeassistant_service.h b/esphome/components/api/homeassistant_service.h index 677d0645d62..9d14061d072 100644 --- a/esphome/components/api/homeassistant_service.h +++ b/esphome/components/api/homeassistant_service.h @@ -236,10 +236,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]