1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-25 22:52:20 +01:00

Merge remote-tracking branch 'upstream/dev' into scheduler_pool_v2

This commit is contained in:
J. Nick Koston
2025-09-02 21:31:12 -05:00
78 changed files with 734 additions and 160 deletions

View File

@@ -13,7 +13,7 @@ from esphome.const import (
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_WEB_SERVER, CONF_WEB_SERVER,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
@@ -345,6 +345,6 @@ async def alarm_control_panel_is_armed_to_code(
return cg.new_Pvariable(condition_id, template_arg, paren) return cg.new_Pvariable(condition_id, template_arg, paren)
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(alarm_control_panel_ns.using) cg.add_global(alarm_control_panel_ns.using)

View File

@@ -24,7 +24,7 @@ from esphome.const import (
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_VARIABLES, CONF_VARIABLES,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
DOMAIN = "api" DOMAIN = "api"
DEPENDENCIES = ["network"] DEPENDENCIES = ["network"]
@@ -134,7 +134,7 @@ CONFIG_SCHEMA = cv.All(
) )
@coroutine_with_priority(40.0) @coroutine_with_priority(CoroPriority.WEB)
async def to_code(config): async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config) await cg.register_component(var, config)

View File

@@ -8,7 +8,7 @@ from esphome.const import (
PLATFORM_LN882X, PLATFORM_LN882X,
PLATFORM_RTL87XX, PLATFORM_RTL87XX,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
@@ -27,7 +27,7 @@ CONFIG_SCHEMA = cv.All(
) )
@coroutine_with_priority(200.0) @coroutine_with_priority(CoroPriority.NETWORK_TRANSPORT)
async def to_code(config): async def to_code(config):
if CORE.is_esp32 or CORE.is_libretiny: if CORE.is_esp32 or CORE.is_libretiny:
# https://github.com/ESP32Async/AsyncTCP # https://github.com/ESP32Async/AsyncTCP

View File

@@ -2,7 +2,7 @@ from esphome import automation
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_MIC_GAIN from esphome.const import CONF_ID, CONF_MIC_GAIN
from esphome.core import coroutine_with_priority from esphome.core import CoroPriority, coroutine_with_priority
CODEOWNERS = ["@kbx81"] CODEOWNERS = ["@kbx81"]
IS_PLATFORM_COMPONENT = True IS_PLATFORM_COMPONENT = True
@@ -35,7 +35,7 @@ async def audio_adc_set_mic_gain_to_code(config, action_id, template_arg, args):
return var return var
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_define("USE_AUDIO_ADC") cg.add_define("USE_AUDIO_ADC")
cg.add_global(audio_adc_ns.using) cg.add_global(audio_adc_ns.using)

View File

@@ -3,7 +3,7 @@ from esphome.automation import maybe_simple_id
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_VOLUME from esphome.const import CONF_ID, CONF_VOLUME
from esphome.core import coroutine_with_priority from esphome.core import CoroPriority, coroutine_with_priority
CODEOWNERS = ["@kbx81"] CODEOWNERS = ["@kbx81"]
IS_PLATFORM_COMPONENT = True IS_PLATFORM_COMPONENT = True
@@ -51,7 +51,7 @@ async def audio_dac_set_volume_to_code(config, action_id, template_arg, args):
return var return var
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_define("USE_AUDIO_DAC") cg.add_define("USE_AUDIO_DAC")
cg.add_global(audio_dac_ns.using) cg.add_global(audio_dac_ns.using)

View File

@@ -59,7 +59,7 @@ from esphome.const import (
DEVICE_CLASS_VIBRATION, DEVICE_CLASS_VIBRATION,
DEVICE_CLASS_WINDOW, DEVICE_CLASS_WINDOW,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
from esphome.util import Registry from esphome.util import Registry
@@ -652,7 +652,7 @@ async def binary_sensor_is_off_to_code(config, condition_id, template_arg, args)
return cg.new_Pvariable(condition_id, template_arg, paren, False) return cg.new_Pvariable(condition_id, template_arg, paren, False)
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(binary_sensor_ns.using) cg.add_global(binary_sensor_ns.using)

View File

@@ -17,7 +17,7 @@ from esphome.const import (
DEVICE_CLASS_RESTART, DEVICE_CLASS_RESTART,
DEVICE_CLASS_UPDATE, DEVICE_CLASS_UPDATE,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
@@ -134,6 +134,6 @@ async def button_press_to_code(config, action_id, template_arg, args):
return cg.new_Pvariable(action_id, template_arg, paren) return cg.new_Pvariable(action_id, template_arg, paren)
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(button_ns.using) cg.add_global(button_ns.using)

View File

@@ -14,8 +14,8 @@ void log_button(const char *tag, const char *prefix, const char *type, Button *o
ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str()); ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str());
if (!obj->get_icon().empty()) { if (!obj->get_icon_ref().empty()) {
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon().c_str()); ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon_ref().c_str());
} }
} }

View File

@@ -10,7 +10,7 @@ from esphome.const import (
PLATFORM_LN882X, PLATFORM_LN882X,
PLATFORM_RTL87XX, PLATFORM_RTL87XX,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
AUTO_LOAD = ["web_server_base", "ota.web_server"] AUTO_LOAD = ["web_server_base", "ota.web_server"]
DEPENDENCIES = ["wifi"] DEPENDENCIES = ["wifi"]
@@ -40,7 +40,7 @@ CONFIG_SCHEMA = cv.All(
) )
@coroutine_with_priority(64.0) @coroutine_with_priority(CoroPriority.COMMUNICATION)
async def to_code(config): async def to_code(config):
paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID]) paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID])

View File

@@ -47,7 +47,7 @@ from esphome.const import (
CONF_VISUAL, CONF_VISUAL,
CONF_WEB_SERVER, CONF_WEB_SERVER,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
@@ -517,6 +517,6 @@ async def climate_control_to_code(config, action_id, template_arg, args):
return var return var
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(climate_ns.using) cg.add_global(climate_ns.using)

View File

@@ -32,7 +32,7 @@ from esphome.const import (
DEVICE_CLASS_SHUTTER, DEVICE_CLASS_SHUTTER,
DEVICE_CLASS_WINDOW, DEVICE_CLASS_WINDOW,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
@@ -263,6 +263,6 @@ async def cover_control_to_code(config, action_id, template_arg, args):
return var return var
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(cover_ns.using) cg.add_global(cover_ns.using)

View File

@@ -21,7 +21,7 @@ from esphome.const import (
CONF_WEB_SERVER, CONF_WEB_SERVER,
CONF_YEAR, CONF_YEAR,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
@@ -172,7 +172,7 @@ async def new_datetime(config, *args):
return var return var
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(datetime_ns.using) cg.add_global(datetime_ns.using)

View File

@@ -16,8 +16,8 @@ namespace datetime {
#define LOG_DATETIME_DATE(prefix, type, obj) \ #define LOG_DATETIME_DATE(prefix, type, obj) \
if ((obj) != nullptr) { \ if ((obj) != nullptr) { \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
if (!(obj)->get_icon().empty()) { \ if (!(obj)->get_icon_ref().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \
} \ } \
} }

View File

@@ -16,8 +16,8 @@ namespace datetime {
#define LOG_DATETIME_DATETIME(prefix, type, obj) \ #define LOG_DATETIME_DATETIME(prefix, type, obj) \
if ((obj) != nullptr) { \ if ((obj) != nullptr) { \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
if (!(obj)->get_icon().empty()) { \ if (!(obj)->get_icon_ref().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \
} \ } \
} }

View File

@@ -16,8 +16,8 @@ namespace datetime {
#define LOG_DATETIME_TIME(prefix, type, obj) \ #define LOG_DATETIME_TIME(prefix, type, obj) \
if ((obj) != nullptr) { \ if ((obj) != nullptr) { \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
if (!(obj)->get_icon().empty()) { \ if (!(obj)->get_icon_ref().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \
} \ } \
} }

View File

@@ -15,7 +15,7 @@ from esphome.const import (
CONF_UPDATE_INTERVAL, CONF_UPDATE_INTERVAL,
SCHEDULER_DONT_RUN, SCHEDULER_DONT_RUN,
) )
from esphome.core import coroutine_with_priority from esphome.core import CoroPriority, coroutine_with_priority
IS_PLATFORM_COMPONENT = True IS_PLATFORM_COMPONENT = True
@@ -218,7 +218,7 @@ async def display_is_displaying_page_to_code(config, condition_id, template_arg,
return var return var
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(display_ns.using) cg.add_global(display_ns.using)
cg.add_define("USE_DISPLAY") cg.add_define("USE_DISPLAY")

View File

@@ -855,11 +855,6 @@ async def to_code(config):
cg.add_platformio_option("platform_packages", [conf[CONF_SOURCE]]) cg.add_platformio_option("platform_packages", [conf[CONF_SOURCE]])
# platformio/toolchain-esp32ulp does not support linux_aarch64 yet and has not been updated for over 2 years
# This is espressif's own published version which is more up to date.
cg.add_platformio_option(
"platform_packages", ["espressif/toolchain-esp32ulp@2.35.0-20220830"]
)
add_idf_sdkconfig_option(f"CONFIG_IDF_TARGET_{variant}", True) add_idf_sdkconfig_option(f"CONFIG_IDF_TARGET_{variant}", True)
add_idf_sdkconfig_option( add_idf_sdkconfig_option(
f"CONFIG_ESPTOOLPY_FLASHSIZE_{config[CONF_FLASH_SIZE]}", True f"CONFIG_ESPTOOLPY_FLASHSIZE_{config[CONF_FLASH_SIZE]}", True

View File

@@ -30,7 +30,7 @@ from esphome.const import (
CONF_SERVICE_UUID, CONF_SERVICE_UUID,
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.enum import StrEnum from esphome.enum import StrEnum
from esphome.types import ConfigType from esphome.types import ConfigType
@@ -368,7 +368,7 @@ async def to_code(config):
# This needs to be run as a job with very low priority so that all components have # This needs to be run as a job with very low priority so that all components have
# chance to call register_ble_tracker and register_client before the list is checked # chance to call register_ble_tracker and register_client before the list is checked
# and added to the global defines list. # and added to the global defines list.
@coroutine_with_priority(-1000) @coroutine_with_priority(CoroPriority.FINAL)
async def _add_ble_features(): async def _add_ble_features():
# Add feature-specific defines based on what's needed # Add feature-specific defines based on what's needed
if BLEFeatures.ESP_BT_DEVICE in _required_features: if BLEFeatures.ESP_BT_DEVICE in _required_features:

View File

@@ -17,7 +17,7 @@ from esphome.const import (
PLATFORM_ESP8266, PLATFORM_ESP8266,
ThreadModel, ThreadModel,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.helpers import copy_file_if_changed from esphome.helpers import copy_file_if_changed
from .boards import BOARDS, ESP8266_LD_SCRIPTS from .boards import BOARDS, ESP8266_LD_SCRIPTS
@@ -176,7 +176,7 @@ CONFIG_SCHEMA = cv.All(
) )
@coroutine_with_priority(1000) @coroutine_with_priority(CoroPriority.PLATFORM)
async def to_code(config): async def to_code(config):
cg.add(esp8266_ns.setup_preferences()) cg.add(esp8266_ns.setup_preferences())

View File

@@ -17,7 +17,7 @@ from esphome.const import (
CONF_PULLUP, CONF_PULLUP,
PLATFORM_ESP8266, PLATFORM_ESP8266,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from . import boards from . import boards
from .const import KEY_BOARD, KEY_ESP8266, KEY_PIN_INITIAL_STATES, esp8266_ns from .const import KEY_BOARD, KEY_ESP8266, KEY_PIN_INITIAL_STATES, esp8266_ns
@@ -188,7 +188,7 @@ async def esp8266_pin_to_code(config):
return var return var
@coroutine_with_priority(-999.0) @coroutine_with_priority(CoroPriority.WORKAROUNDS)
async def add_pin_initial_states_array(): async def add_pin_initial_states_array():
# Add includes at the very end, so that they override everything # Add includes at the very end, so that they override everything
initial_states: list[PinInitialState] = CORE.data[KEY_ESP8266][ initial_states: list[PinInitialState] = CORE.data[KEY_ESP8266][

View File

@@ -16,7 +16,7 @@ from esphome.const import (
CONF_SAFE_MODE, CONF_SAFE_MODE,
CONF_VERSION, CONF_VERSION,
) )
from esphome.core import coroutine_with_priority from esphome.core import CoroPriority, coroutine_with_priority
import esphome.final_validate as fv import esphome.final_validate as fv
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -121,7 +121,7 @@ CONFIG_SCHEMA = (
FINAL_VALIDATE_SCHEMA = ota_esphome_final_validate FINAL_VALIDATE_SCHEMA = ota_esphome_final_validate
@coroutine_with_priority(52.0) @coroutine_with_priority(CoroPriority.COMMUNICATION)
async def to_code(config): async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_port(config[CONF_PORT])) cg.add(var.set_port(config[CONF_PORT]))

View File

@@ -38,7 +38,12 @@ from esphome.const import (
KEY_CORE, KEY_CORE,
KEY_FRAMEWORK_VERSION, KEY_FRAMEWORK_VERSION,
) )
from esphome.core import CORE, TimePeriodMilliseconds, coroutine_with_priority from esphome.core import (
CORE,
CoroPriority,
TimePeriodMilliseconds,
coroutine_with_priority,
)
import esphome.final_validate as fv import esphome.final_validate as fv
CONFLICTS_WITH = ["wifi"] CONFLICTS_WITH = ["wifi"]
@@ -289,7 +294,7 @@ def phy_register(address: int, value: int, page: int):
) )
@coroutine_with_priority(60.0) @coroutine_with_priority(CoroPriority.COMMUNICATION)
async def to_code(config): async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config) await cg.register_component(var, config)

View File

@@ -17,7 +17,7 @@ from esphome.const import (
DEVICE_CLASS_EMPTY, DEVICE_CLASS_EMPTY,
DEVICE_CLASS_MOTION, DEVICE_CLASS_MOTION,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
@@ -143,6 +143,6 @@ async def event_fire_to_code(config, action_id, template_arg, args):
return var return var
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(event_ns.using) cg.add_global(event_ns.using)

View File

@@ -13,8 +13,8 @@ namespace event {
#define LOG_EVENT(prefix, type, obj) \ #define LOG_EVENT(prefix, type, obj) \
if ((obj) != nullptr) { \ if ((obj) != nullptr) { \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
if (!(obj)->get_icon().empty()) { \ if (!(obj)->get_icon_ref().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \
} \ } \
if (!(obj)->get_device_class().empty()) { \ if (!(obj)->get_device_class().empty()) { \
ESP_LOGCONFIG(TAG, "%s Device Class: '%s'", prefix, (obj)->get_device_class().c_str()); \ ESP_LOGCONFIG(TAG, "%s Device Class: '%s'", prefix, (obj)->get_device_class().c_str()); \

View File

@@ -31,7 +31,7 @@ from esphome.const import (
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_WEB_SERVER, CONF_WEB_SERVER,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
IS_PLATFORM_COMPONENT = True IS_PLATFORM_COMPONENT = True
@@ -398,6 +398,6 @@ async def fan_is_on_off_to_code(config, condition_id, template_arg, args):
return cg.new_Pvariable(condition_id, template_arg, paren) return cg.new_Pvariable(condition_id, template_arg, paren)
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(fan_ns.using) cg.add_global(fan_ns.using)

View File

@@ -8,7 +8,7 @@ from esphome.const import (
CONF_TYPE, CONF_TYPE,
CONF_VALUE, CONF_VALUE,
) )
from esphome.core import coroutine_with_priority from esphome.core import CoroPriority, coroutine_with_priority
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
globals_ns = cg.esphome_ns.namespace("globals") globals_ns = cg.esphome_ns.namespace("globals")
@@ -35,7 +35,7 @@ CONFIG_SCHEMA = cv.Schema(
# Run with low priority so that namespaces are registered first # Run with low priority so that namespaces are registered first
@coroutine_with_priority(-100.0) @coroutine_with_priority(CoroPriority.LATE)
async def to_code(config): async def to_code(config):
type_ = cg.RawExpression(config[CONF_TYPE]) type_ = cg.RawExpression(config[CONF_TYPE])
restore = config[CONF_RESTORE_VALUE] restore = config[CONF_RESTORE_VALUE]

View File

@@ -42,9 +42,10 @@ class HostPreferences : public ESPPreferences {
if (len > 255) if (len > 255)
return false; return false;
this->setup_(); this->setup_();
if (this->data.count(key) == 0) auto it = this->data.find(key);
if (it == this->data.end())
return false; return false;
auto vec = this->data[key]; const auto &vec = it->second;
if (vec.size() != len) if (vec.size() != len)
return false; return false;
memcpy(data, vec.data(), len); memcpy(data, vec.data(), len);

View File

@@ -3,7 +3,7 @@ import esphome.codegen as cg
from esphome.components.ota import BASE_OTA_SCHEMA, OTAComponent, ota_to_code from esphome.components.ota import BASE_OTA_SCHEMA, OTAComponent, ota_to_code
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_PASSWORD, CONF_URL, CONF_USERNAME from esphome.const import CONF_ID, CONF_PASSWORD, CONF_URL, CONF_USERNAME
from esphome.core import coroutine_with_priority from esphome.core import CoroPriority, coroutine_with_priority
from .. import CONF_HTTP_REQUEST_ID, HttpRequestComponent, http_request_ns from .. import CONF_HTTP_REQUEST_ID, HttpRequestComponent, http_request_ns
@@ -40,7 +40,7 @@ CONFIG_SCHEMA = cv.All(
) )
@coroutine_with_priority(52.0) @coroutine_with_priority(CoroPriority.COMMUNICATION)
async def to_code(config): async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await ota_to_code(var, config) await ota_to_code(var, config)

View File

@@ -18,7 +18,7 @@ from esphome.const import (
PLATFORM_RP2040, PLATFORM_RP2040,
PlatformFramework, PlatformFramework,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
import esphome.final_validate as fv import esphome.final_validate as fv
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
@@ -74,7 +74,7 @@ CONFIG_SCHEMA = cv.All(
) )
@coroutine_with_priority(1.0) @coroutine_with_priority(CoroPriority.BUS)
async def to_code(config): async def to_code(config):
cg.add_global(i2c_ns.using) cg.add_global(i2c_ns.using)
cg.add_define("USE_I2C") cg.add_define("USE_I2C")

View File

@@ -1,6 +1,6 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.core import coroutine_with_priority from esphome.core import CoroPriority, coroutine_with_priority
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
json_ns = cg.esphome_ns.namespace("json") json_ns = cg.esphome_ns.namespace("json")
@@ -10,7 +10,7 @@ CONFIG_SCHEMA = cv.All(
) )
@coroutine_with_priority(1.0) @coroutine_with_priority(CoroPriority.BUS)
async def to_code(config): async def to_code(config):
cg.add_library("bblanchon/ArduinoJson", "7.4.2") cg.add_library("bblanchon/ArduinoJson", "7.4.2")
cg.add_define("USE_JSON") cg.add_define("USE_JSON")

View File

@@ -37,7 +37,7 @@ from esphome.const import (
CONF_WEB_SERVER, CONF_WEB_SERVER,
CONF_WHITE, CONF_WHITE,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
@@ -283,6 +283,6 @@ async def new_light(config, *args):
return output_var return output_var
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(light_ns.using) cg.add_global(light_ns.using)

View File

@@ -13,7 +13,7 @@ from esphome.const import (
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_WEB_SERVER, CONF_WEB_SERVER,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
@@ -155,6 +155,6 @@ async def lock_is_off_to_code(config, condition_id, template_arg, args):
return cg.new_Pvariable(condition_id, template_arg, paren, False) return cg.new_Pvariable(condition_id, template_arg, paren, False)
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(lock_ns.using) cg.add_global(lock_ns.using)

View File

@@ -15,8 +15,8 @@ class Lock;
#define LOG_LOCK(prefix, type, obj) \ #define LOG_LOCK(prefix, type, obj) \
if ((obj) != nullptr) { \ if ((obj) != nullptr) { \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
if (!(obj)->get_icon().empty()) { \ if (!(obj)->get_icon_ref().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \
} \ } \
if ((obj)->traits.get_assumed_state()) { \ if ((obj)->traits.get_assumed_state()) { \
ESP_LOGCONFIG(TAG, "%s Assumed State: YES", prefix); \ ESP_LOGCONFIG(TAG, "%s Assumed State: YES", prefix); \

View File

@@ -51,7 +51,7 @@ from esphome.const import (
PLATFORM_RTL87XX, PLATFORM_RTL87XX,
PlatformFramework, PlatformFramework,
) )
from esphome.core import CORE, Lambda, coroutine_with_priority from esphome.core import CORE, CoroPriority, Lambda, coroutine_with_priority
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
logger_ns = cg.esphome_ns.namespace("logger") logger_ns = cg.esphome_ns.namespace("logger")
@@ -275,7 +275,7 @@ CONFIG_SCHEMA = cv.All(
) )
@coroutine_with_priority(90.0) @coroutine_with_priority(CoroPriority.DIAGNOSTICS)
async def to_code(config): async def to_code(config):
baud_rate = config[CONF_BAUD_RATE] baud_rate = config[CONF_BAUD_RATE]
level = config[CONF_LEVEL] level = config[CONF_LEVEL]

View File

@@ -11,7 +11,7 @@ from esphome.const import (
CONF_SERVICES, CONF_SERVICES,
PlatformFramework, PlatformFramework,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
DEPENDENCIES = ["network"] DEPENDENCIES = ["network"]
@@ -72,7 +72,7 @@ def mdns_service(
) )
@coroutine_with_priority(55.0) @coroutine_with_priority(CoroPriority.COMMUNICATION)
async def to_code(config): async def to_code(config):
if config[CONF_DISABLED] is True: if config[CONF_DISABLED] is True:
return return

View File

@@ -14,7 +14,7 @@ from esphome.const import (
) )
from esphome.core import CORE from esphome.core import CORE
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.coroutine import coroutine_with_priority from esphome.coroutine import CoroPriority, coroutine_with_priority
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
CODEOWNERS = ["@jesserockz"] CODEOWNERS = ["@jesserockz"]
@@ -303,7 +303,7 @@ async def media_player_volume_set_action(config, action_id, template_arg, args):
return var return var
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(media_player_ns.using) cg.add_global(media_player_ns.using)
cg.add_define("USE_MEDIA_PLAYER") cg.add_define("USE_MEDIA_PLAYER")

View File

@@ -12,7 +12,7 @@ from esphome.const import (
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
) )
from esphome.core import CORE from esphome.core import CORE
from esphome.coroutine import coroutine_with_priority from esphome.coroutine import CoroPriority, coroutine_with_priority
AUTO_LOAD = ["audio"] AUTO_LOAD = ["audio"]
CODEOWNERS = ["@jesserockz", "@kahrendt"] CODEOWNERS = ["@jesserockz", "@kahrendt"]
@@ -213,7 +213,7 @@ automation.register_condition(
)(microphone_action) )(microphone_action)
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(microphone_ns.using) cg.add_global(microphone_ns.using)
cg.add_define("USE_MICROPHONE") cg.add_define("USE_MICROPHONE")

View File

@@ -57,7 +57,7 @@ from esphome.const import (
PLATFORM_ESP8266, PLATFORM_ESP8266,
PlatformFramework, PlatformFramework,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
DEPENDENCIES = ["network"] DEPENDENCIES = ["network"]
@@ -321,7 +321,7 @@ def exp_mqtt_message(config):
) )
@coroutine_with_priority(40.0) @coroutine_with_priority(CoroPriority.WEB)
async def to_code(config): async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config) await cg.register_component(var, config)

View File

@@ -2,7 +2,7 @@ import esphome.codegen as cg
from esphome.components.esp32 import add_idf_sdkconfig_option from esphome.components.esp32 import add_idf_sdkconfig_option
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ENABLE_IPV6, CONF_MIN_IPV6_ADDR_COUNT from esphome.const import CONF_ENABLE_IPV6, CONF_MIN_IPV6_ADDR_COUNT
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
AUTO_LOAD = ["mdns"] AUTO_LOAD = ["mdns"]
@@ -36,7 +36,7 @@ CONFIG_SCHEMA = cv.Schema(
) )
@coroutine_with_priority(201.0) @coroutine_with_priority(CoroPriority.NETWORK)
async def to_code(config): async def to_code(config):
cg.add_define("USE_NETWORK") cg.add_define("USE_NETWORK")
if CORE.using_arduino and CORE.is_esp32: if CORE.using_arduino and CORE.is_esp32:

View File

@@ -30,7 +30,7 @@ from esphome.const import (
PLATFORM_NRF52, PLATFORM_NRF52,
ThreadModel, ThreadModel,
) )
from esphome.core import CORE, EsphomeError, coroutine_with_priority from esphome.core import CORE, CoroPriority, EsphomeError, coroutine_with_priority
from esphome.storage_json import StorageJSON from esphome.storage_json import StorageJSON
from esphome.types import ConfigType from esphome.types import ConfigType
@@ -132,7 +132,7 @@ def _final_validate(config):
FINAL_VALIDATE_SCHEMA = _final_validate FINAL_VALIDATE_SCHEMA = _final_validate
@coroutine_with_priority(1000) @coroutine_with_priority(CoroPriority.PLATFORM)
async def to_code(config: ConfigType) -> None: async def to_code(config: ConfigType) -> None:
"""Convert the configuration to code.""" """Convert the configuration to code."""
cg.add_platformio_option("board", config[CONF_BOARD]) cg.add_platformio_option("board", config[CONF_BOARD])
@@ -170,7 +170,7 @@ async def to_code(config: ConfigType) -> None:
CORE.add_job(_dfu_to_code, dfu_config) CORE.add_job(_dfu_to_code, dfu_config)
@coroutine_with_priority(90) @coroutine_with_priority(CoroPriority.DIAGNOSTICS)
async def _dfu_to_code(dfu_config): async def _dfu_to_code(dfu_config):
cg.add_define("USE_NRF52_DFU") cg.add_define("USE_NRF52_DFU")
var = cg.new_Pvariable(dfu_config[CONF_ID]) var = cg.new_Pvariable(dfu_config[CONF_ID])

View File

@@ -76,7 +76,7 @@ from esphome.const import (
DEVICE_CLASS_WIND_DIRECTION, DEVICE_CLASS_WIND_DIRECTION,
DEVICE_CLASS_WIND_SPEED, DEVICE_CLASS_WIND_SPEED,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
@@ -321,7 +321,7 @@ async def number_in_range_to_code(config, condition_id, template_arg, args):
return var return var
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(number_ns.using) cg.add_global(number_ns.using)

View File

@@ -14,8 +14,8 @@ void log_number(const char *tag, const char *prefix, const char *type, Number *o
ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str()); ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str());
if (!obj->get_icon().empty()) { if (!obj->get_icon_ref().empty()) {
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon().c_str()); ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon_ref().c_str());
} }
if (!obj->traits.get_unit_of_measurement().empty()) { if (!obj->traits.get_unit_of_measurement().empty()) {

View File

@@ -10,7 +10,7 @@ from esphome.const import (
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
PlatformFramework, PlatformFramework,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
AUTO_LOAD = ["md5", "safe_mode"] AUTO_LOAD = ["md5", "safe_mode"]
@@ -82,7 +82,7 @@ BASE_OTA_SCHEMA = cv.Schema(
) )
@coroutine_with_priority(54.0) @coroutine_with_priority(CoroPriority.COMMUNICATION)
async def to_code(config): async def to_code(config):
cg.add_define("USE_OTA") cg.add_define("USE_OTA")

View File

@@ -18,7 +18,7 @@ from esphome.const import (
PLATFORM_RP2040, PLATFORM_RP2040,
ThreadModel, ThreadModel,
) )
from esphome.core import CORE, EsphomeError, coroutine_with_priority from esphome.core import CORE, CoroPriority, EsphomeError, coroutine_with_priority
from esphome.helpers import copy_file_if_changed, mkdir_p, read_file, write_file from esphome.helpers import copy_file_if_changed, mkdir_p, read_file, write_file
from .const import KEY_BOARD, KEY_PIO_FILES, KEY_RP2040, rp2040_ns from .const import KEY_BOARD, KEY_PIO_FILES, KEY_RP2040, rp2040_ns
@@ -159,7 +159,7 @@ CONFIG_SCHEMA = cv.All(
) )
@coroutine_with_priority(1000) @coroutine_with_priority(CoroPriority.PLATFORM)
async def to_code(config): async def to_code(config):
cg.add(rp2040_ns.setup_preferences()) cg.add(rp2040_ns.setup_preferences())

View File

@@ -10,7 +10,7 @@ from esphome.const import (
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
KEY_PAST_SAFE_MODE, KEY_PAST_SAFE_MODE,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.cpp_generator import RawExpression from esphome.cpp_generator import RawExpression
CODEOWNERS = ["@paulmonigatti", "@jsuanet", "@kbx81"] CODEOWNERS = ["@paulmonigatti", "@jsuanet", "@kbx81"]
@@ -53,7 +53,7 @@ CONFIG_SCHEMA = cv.All(
) )
@coroutine_with_priority(50.0) @coroutine_with_priority(CoroPriority.APPLICATION)
async def to_code(config): async def to_code(config):
if not config[CONF_DISABLED]: if not config[CONF_DISABLED]:
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])

View File

@@ -16,7 +16,7 @@ from esphome.const import (
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_WEB_SERVER, CONF_WEB_SERVER,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
@@ -124,7 +124,7 @@ async def new_select(config, *args, options: list[str]):
return var return var
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(select_ns.using) cg.add_global(select_ns.using)

View File

@@ -12,8 +12,8 @@ namespace select {
#define LOG_SELECT(prefix, type, obj) \ #define LOG_SELECT(prefix, type, obj) \
if ((obj) != nullptr) { \ if ((obj) != nullptr) { \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
if (!(obj)->get_icon().empty()) { \ if (!(obj)->get_icon_ref().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \
} \ } \
} }

View File

@@ -101,7 +101,7 @@ from esphome.const import (
DEVICE_CLASS_WIND_SPEED, DEVICE_CLASS_WIND_SPEED,
ENTITY_CATEGORY_CONFIG, ENTITY_CATEGORY_CONFIG,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
from esphome.util import Registry from esphome.util import Registry
@@ -1142,6 +1142,6 @@ def _lstsq(a, b):
return _mat_dot(_mat_dot(x, a_t), b) return _mat_dot(_mat_dot(x, a_t), b)
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(sensor_ns.using) cg.add_global(sensor_ns.using)

View File

@@ -17,15 +17,15 @@ void log_sensor(const char *tag, const char *prefix, const char *type, Sensor *o
"%s State Class: '%s'\n" "%s State Class: '%s'\n"
"%s Unit of Measurement: '%s'\n" "%s Unit of Measurement: '%s'\n"
"%s Accuracy Decimals: %d", "%s Accuracy Decimals: %d",
prefix, type, obj->get_name().c_str(), prefix, state_class_to_string(obj->get_state_class()).c_str(), prefix, type, obj->get_name().c_str(), prefix, state_class_to_string(obj->get_state_class()), prefix,
prefix, obj->get_unit_of_measurement().c_str(), prefix, obj->get_accuracy_decimals()); obj->get_unit_of_measurement().c_str(), prefix, obj->get_accuracy_decimals());
if (!obj->get_device_class().empty()) { if (!obj->get_device_class().empty()) {
ESP_LOGCONFIG(tag, "%s Device Class: '%s'", prefix, obj->get_device_class().c_str()); ESP_LOGCONFIG(tag, "%s Device Class: '%s'", prefix, obj->get_device_class().c_str());
} }
if (!obj->get_icon().empty()) { if (!obj->get_icon_ref().empty()) {
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon().c_str()); ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon_ref().c_str());
} }
if (obj->get_force_update()) { if (obj->get_force_update()) {
@@ -33,7 +33,7 @@ void log_sensor(const char *tag, const char *prefix, const char *type, Sensor *o
} }
} }
std::string state_class_to_string(StateClass state_class) { const char *state_class_to_string(StateClass state_class) {
switch (state_class) { switch (state_class) {
case STATE_CLASS_MEASUREMENT: case STATE_CLASS_MEASUREMENT:
return "measurement"; return "measurement";

View File

@@ -33,7 +33,7 @@ enum StateClass : uint8_t {
STATE_CLASS_TOTAL = 3, STATE_CLASS_TOTAL = 3,
}; };
std::string state_class_to_string(StateClass state_class); const char *state_class_to_string(StateClass state_class);
/** Base-class for all sensors. /** Base-class for all sensors.
* *

View File

@@ -4,7 +4,7 @@ from esphome.components import audio, audio_dac
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_DATA, CONF_ID, CONF_VOLUME from esphome.const import CONF_DATA, CONF_ID, CONF_VOLUME
from esphome.core import CORE from esphome.core import CORE
from esphome.coroutine import coroutine_with_priority from esphome.coroutine import CoroPriority, coroutine_with_priority
AUTO_LOAD = ["audio"] AUTO_LOAD = ["audio"]
CODEOWNERS = ["@jesserockz", "@kahrendt"] CODEOWNERS = ["@jesserockz", "@kahrendt"]
@@ -138,7 +138,7 @@ async def speaker_mute_action_to_code(config, action_id, template_arg, args):
return cg.new_Pvariable(action_id, template_arg, paren) return cg.new_Pvariable(action_id, template_arg, paren)
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(speaker_ns.using) cg.add_global(speaker_ns.using)
cg.add_define("USE_SPEAKER") cg.add_define("USE_SPEAKER")

View File

@@ -35,7 +35,7 @@ from esphome.const import (
PLATFORM_RP2040, PLATFORM_RP2040,
PlatformFramework, PlatformFramework,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
import esphome.final_validate as fv import esphome.final_validate as fv
CODEOWNERS = ["@esphome/core", "@clydebarrow"] CODEOWNERS = ["@esphome/core", "@clydebarrow"]
@@ -351,7 +351,7 @@ CONFIG_SCHEMA = cv.All(
) )
@coroutine_with_priority(1.0) @coroutine_with_priority(CoroPriority.BUS)
async def to_code(configs): async def to_code(configs):
cg.add_define("USE_SPI") cg.add_define("USE_SPI")
cg.add_global(spi_ns.using) cg.add_global(spi_ns.using)

View File

@@ -2,7 +2,7 @@ from esphome import pins
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_PIN from esphome.const import CONF_ID, CONF_PIN
from esphome.core import coroutine_with_priority from esphome.core import CoroPriority, coroutine_with_priority
status_led_ns = cg.esphome_ns.namespace("status_led") status_led_ns = cg.esphome_ns.namespace("status_led")
StatusLED = status_led_ns.class_("StatusLED", cg.Component) StatusLED = status_led_ns.class_("StatusLED", cg.Component)
@@ -15,7 +15,7 @@ CONFIG_SCHEMA = cv.Schema(
).extend(cv.COMPONENT_SCHEMA) ).extend(cv.COMPONENT_SCHEMA)
@coroutine_with_priority(80.0) @coroutine_with_priority(CoroPriority.STATUS)
async def to_code(config): async def to_code(config):
pin = await cg.gpio_pin_expression(config[CONF_PIN]) pin = await cg.gpio_pin_expression(config[CONF_PIN])
rhs = StatusLED.new(pin) rhs = StatusLED.new(pin)

View File

@@ -10,7 +10,7 @@ from esphome.const import (
CONF_SPEED, CONF_SPEED,
CONF_TARGET, CONF_TARGET,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
IS_PLATFORM_COMPONENT = True IS_PLATFORM_COMPONENT = True
@@ -178,6 +178,6 @@ async def stepper_set_deceleration_to_code(config, action_id, template_arg, args
return var return var
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(stepper_ns.using) cg.add_global(stepper_ns.using)

View File

@@ -21,7 +21,7 @@ from esphome.const import (
DEVICE_CLASS_OUTLET, DEVICE_CLASS_OUTLET,
DEVICE_CLASS_SWITCH, DEVICE_CLASS_SWITCH,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
@@ -230,6 +230,6 @@ async def switch_is_off_to_code(config, condition_id, template_arg, args):
return cg.new_Pvariable(condition_id, template_arg, paren, False) return cg.new_Pvariable(condition_id, template_arg, paren, False)
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(switch_ns.using) cg.add_global(switch_ns.using)

View File

@@ -91,8 +91,8 @@ void log_switch(const char *tag, const char *prefix, const char *type, Switch *o
LOG_STR_ARG(onoff)); LOG_STR_ARG(onoff));
// Add optional fields separately // Add optional fields separately
if (!obj->get_icon().empty()) { if (!obj->get_icon_ref().empty()) {
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon().c_str()); ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon_ref().c_str());
} }
if (obj->assumed_state()) { if (obj->assumed_state()) {
ESP_LOGCONFIG(tag, "%s Assumed State: YES", prefix); ESP_LOGCONFIG(tag, "%s Assumed State: YES", prefix);

View File

@@ -13,7 +13,7 @@ from esphome.const import (
CONF_VALUE, CONF_VALUE,
CONF_WEB_SERVER, CONF_WEB_SERVER,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
@@ -149,7 +149,7 @@ async def new_text(
return var return var
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(text_ns.using) cg.add_global(text_ns.using)

View File

@@ -12,8 +12,8 @@ namespace text {
#define LOG_TEXT(prefix, type, obj) \ #define LOG_TEXT(prefix, type, obj) \
if ((obj) != nullptr) { \ if ((obj) != nullptr) { \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \ ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
if (!(obj)->get_icon().empty()) { \ if (!(obj)->get_icon_ref().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \
} \ } \
} }

View File

@@ -20,7 +20,7 @@ from esphome.const import (
DEVICE_CLASS_EMPTY, DEVICE_CLASS_EMPTY,
DEVICE_CLASS_TIMESTAMP, DEVICE_CLASS_TIMESTAMP,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
from esphome.util import Registry from esphome.util import Registry
@@ -230,7 +230,7 @@ async def new_text_sensor(config, *args):
return var return var
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(text_sensor_ns.using) cg.add_global(text_sensor_ns.using)

View File

@@ -17,8 +17,8 @@ namespace text_sensor {
if (!(obj)->get_device_class().empty()) { \ if (!(obj)->get_device_class().empty()) { \
ESP_LOGCONFIG(TAG, "%s Device Class: '%s'", prefix, (obj)->get_device_class().c_str()); \ ESP_LOGCONFIG(TAG, "%s Device Class: '%s'", prefix, (obj)->get_device_class().c_str()); \
} \ } \
if (!(obj)->get_icon().empty()) { \ if (!(obj)->get_icon_ref().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \ ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \
} \ } \
} }

View File

@@ -26,7 +26,7 @@ from esphome.const import (
CONF_TIMEZONE, CONF_TIMEZONE,
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -340,7 +340,7 @@ async def register_time(time_var, config):
await setup_time_core_(time_var, config) await setup_time_core_(time_var, config)
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
if CORE.using_zephyr: if CORE.using_zephyr:
zephyr_add_prj_conf("POSIX_CLOCK", True) zephyr_add_prj_conf("POSIX_CLOCK", True)

View File

@@ -13,7 +13,7 @@ from esphome.const import (
CONF_SWAP_XY, CONF_SWAP_XY,
CONF_TRANSFORM, CONF_TRANSFORM,
) )
from esphome.core import coroutine_with_priority from esphome.core import CoroPriority, coroutine_with_priority
CODEOWNERS = ["@jesserockz", "@nielsnl68"] CODEOWNERS = ["@jesserockz", "@nielsnl68"]
DEPENDENCIES = ["display"] DEPENDENCIES = ["display"]
@@ -152,7 +152,7 @@ async def register_touchscreen(var, config):
) )
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(touchscreen_ns.using) cg.add_global(touchscreen_ns.using)
cg.add_define("USE_TOUCHSCREEN") cg.add_define("USE_TOUCHSCREEN")

View File

@@ -14,7 +14,7 @@ from esphome.const import (
DEVICE_CLASS_FIRMWARE, DEVICE_CLASS_FIRMWARE,
ENTITY_CATEGORY_CONFIG, ENTITY_CATEGORY_CONFIG,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
@@ -124,7 +124,7 @@ async def new_update(config):
return var return var
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(update_ns.using) cg.add_global(update_ns.using)

View File

@@ -21,7 +21,7 @@ from esphome.const import (
DEVICE_CLASS_GAS, DEVICE_CLASS_GAS,
DEVICE_CLASS_WATER, DEVICE_CLASS_WATER,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObjClass
@@ -233,6 +233,6 @@ async def valve_control_to_code(config, action_id, template_arg, args):
return var return var
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config): async def to_code(config):
cg.add_global(valve_ns.using) cg.add_global(valve_ns.using)

View File

@@ -31,7 +31,7 @@ from esphome.const import (
PLATFORM_LN882X, PLATFORM_LN882X,
PLATFORM_RTL87XX, PLATFORM_RTL87XX,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
import esphome.final_validate as fv import esphome.final_validate as fv
from esphome.types import ConfigType from esphome.types import ConfigType
@@ -269,7 +269,7 @@ def add_resource_as_progmem(
cg.add_global(cg.RawExpression(size_t)) cg.add_global(cg.RawExpression(size_t))
@coroutine_with_priority(40.0) @coroutine_with_priority(CoroPriority.WEB)
async def to_code(config): async def to_code(config):
paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID]) paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID])

View File

@@ -3,7 +3,7 @@ from esphome.components.esp32 import add_idf_component
from esphome.components.ota import BASE_OTA_SCHEMA, OTAComponent, ota_to_code from esphome.components.ota import BASE_OTA_SCHEMA, OTAComponent, ota_to_code
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ID from esphome.const import CONF_ID
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
DEPENDENCIES = ["network", "web_server_base"] DEPENDENCIES = ["network", "web_server_base"]
@@ -22,7 +22,7 @@ CONFIG_SCHEMA = (
) )
@coroutine_with_priority(52.0) @coroutine_with_priority(CoroPriority.COMMUNICATION)
async def to_code(config): async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await ota_to_code(var, config) await ota_to_code(var, config)

View File

@@ -1,7 +1,7 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ID from esphome.const import CONF_ID
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
DEPENDENCIES = ["network"] DEPENDENCIES = ["network"]
@@ -26,7 +26,7 @@ CONFIG_SCHEMA = cv.Schema(
) )
@coroutine_with_priority(65.0) @coroutine_with_priority(CoroPriority.COMMUNICATION)
async def to_code(config): async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config) await cg.register_component(var, config)

View File

@@ -44,7 +44,7 @@ from esphome.const import (
CONF_USERNAME, CONF_USERNAME,
PlatformFramework, PlatformFramework,
) )
from esphome.core import CORE, HexInt, coroutine_with_priority from esphome.core import CORE, CoroPriority, HexInt, coroutine_with_priority
import esphome.final_validate as fv import esphome.final_validate as fv
from . import wpa2_eap from . import wpa2_eap
@@ -370,7 +370,7 @@ def wifi_network(config, ap, static_ip):
return ap return ap
@coroutine_with_priority(60.0) @coroutine_with_priority(CoroPriority.COMMUNICATION)
async def to_code(config): async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_use_address(config[CONF_USE_ADDRESS])) cg.add(var.set_use_address(config[CONF_USE_ADDRESS]))

View File

@@ -29,6 +29,7 @@ from esphome.const import (
# pylint: disable=unused-import # pylint: disable=unused-import
from esphome.coroutine import ( # noqa: F401 from esphome.coroutine import ( # noqa: F401
CoroPriority,
FakeAwaitable as _FakeAwaitable, FakeAwaitable as _FakeAwaitable,
FakeEventLoop as _FakeEventLoop, FakeEventLoop as _FakeEventLoop,
coroutine, coroutine,

View File

@@ -39,7 +39,7 @@ from esphome.const import (
PlatformFramework, PlatformFramework,
__version__ as ESPHOME_VERSION, __version__ as ESPHOME_VERSION,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.helpers import ( from esphome.helpers import (
copy_file_if_changed, copy_file_if_changed,
fnv1a_32bit_hash, fnv1a_32bit_hash,
@@ -359,7 +359,7 @@ ARDUINO_GLUE_CODE = """\
""" """
@coroutine_with_priority(-999.0) @coroutine_with_priority(CoroPriority.WORKAROUNDS)
async def add_arduino_global_workaround(): async def add_arduino_global_workaround():
# The Arduino framework defined these itself in the global # The Arduino framework defined these itself in the global
# namespace. For the esphome codebase that is not a problem, # namespace. For the esphome codebase that is not a problem,
@@ -376,7 +376,7 @@ async def add_arduino_global_workaround():
cg.add_global(cg.RawStatement(line)) cg.add_global(cg.RawStatement(line))
@coroutine_with_priority(-1000.0) @coroutine_with_priority(CoroPriority.FINAL)
async def add_includes(includes): async def add_includes(includes):
# Add includes at the very end, so that the included files can access global variables # Add includes at the very end, so that the included files can access global variables
for include in includes: for include in includes:
@@ -392,7 +392,7 @@ async def add_includes(includes):
include_file(path, basename) include_file(path, basename)
@coroutine_with_priority(-1000.0) @coroutine_with_priority(CoroPriority.FINAL)
async def _add_platformio_options(pio_options): async def _add_platformio_options(pio_options):
# Add includes at the very end, so that they override everything # Add includes at the very end, so that they override everything
for key, val in pio_options.items(): for key, val in pio_options.items():
@@ -401,7 +401,7 @@ async def _add_platformio_options(pio_options):
cg.add_platformio_option(key, val) cg.add_platformio_option(key, val)
@coroutine_with_priority(30.0) @coroutine_with_priority(CoroPriority.AUTOMATION)
async def _add_automations(config): async def _add_automations(config):
for conf in config.get(CONF_ON_BOOT, []): for conf in config.get(CONF_ON_BOOT, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], conf.get(CONF_PRIORITY)) trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], conf.get(CONF_PRIORITY))
@@ -423,7 +423,7 @@ async def _add_automations(config):
DATETIME_SUBTYPES = {"date", "time", "datetime"} DATETIME_SUBTYPES = {"date", "time", "datetime"}
@coroutine_with_priority(-1000.0) @coroutine_with_priority(CoroPriority.FINAL)
async def _add_platform_defines() -> None: async def _add_platform_defines() -> None:
# Generate compile-time defines for platforms that have actual entities # Generate compile-time defines for platforms that have actual entities
# Only add USE_* and count defines when there are entities # Only add USE_* and count defines when there are entities
@@ -442,7 +442,7 @@ async def _add_platform_defines() -> None:
cg.add_define(f"USE_{platform_name.upper()}") cg.add_define(f"USE_{platform_name.upper()}")
@coroutine_with_priority(100.0) @coroutine_with_priority(CoroPriority.CORE)
async def to_code(config: ConfigType) -> None: async def to_code(config: ConfigType) -> None:
cg.add_global(cg.global_ns.namespace("esphome").using) cg.add_global(cg.global_ns.namespace("esphome").using)
# These can be used by user lambdas, put them to default scope # These can be used by user lambdas, put them to default scope

View File

@@ -45,10 +45,15 @@ void EntityBase::set_icon(const char *icon) {
#endif #endif
} }
// Check if the object_id is dynamic (changes with MAC suffix)
bool EntityBase::is_object_id_dynamic_() const {
return !this->flags_.has_own_name && App.is_name_add_mac_suffix_enabled();
}
// Entity Object ID // Entity Object ID
std::string EntityBase::get_object_id() const { std::string EntityBase::get_object_id() const {
// Check if `App.get_friendly_name()` is constant or dynamic. // Check if `App.get_friendly_name()` is constant or dynamic.
if (!this->flags_.has_own_name && App.is_name_add_mac_suffix_enabled()) { if (this->is_object_id_dynamic_()) {
// `App.get_friendly_name()` is dynamic. // `App.get_friendly_name()` is dynamic.
return str_sanitize(str_snake_case(App.get_friendly_name())); return str_sanitize(str_snake_case(App.get_friendly_name()));
} }
@@ -58,7 +63,7 @@ std::string EntityBase::get_object_id() const {
StringRef EntityBase::get_object_id_ref_for_api_() const { StringRef EntityBase::get_object_id_ref_for_api_() const {
static constexpr auto EMPTY_STRING = StringRef::from_lit(""); static constexpr auto EMPTY_STRING = StringRef::from_lit("");
// Return empty for dynamic case (MAC suffix) // Return empty for dynamic case (MAC suffix)
if (!this->flags_.has_own_name && App.is_name_add_mac_suffix_enabled()) { if (this->is_object_id_dynamic_()) {
return EMPTY_STRING; return EMPTY_STRING;
} }
// For static case, return the string or empty if null // For static case, return the string or empty if null
@@ -70,7 +75,10 @@ void EntityBase::set_object_id(const char *object_id) {
} }
// Calculate Object ID Hash from Entity Name // Calculate Object ID Hash from Entity Name
void EntityBase::calc_object_id_() { this->object_id_hash_ = fnv1_hash(this->get_object_id()); } void EntityBase::calc_object_id_() {
this->object_id_hash_ =
fnv1_hash(this->is_object_id_dynamic_() ? this->get_object_id().c_str() : this->object_id_c_str_);
}
uint32_t EntityBase::get_object_id_hash() { return this->object_id_hash_; } uint32_t EntityBase::get_object_id_hash() { return this->object_id_hash_; }

View File

@@ -126,6 +126,9 @@ class EntityBase {
virtual uint32_t hash_base() { return 0L; } virtual uint32_t hash_base() { return 0L; }
void calc_object_id_(); void calc_object_id_();
/// Check if the object_id is dynamic (changes with MAC suffix)
bool is_object_id_dynamic_() const;
StringRef name_; StringRef name_;
const char *object_id_c_str_{nullptr}; const char *object_id_c_str_{nullptr};
#ifdef USE_ENTITY_ICON #ifdef USE_ENTITY_ICON

View File

@@ -142,11 +142,13 @@ uint16_t crc16be(const uint8_t *data, uint16_t len, uint16_t crc, uint16_t poly,
return refout ? (crc ^ 0xffff) : crc; return refout ? (crc ^ 0xffff) : crc;
} }
uint32_t fnv1_hash(const std::string &str) { uint32_t fnv1_hash(const char *str) {
uint32_t hash = 2166136261UL; uint32_t hash = 2166136261UL;
for (char c : str) { if (str) {
hash *= 16777619UL; while (*str) {
hash ^= c; hash *= 16777619UL;
hash ^= *str++;
}
} }
return hash; return hash;
} }

View File

@@ -155,7 +155,8 @@ uint16_t crc16be(const uint8_t *data, uint16_t len, uint16_t crc = 0, uint16_t p
bool refout = false); bool refout = false);
/// Calculate a FNV-1 hash of \p str. /// Calculate a FNV-1 hash of \p str.
uint32_t fnv1_hash(const std::string &str); uint32_t fnv1_hash(const char *str);
inline uint32_t fnv1_hash(const std::string &str) { return fnv1_hash(str.c_str()); }
/// Return a random 32-bit unsigned integer. /// Return a random 32-bit unsigned integer.
uint32_t random_uint32(); uint32_t random_uint32();

View File

@@ -42,7 +42,10 @@ Here everything is combined in `yield` expressions. You await other coroutines u
the last `yield` expression defines what is returned. the last `yield` expression defines what is returned.
""" """
from __future__ import annotations
from collections.abc import Awaitable, Callable, Generator, Iterator from collections.abc import Awaitable, Callable, Generator, Iterator
import enum
import functools import functools
import heapq import heapq
import inspect import inspect
@@ -53,6 +56,79 @@ from typing import Any
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
class CoroPriority(enum.IntEnum):
"""Execution priority stages for ESPHome code generation.
Higher values run first. These stages ensure proper dependency
resolution during code generation.
"""
# Platform initialization - must run first
# Examples: esp32, esp8266, rp2040
PLATFORM = 1000
# Network infrastructure setup
# Examples: network (201)
NETWORK = 201
# Network transport layer
# Examples: async_tcp (200)
NETWORK_TRANSPORT = 200
# Core system components
# Examples: esphome core, most entity base components (cover, update, datetime,
# valve, alarm_control_panel, lock, event, binary_sensor, button, climate, fan,
# light, media_player, number, select, sensor, switch, text_sensor, text),
# microphone, speaker, audio_dac, touchscreen, stepper
CORE = 100
# Diagnostic and debugging systems
# Examples: logger (90)
DIAGNOSTICS = 90
# Status and monitoring systems
# Examples: status_led (80)
STATUS = 80
# Communication protocols and services
# Examples: web_server_base (65), captive_portal (64), wifi (60), ethernet (60),
# mdns (55), ota_updates (54), web_server_ota (52)
COMMUNICATION = 60
# Application-level services
# Examples: safe_mode (50)
APPLICATION = 50
# Web and UI services
# Examples: web_server (40)
WEB = 40
# Automations and user logic
# Examples: esphome core automations (30)
AUTOMATION = 30
# Bus and peripheral setup
# Examples: i2c (1)
BUS = 1
# Standard component priority (default)
# Components without explicit priority run at 0
COMPONENT = 0
# Components that need others to be registered first
# Examples: globals (-100)
LATE = -100
# Platform-specific workarounds and fixes
# Examples: add_arduino_global_workaround (-999), esp8266 pin states (-999)
WORKAROUNDS = -999
# Final setup that requires all components to be registered
# Examples: add_includes, _add_platformio_options, _add_platform_defines (all -1000),
# esp32_ble_tracker feature defines (-1000)
FINAL = -1000
def coroutine(func: Callable[..., Any]) -> Callable[..., Awaitable[Any]]: def coroutine(func: Callable[..., Any]) -> Callable[..., Awaitable[Any]]:
"""Decorator to apply to methods to convert them to ESPHome coroutines.""" """Decorator to apply to methods to convert them to ESPHome coroutines."""
if getattr(func, "_esphome_coroutine", False): if getattr(func, "_esphome_coroutine", False):
@@ -95,15 +171,16 @@ def coroutine(func: Callable[..., Any]) -> Callable[..., Awaitable[Any]]:
return coro return coro
def coroutine_with_priority(priority: float): def coroutine_with_priority(priority: float | CoroPriority):
"""Decorator to apply to functions to convert them to ESPHome coroutines. """Decorator to apply to functions to convert them to ESPHome coroutines.
:param priority: priority with which to schedule the coroutine, higher priorities run first. :param priority: priority with which to schedule the coroutine, higher priorities run first.
Can be a float or a CoroPriority enum value.
""" """
def decorator(func): def decorator(func):
coro = coroutine(func) coro = coroutine(func)
coro.priority = priority coro.priority = float(priority)
return coro return coro
return decorator return decorator
@@ -173,7 +250,7 @@ class _Task:
self.iterator = iterator self.iterator = iterator
self.original_function = original_function self.original_function = original_function
def with_priority(self, priority: float) -> "_Task": def with_priority(self, priority: float) -> _Task:
return _Task(priority, self.id_number, self.iterator, self.original_function) return _Task(priority, self.id_number, self.iterator, self.original_function)
@property @property

View File

@@ -0,0 +1,110 @@
esphome:
name: test_device
on_boot:
- lambda: |-
ESP_LOGD("test", "Host preferences test starting");
host:
logger:
level: DEBUG
api:
preferences:
flash_write_interval: 0s # Disable automatic saving for test control
switch:
- platform: template
name: "Test Switch"
id: test_switch
optimistic: true
restore_mode: DISABLED # Don't auto-restore for test control
number:
- platform: template
name: "Test Number"
id: test_number
min_value: 0
max_value: 100
step: 0.1
optimistic: true
restore_value: false # Don't auto-restore for test control
button:
- platform: template
name: "Save Preferences"
on_press:
- lambda: |-
// Save current values to preferences
ESPPreferenceObject switch_pref = global_preferences->make_preference<bool>(0x1234);
ESPPreferenceObject number_pref = global_preferences->make_preference<float>(0x5678);
bool switch_value = id(test_switch).state;
float number_value = id(test_number).state;
if (switch_pref.save(&switch_value)) {
ESP_LOGI("test", "Preference saved: key=switch, value=%.1f", switch_value ? 1.0 : 0.0);
}
if (number_pref.save(&number_value)) {
ESP_LOGI("test", "Preference saved: key=number, value=%.1f", number_value);
}
// Force sync to disk
global_preferences->sync();
- platform: template
name: "Load Preferences"
on_press:
- lambda: |-
// Load values from preferences
ESPPreferenceObject switch_pref = global_preferences->make_preference<bool>(0x1234);
ESPPreferenceObject number_pref = global_preferences->make_preference<float>(0x5678);
// Also try to load non-existent preferences (tests our fix)
ESPPreferenceObject fake_pref1 = global_preferences->make_preference<uint32_t>(0x9999);
ESPPreferenceObject fake_pref2 = global_preferences->make_preference<uint32_t>(0xAAAA);
bool switch_value = false;
float number_value = 0.0;
uint32_t fake_value = 0;
int loaded_count = 0;
// These should not exist and shouldn't create map entries
fake_pref1.load(&fake_value);
fake_pref2.load(&fake_value);
if (switch_pref.load(&switch_value)) {
id(test_switch).publish_state(switch_value);
ESP_LOGI("test", "Preference loaded: key=switch, value=%.1f", switch_value ? 1.0 : 0.0);
loaded_count++;
} else {
ESP_LOGW("test", "Failed to load switch preference");
}
if (number_pref.load(&number_value)) {
id(test_number).publish_state(number_value);
ESP_LOGI("test", "Preference loaded: key=number, value=%.1f", number_value);
loaded_count++;
} else {
ESP_LOGW("test", "Failed to load number preference");
}
// Log completion message for the test to detect
ESP_LOGI("test", "Final load test: loaded %d preferences successfully", loaded_count);
- platform: template
name: "Verify Preferences"
on_press:
- lambda: |-
// Verify current values match what we expect
bool switch_value = id(test_switch).state;
float number_value = id(test_number).state;
// After loading, switch should be true (1.0) and number should be 42.5
if (switch_value == true && number_value == 42.5) {
ESP_LOGI("test", "Preferences verified: values match!");
} else {
ESP_LOGE("test", "Preferences mismatch: switch=%d, number=%.1f",
switch_value, number_value);
}

View File

@@ -0,0 +1,167 @@
"""Test host preferences save and load functionality."""
from __future__ import annotations
import asyncio
import re
from typing import Any
from aioesphomeapi import ButtonInfo, EntityInfo, NumberInfo, SwitchInfo
import pytest
from .types import APIClientConnectedFactory, RunCompiledFunction
def find_entity_by_name(
entities: list[EntityInfo], entity_type: type, name: str
) -> Any:
"""Helper to find an entity by type and name."""
return next(
(e for e in entities if isinstance(e, entity_type) and e.name == name), None
)
@pytest.mark.asyncio
async def test_host_preferences_save_load(
yaml_config: str,
run_compiled: RunCompiledFunction,
api_client_connected: APIClientConnectedFactory,
) -> None:
"""Test that preferences are correctly saved and loaded after our optimization fix."""
loop = asyncio.get_running_loop()
log_lines: list[str] = []
preferences_saved = loop.create_future()
preferences_loaded = loop.create_future()
values_match = loop.create_future()
final_load_complete = loop.create_future()
# Patterns to match preference logs
save_pattern = re.compile(r"Preference saved: key=(\w+), value=([0-9.]+)")
load_pattern = re.compile(r"Preference loaded: key=(\w+), value=([0-9.]+)")
verify_pattern = re.compile(r"Preferences verified: values match!")
final_load_success_pattern = re.compile(
r"Final load test: loaded \d+ preferences successfully"
)
saved_values: dict[str, float] = {}
loaded_values: dict[str, float] = {}
def check_output(line: str) -> None:
"""Check log output for preference operations."""
log_lines.append(line)
# Look for save operations
match = save_pattern.search(line)
if match:
key = match.group(1)
value = float(match.group(2))
saved_values[key] = value
if len(saved_values) >= 2 and not preferences_saved.done():
preferences_saved.set_result(True)
# Look for load operations
match = load_pattern.search(line)
if match:
key = match.group(1)
value = float(match.group(2))
loaded_values[key] = value
if len(loaded_values) >= 2 and not preferences_loaded.done():
preferences_loaded.set_result(True)
# Look for verification
if verify_pattern.search(line) and not values_match.done():
values_match.set_result(True)
# Look for final load test completion
if final_load_success_pattern.search(line) and not final_load_complete.done():
final_load_complete.set_result(True)
async with (
run_compiled(yaml_config, line_callback=check_output),
api_client_connected() as client,
):
# Get entity list
entities, _ = await client.list_entities_services()
# Find our test entities using helper
test_switch = find_entity_by_name(entities, SwitchInfo, "Test Switch")
test_number = find_entity_by_name(entities, NumberInfo, "Test Number")
save_button = find_entity_by_name(entities, ButtonInfo, "Save Preferences")
load_button = find_entity_by_name(entities, ButtonInfo, "Load Preferences")
verify_button = find_entity_by_name(entities, ButtonInfo, "Verify Preferences")
assert test_switch is not None, "Test Switch not found"
assert test_number is not None, "Test Number not found"
assert save_button is not None, "Save Preferences button not found"
assert load_button is not None, "Load Preferences button not found"
assert verify_button is not None, "Verify Preferences button not found"
# Set initial values
client.switch_command(test_switch.key, True)
client.number_command(test_number.key, 42.5)
# Save preferences
client.button_command(save_button.key)
# Wait for save to complete
try:
await asyncio.wait_for(preferences_saved, timeout=5.0)
except TimeoutError:
pytest.fail("Preferences not saved within timeout")
# Verify we saved the expected values
assert "switch" in saved_values, f"Switch preference not saved: {saved_values}"
assert "number" in saved_values, f"Number preference not saved: {saved_values}"
assert saved_values["switch"] == 1.0, (
f"Switch value incorrect: {saved_values['switch']}"
)
assert saved_values["number"] == 42.5, (
f"Number value incorrect: {saved_values['number']}"
)
# Change the values to something else
client.switch_command(test_switch.key, False)
client.number_command(test_number.key, 13.7)
# Load preferences (should restore the saved values)
client.button_command(load_button.key)
# Wait for load to complete
try:
await asyncio.wait_for(preferences_loaded, timeout=5.0)
except TimeoutError:
pytest.fail("Preferences not loaded within timeout")
# Verify loaded values match saved values
assert "switch" in loaded_values, (
f"Switch preference not loaded: {loaded_values}"
)
assert "number" in loaded_values, (
f"Number preference not loaded: {loaded_values}"
)
assert loaded_values["switch"] == saved_values["switch"], (
f"Loaded switch value {loaded_values['switch']} doesn't match saved {saved_values['switch']}"
)
assert loaded_values["number"] == saved_values["number"], (
f"Loaded number value {loaded_values['number']} doesn't match saved {saved_values['number']}"
)
# Verify the values were actually restored
client.button_command(verify_button.key)
# Wait for verification
try:
await asyncio.wait_for(values_match, timeout=5.0)
except TimeoutError:
pytest.fail("Preference verification failed within timeout")
# Test that non-existent preferences don't crash (tests our fix)
# This will trigger load attempts for keys that don't exist
# Our fix should prevent map entries from being created
client.button_command(load_button.key)
# Wait for the final load test to complete
try:
await asyncio.wait_for(final_load_complete, timeout=5.0)
except TimeoutError:
pytest.fail("Final load test did not complete within timeout")

View File

@@ -0,0 +1,204 @@
"""Tests for the coroutine module."""
import pytest
from esphome.coroutine import CoroPriority, FakeEventLoop, coroutine_with_priority
def test_coro_priority_enum_values() -> None:
"""Test that CoroPriority enum values match expected priorities."""
assert CoroPriority.PLATFORM == 1000
assert CoroPriority.NETWORK == 201
assert CoroPriority.NETWORK_TRANSPORT == 200
assert CoroPriority.CORE == 100
assert CoroPriority.DIAGNOSTICS == 90
assert CoroPriority.STATUS == 80
assert CoroPriority.COMMUNICATION == 60
assert CoroPriority.APPLICATION == 50
assert CoroPriority.WEB == 40
assert CoroPriority.AUTOMATION == 30
assert CoroPriority.BUS == 1
assert CoroPriority.COMPONENT == 0
assert CoroPriority.LATE == -100
assert CoroPriority.WORKAROUNDS == -999
assert CoroPriority.FINAL == -1000
def test_coroutine_with_priority_accepts_float() -> None:
"""Test that coroutine_with_priority accepts float values."""
@coroutine_with_priority(100.0)
def test_func() -> None:
pass
assert hasattr(test_func, "priority")
assert test_func.priority == 100.0
def test_coroutine_with_priority_accepts_enum() -> None:
"""Test that coroutine_with_priority accepts CoroPriority enum values."""
@coroutine_with_priority(CoroPriority.CORE)
def test_func() -> None:
pass
assert hasattr(test_func, "priority")
assert test_func.priority == 100.0
def test_float_and_enum_are_interchangeable() -> None:
"""Test that float and CoroPriority enum values produce the same priority."""
@coroutine_with_priority(100.0)
def func_with_float() -> None:
pass
@coroutine_with_priority(CoroPriority.CORE)
def func_with_enum() -> None:
pass
assert func_with_float.priority == func_with_enum.priority
assert func_with_float.priority == 100.0
@pytest.mark.parametrize(
("enum_value", "float_value"),
[
(CoroPriority.PLATFORM, 1000.0),
(CoroPriority.NETWORK, 201.0),
(CoroPriority.NETWORK_TRANSPORT, 200.0),
(CoroPriority.CORE, 100.0),
(CoroPriority.DIAGNOSTICS, 90.0),
(CoroPriority.STATUS, 80.0),
(CoroPriority.COMMUNICATION, 60.0),
(CoroPriority.APPLICATION, 50.0),
(CoroPriority.WEB, 40.0),
(CoroPriority.AUTOMATION, 30.0),
(CoroPriority.BUS, 1.0),
(CoroPriority.COMPONENT, 0.0),
(CoroPriority.LATE, -100.0),
(CoroPriority.WORKAROUNDS, -999.0),
(CoroPriority.FINAL, -1000.0),
],
)
def test_all_priority_values_are_interchangeable(
enum_value: CoroPriority, float_value: float
) -> None:
"""Test that all CoroPriority values work correctly with coroutine_with_priority."""
@coroutine_with_priority(enum_value)
def func_with_enum() -> None:
pass
@coroutine_with_priority(float_value)
def func_with_float() -> None:
pass
assert func_with_enum.priority == float_value
assert func_with_float.priority == float_value
assert func_with_enum.priority == func_with_float.priority
def test_execution_order_with_enum_priorities() -> None:
"""Test that execution order is correct when using enum priorities."""
execution_order: list[str] = []
@coroutine_with_priority(CoroPriority.PLATFORM)
async def platform_func() -> None:
execution_order.append("platform")
@coroutine_with_priority(CoroPriority.CORE)
async def core_func() -> None:
execution_order.append("core")
@coroutine_with_priority(CoroPriority.FINAL)
async def final_func() -> None:
execution_order.append("final")
# Create event loop and add jobs
loop = FakeEventLoop()
loop.add_job(platform_func)
loop.add_job(core_func)
loop.add_job(final_func)
# Run all tasks
loop.flush_tasks()
# Check execution order (higher priority runs first)
assert execution_order == ["platform", "core", "final"]
def test_mixed_float_and_enum_priorities() -> None:
"""Test that mixing float and enum priorities works correctly."""
execution_order: list[str] = []
@coroutine_with_priority(1000.0) # Same as PLATFORM
async def func1() -> None:
execution_order.append("func1")
@coroutine_with_priority(CoroPriority.CORE)
async def func2() -> None:
execution_order.append("func2")
@coroutine_with_priority(-1000.0) # Same as FINAL
async def func3() -> None:
execution_order.append("func3")
# Create event loop and add jobs
loop = FakeEventLoop()
loop.add_job(func2)
loop.add_job(func3)
loop.add_job(func1)
# Run all tasks
loop.flush_tasks()
# Check execution order
assert execution_order == ["func1", "func2", "func3"]
def test_enum_priority_comparison() -> None:
"""Test that enum priorities can be compared directly."""
assert CoroPriority.PLATFORM > CoroPriority.NETWORK
assert CoroPriority.NETWORK > CoroPriority.NETWORK_TRANSPORT
assert CoroPriority.NETWORK_TRANSPORT > CoroPriority.CORE
assert CoroPriority.CORE > CoroPriority.DIAGNOSTICS
assert CoroPriority.DIAGNOSTICS > CoroPriority.STATUS
assert CoroPriority.STATUS > CoroPriority.COMMUNICATION
assert CoroPriority.COMMUNICATION > CoroPriority.APPLICATION
assert CoroPriority.APPLICATION > CoroPriority.WEB
assert CoroPriority.WEB > CoroPriority.AUTOMATION
assert CoroPriority.AUTOMATION > CoroPriority.BUS
assert CoroPriority.BUS > CoroPriority.COMPONENT
assert CoroPriority.COMPONENT > CoroPriority.LATE
assert CoroPriority.LATE > CoroPriority.WORKAROUNDS
assert CoroPriority.WORKAROUNDS > CoroPriority.FINAL
def test_custom_priority_between_enum_values() -> None:
"""Test that custom float priorities between enum values work correctly."""
execution_order: list[str] = []
@coroutine_with_priority(CoroPriority.CORE) # 100
async def core_func() -> None:
execution_order.append("core")
@coroutine_with_priority(95.0) # Between CORE and DIAGNOSTICS
async def custom_func() -> None:
execution_order.append("custom")
@coroutine_with_priority(CoroPriority.DIAGNOSTICS) # 90
async def diag_func() -> None:
execution_order.append("diagnostics")
# Create event loop and add jobs
loop = FakeEventLoop()
loop.add_job(diag_func)
loop.add_job(core_func)
loop.add_job(custom_func)
# Run all tasks
loop.flush_tasks()
# Check execution order
assert execution_order == ["core", "custom", "diagnostics"]