1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-25 06:32:22 +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_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.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)
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(alarm_control_panel_ns.using)

View File

@@ -24,7 +24,7 @@ from esphome.const import (
CONF_TRIGGER_ID,
CONF_VARIABLES,
)
from esphome.core import CORE, coroutine_with_priority
from esphome.core import CORE, CoroPriority, coroutine_with_priority
DOMAIN = "api"
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):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)

View File

@@ -8,7 +8,7 @@ from esphome.const import (
PLATFORM_LN882X,
PLATFORM_RTL87XX,
)
from esphome.core import CORE, coroutine_with_priority
from esphome.core import CORE, CoroPriority, coroutine_with_priority
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):
if CORE.is_esp32 or CORE.is_libretiny:
# https://github.com/ESP32Async/AsyncTCP

View File

@@ -2,7 +2,7 @@ from esphome import automation
import esphome.codegen as cg
import esphome.config_validation as cv
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"]
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
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_define("USE_AUDIO_ADC")
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.config_validation as cv
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"]
IS_PLATFORM_COMPONENT = True
@@ -51,7 +51,7 @@ async def audio_dac_set_volume_to_code(config, action_id, template_arg, args):
return var
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_define("USE_AUDIO_DAC")
cg.add_global(audio_dac_ns.using)

View File

@@ -59,7 +59,7 @@ from esphome.const import (
DEVICE_CLASS_VIBRATION,
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.cpp_generator import MockObjClass
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)
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(binary_sensor_ns.using)

View File

@@ -17,7 +17,7 @@ from esphome.const import (
DEVICE_CLASS_RESTART,
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.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)
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
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());
if (!obj->get_icon().empty()) {
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon().c_str());
if (!obj->get_icon_ref().empty()) {
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_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"]
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):
paren = await cg.get_variable(config[CONF_WEB_SERVER_BASE_ID])

View File

@@ -47,7 +47,7 @@ from esphome.const import (
CONF_VISUAL,
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.cpp_generator import MockObjClass
@@ -517,6 +517,6 @@ async def climate_control_to_code(config, action_id, template_arg, args):
return var
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(climate_ns.using)

View File

@@ -32,7 +32,7 @@ from esphome.const import (
DEVICE_CLASS_SHUTTER,
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.cpp_generator import MockObjClass
@@ -263,6 +263,6 @@ async def cover_control_to_code(config, action_id, template_arg, args):
return var
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(cover_ns.using)

View File

@@ -21,7 +21,7 @@ from esphome.const import (
CONF_WEB_SERVER,
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.cpp_generator import MockObjClass
@@ -172,7 +172,7 @@ async def new_datetime(config, *args):
return var
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(datetime_ns.using)

View File

@@ -16,8 +16,8 @@ namespace datetime {
#define LOG_DATETIME_DATE(prefix, type, obj) \
if ((obj) != nullptr) { \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
if (!(obj)->get_icon().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \
if (!(obj)->get_icon_ref().empty()) { \
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) \
if ((obj) != nullptr) { \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
if (!(obj)->get_icon().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \
if (!(obj)->get_icon_ref().empty()) { \
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) \
if ((obj) != nullptr) { \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
if (!(obj)->get_icon().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \
if (!(obj)->get_icon_ref().empty()) { \
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,
SCHEDULER_DONT_RUN,
)
from esphome.core import coroutine_with_priority
from esphome.core import CoroPriority, coroutine_with_priority
IS_PLATFORM_COMPONENT = True
@@ -218,7 +218,7 @@ async def display_is_displaying_page_to_code(config, condition_id, template_arg,
return var
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(display_ns.using)
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]])
# 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_ESPTOOLPY_FLASHSIZE_{config[CONF_FLASH_SIZE]}", True

View File

@@ -30,7 +30,7 @@ from esphome.const import (
CONF_SERVICE_UUID,
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.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
# chance to call register_ble_tracker and register_client before the list is checked
# and added to the global defines list.
@coroutine_with_priority(-1000)
@coroutine_with_priority(CoroPriority.FINAL)
async def _add_ble_features():
# Add feature-specific defines based on what's needed
if BLEFeatures.ESP_BT_DEVICE in _required_features:

View File

@@ -17,7 +17,7 @@ from esphome.const import (
PLATFORM_ESP8266,
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 .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):
cg.add(esp8266_ns.setup_preferences())

View File

@@ -17,7 +17,7 @@ from esphome.const import (
CONF_PULLUP,
PLATFORM_ESP8266,
)
from esphome.core import CORE, coroutine_with_priority
from esphome.core import CORE, CoroPriority, coroutine_with_priority
from . import boards
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
@coroutine_with_priority(-999.0)
@coroutine_with_priority(CoroPriority.WORKAROUNDS)
async def add_pin_initial_states_array():
# Add includes at the very end, so that they override everything
initial_states: list[PinInitialState] = CORE.data[KEY_ESP8266][

View File

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

View File

@@ -38,7 +38,12 @@ from esphome.const import (
KEY_CORE,
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
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):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)

View File

@@ -17,7 +17,7 @@ from esphome.const import (
DEVICE_CLASS_EMPTY,
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.cpp_generator import MockObjClass
@@ -143,6 +143,6 @@ async def event_fire_to_code(config, action_id, template_arg, args):
return var
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(event_ns.using)

View File

@@ -13,8 +13,8 @@ namespace event {
#define LOG_EVENT(prefix, type, obj) \
if ((obj) != nullptr) { \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
if (!(obj)->get_icon().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \
if (!(obj)->get_icon_ref().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon_ref().c_str()); \
} \
if (!(obj)->get_device_class().empty()) { \
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_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
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)
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(fan_ns.using)

View File

@@ -8,7 +8,7 @@ from esphome.const import (
CONF_TYPE,
CONF_VALUE,
)
from esphome.core import coroutine_with_priority
from esphome.core import CoroPriority, coroutine_with_priority
CODEOWNERS = ["@esphome/core"]
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
@coroutine_with_priority(-100.0)
@coroutine_with_priority(CoroPriority.LATE)
async def to_code(config):
type_ = cg.RawExpression(config[CONF_TYPE])
restore = config[CONF_RESTORE_VALUE]

View File

@@ -42,9 +42,10 @@ class HostPreferences : public ESPPreferences {
if (len > 255)
return false;
this->setup_();
if (this->data.count(key) == 0)
auto it = this->data.find(key);
if (it == this->data.end())
return false;
auto vec = this->data[key];
const auto &vec = it->second;
if (vec.size() != len)
return false;
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
import esphome.config_validation as cv
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
@@ -40,7 +40,7 @@ CONFIG_SCHEMA = cv.All(
)
@coroutine_with_priority(52.0)
@coroutine_with_priority(CoroPriority.COMMUNICATION)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await ota_to_code(var, config)

View File

@@ -18,7 +18,7 @@ from esphome.const import (
PLATFORM_RP2040,
PlatformFramework,
)
from esphome.core import CORE, coroutine_with_priority
from esphome.core import CORE, CoroPriority, coroutine_with_priority
import esphome.final_validate as fv
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):
cg.add_global(i2c_ns.using)
cg.add_define("USE_I2C")

View File

@@ -1,6 +1,6 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.core import coroutine_with_priority
from esphome.core import CoroPriority, coroutine_with_priority
CODEOWNERS = ["@esphome/core"]
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):
cg.add_library("bblanchon/ArduinoJson", "7.4.2")
cg.add_define("USE_JSON")

View File

@@ -37,7 +37,7 @@ from esphome.const import (
CONF_WEB_SERVER,
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.cpp_generator import MockObjClass
@@ -283,6 +283,6 @@ async def new_light(config, *args):
return output_var
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(light_ns.using)

View File

@@ -13,7 +13,7 @@ from esphome.const import (
CONF_TRIGGER_ID,
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.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)
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(lock_ns.using)

View File

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

View File

@@ -51,7 +51,7 @@ from esphome.const import (
PLATFORM_RTL87XX,
PlatformFramework,
)
from esphome.core import CORE, Lambda, coroutine_with_priority
from esphome.core import CORE, CoroPriority, Lambda, coroutine_with_priority
CODEOWNERS = ["@esphome/core"]
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):
baud_rate = config[CONF_BAUD_RATE]
level = config[CONF_LEVEL]

View File

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

View File

@@ -14,7 +14,7 @@ from esphome.const import (
)
from esphome.core import CORE
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
CODEOWNERS = ["@jesserockz"]
@@ -303,7 +303,7 @@ async def media_player_volume_set_action(config, action_id, template_arg, args):
return var
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(media_player_ns.using)
cg.add_define("USE_MEDIA_PLAYER")

View File

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

View File

@@ -57,7 +57,7 @@ from esphome.const import (
PLATFORM_ESP8266,
PlatformFramework,
)
from esphome.core import CORE, coroutine_with_priority
from esphome.core import CORE, CoroPriority, coroutine_with_priority
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):
var = cg.new_Pvariable(config[CONF_ID])
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
import esphome.config_validation as cv
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"]
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):
cg.add_define("USE_NETWORK")
if CORE.using_arduino and CORE.is_esp32:

View File

@@ -30,7 +30,7 @@ from esphome.const import (
PLATFORM_NRF52,
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.types import ConfigType
@@ -132,7 +132,7 @@ def _final_validate(config):
FINAL_VALIDATE_SCHEMA = _final_validate
@coroutine_with_priority(1000)
@coroutine_with_priority(CoroPriority.PLATFORM)
async def to_code(config: ConfigType) -> None:
"""Convert the configuration to code."""
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)
@coroutine_with_priority(90)
@coroutine_with_priority(CoroPriority.DIAGNOSTICS)
async def _dfu_to_code(dfu_config):
cg.add_define("USE_NRF52_DFU")
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_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.cpp_generator import MockObjClass
@@ -321,7 +321,7 @@ async def number_in_range_to_code(config, condition_id, template_arg, args):
return var
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
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());
if (!obj->get_icon().empty()) {
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon().c_str());
if (!obj->get_icon_ref().empty()) {
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon_ref().c_str());
}
if (!obj->traits.get_unit_of_measurement().empty()) {

View File

@@ -10,7 +10,7 @@ from esphome.const import (
CONF_TRIGGER_ID,
PlatformFramework,
)
from esphome.core import CORE, coroutine_with_priority
from esphome.core import CORE, CoroPriority, coroutine_with_priority
CODEOWNERS = ["@esphome/core"]
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):
cg.add_define("USE_OTA")

View File

@@ -18,7 +18,7 @@ from esphome.const import (
PLATFORM_RP2040,
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 .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):
cg.add(rp2040_ns.setup_preferences())

View File

@@ -10,7 +10,7 @@ from esphome.const import (
CONF_TRIGGER_ID,
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
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):
if not config[CONF_DISABLED]:
var = cg.new_Pvariable(config[CONF_ID])

View File

@@ -16,7 +16,7 @@ from esphome.const import (
CONF_TRIGGER_ID,
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.cpp_generator import MockObjClass
@@ -124,7 +124,7 @@ async def new_select(config, *args, options: list[str]):
return var
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(select_ns.using)

View File

@@ -12,8 +12,8 @@ namespace select {
#define LOG_SELECT(prefix, type, obj) \
if ((obj) != nullptr) { \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
if (!(obj)->get_icon().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \
if (!(obj)->get_icon_ref().empty()) { \
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,
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.cpp_generator import MockObjClass
from esphome.util import Registry
@@ -1142,6 +1142,6 @@ def _lstsq(a, 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):
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 Unit of Measurement: '%s'\n"
"%s Accuracy Decimals: %d",
prefix, type, obj->get_name().c_str(), prefix, state_class_to_string(obj->get_state_class()).c_str(),
prefix, obj->get_unit_of_measurement().c_str(), prefix, obj->get_accuracy_decimals());
prefix, type, obj->get_name().c_str(), prefix, state_class_to_string(obj->get_state_class()), prefix,
obj->get_unit_of_measurement().c_str(), prefix, obj->get_accuracy_decimals());
if (!obj->get_device_class().empty()) {
ESP_LOGCONFIG(tag, "%s Device Class: '%s'", prefix, obj->get_device_class().c_str());
}
if (!obj->get_icon().empty()) {
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon().c_str());
if (!obj->get_icon_ref().empty()) {
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon_ref().c_str());
}
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) {
case STATE_CLASS_MEASUREMENT:
return "measurement";

View File

@@ -33,7 +33,7 @@ enum StateClass : uint8_t {
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.
*

View File

@@ -4,7 +4,7 @@ from esphome.components import audio, audio_dac
import esphome.config_validation as cv
from esphome.const import CONF_DATA, CONF_ID, CONF_VOLUME
from esphome.core import CORE
from esphome.coroutine import coroutine_with_priority
from esphome.coroutine import CoroPriority, coroutine_with_priority
AUTO_LOAD = ["audio"]
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)
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(speaker_ns.using)
cg.add_define("USE_SPEAKER")

View File

@@ -35,7 +35,7 @@ from esphome.const import (
PLATFORM_RP2040,
PlatformFramework,
)
from esphome.core import CORE, coroutine_with_priority
from esphome.core import CORE, CoroPriority, coroutine_with_priority
import esphome.final_validate as fv
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):
cg.add_define("USE_SPI")
cg.add_global(spi_ns.using)

View File

@@ -2,7 +2,7 @@ from esphome import pins
import esphome.codegen as cg
import esphome.config_validation as cv
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")
StatusLED = status_led_ns.class_("StatusLED", cg.Component)
@@ -15,7 +15,7 @@ CONFIG_SCHEMA = cv.Schema(
).extend(cv.COMPONENT_SCHEMA)
@coroutine_with_priority(80.0)
@coroutine_with_priority(CoroPriority.STATUS)
async def to_code(config):
pin = await cg.gpio_pin_expression(config[CONF_PIN])
rhs = StatusLED.new(pin)

View File

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

View File

@@ -21,7 +21,7 @@ from esphome.const import (
DEVICE_CLASS_OUTLET,
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.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)
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
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));
// Add optional fields separately
if (!obj->get_icon().empty()) {
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon().c_str());
if (!obj->get_icon_ref().empty()) {
ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon_ref().c_str());
}
if (obj->assumed_state()) {
ESP_LOGCONFIG(tag, "%s Assumed State: YES", prefix);

View File

@@ -13,7 +13,7 @@ from esphome.const import (
CONF_VALUE,
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.cpp_generator import MockObjClass
@@ -149,7 +149,7 @@ async def new_text(
return var
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(text_ns.using)

View File

@@ -12,8 +12,8 @@ namespace text {
#define LOG_TEXT(prefix, type, obj) \
if ((obj) != nullptr) { \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
if (!(obj)->get_icon().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \
if (!(obj)->get_icon_ref().empty()) { \
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_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.cpp_generator import MockObjClass
from esphome.util import Registry
@@ -230,7 +230,7 @@ async def new_text_sensor(config, *args):
return var
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(text_sensor_ns.using)

View File

@@ -17,8 +17,8 @@ namespace text_sensor {
if (!(obj)->get_device_class().empty()) { \
ESP_LOGCONFIG(TAG, "%s Device Class: '%s'", prefix, (obj)->get_device_class().c_str()); \
} \
if (!(obj)->get_icon().empty()) { \
ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \
if (!(obj)->get_icon_ref().empty()) { \
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_TRIGGER_ID,
)
from esphome.core import CORE, coroutine_with_priority
from esphome.core import CORE, CoroPriority, coroutine_with_priority
_LOGGER = logging.getLogger(__name__)
@@ -340,7 +340,7 @@ async def register_time(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):
if CORE.using_zephyr:
zephyr_add_prj_conf("POSIX_CLOCK", True)

View File

@@ -13,7 +13,7 @@ from esphome.const import (
CONF_SWAP_XY,
CONF_TRANSFORM,
)
from esphome.core import coroutine_with_priority
from esphome.core import CoroPriority, coroutine_with_priority
CODEOWNERS = ["@jesserockz", "@nielsnl68"]
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):
cg.add_global(touchscreen_ns.using)
cg.add_define("USE_TOUCHSCREEN")

View File

@@ -14,7 +14,7 @@ from esphome.const import (
DEVICE_CLASS_FIRMWARE,
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.cpp_generator import MockObjClass
@@ -124,7 +124,7 @@ async def new_update(config):
return var
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(update_ns.using)

View File

@@ -21,7 +21,7 @@ from esphome.const import (
DEVICE_CLASS_GAS,
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.cpp_generator import MockObjClass
@@ -233,6 +233,6 @@ async def valve_control_to_code(config, action_id, template_arg, args):
return var
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config):
cg.add_global(valve_ns.using)

View File

@@ -31,7 +31,7 @@ from esphome.const import (
PLATFORM_LN882X,
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
from esphome.types import ConfigType
@@ -269,7 +269,7 @@ def add_resource_as_progmem(
cg.add_global(cg.RawExpression(size_t))
@coroutine_with_priority(40.0)
@coroutine_with_priority(CoroPriority.WEB)
async def to_code(config):
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
import esphome.config_validation as cv
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"]
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):
var = cg.new_Pvariable(config[CONF_ID])
await ota_to_code(var, config)

View File

@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
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"]
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):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)

View File

@@ -44,7 +44,7 @@ from esphome.const import (
CONF_USERNAME,
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
from . import wpa2_eap
@@ -370,7 +370,7 @@ def wifi_network(config, ap, static_ip):
return ap
@coroutine_with_priority(60.0)
@coroutine_with_priority(CoroPriority.COMMUNICATION)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_use_address(config[CONF_USE_ADDRESS]))

View File

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

View File

@@ -39,7 +39,7 @@ from esphome.const import (
PlatformFramework,
__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 (
copy_file_if_changed,
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():
# The Arduino framework defined these itself in the global
# 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))
@coroutine_with_priority(-1000.0)
@coroutine_with_priority(CoroPriority.FINAL)
async def add_includes(includes):
# Add includes at the very end, so that the included files can access global variables
for include in includes:
@@ -392,7 +392,7 @@ async def add_includes(includes):
include_file(path, basename)
@coroutine_with_priority(-1000.0)
@coroutine_with_priority(CoroPriority.FINAL)
async def _add_platformio_options(pio_options):
# Add includes at the very end, so that they override everything
for key, val in pio_options.items():
@@ -401,7 +401,7 @@ async def _add_platformio_options(pio_options):
cg.add_platformio_option(key, val)
@coroutine_with_priority(30.0)
@coroutine_with_priority(CoroPriority.AUTOMATION)
async def _add_automations(config):
for conf in config.get(CONF_ON_BOOT, []):
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"}
@coroutine_with_priority(-1000.0)
@coroutine_with_priority(CoroPriority.FINAL)
async def _add_platform_defines() -> None:
# Generate compile-time defines for platforms that have actual 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()}")
@coroutine_with_priority(100.0)
@coroutine_with_priority(CoroPriority.CORE)
async def to_code(config: ConfigType) -> None:
cg.add_global(cg.global_ns.namespace("esphome").using)
# 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
}
// 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
std::string EntityBase::get_object_id() const {
// 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.
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 {
static constexpr auto EMPTY_STRING = StringRef::from_lit("");
// 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;
}
// 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
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_; }

View File

@@ -126,6 +126,9 @@ class EntityBase {
virtual uint32_t hash_base() { return 0L; }
void calc_object_id_();
/// Check if the object_id is dynamic (changes with MAC suffix)
bool is_object_id_dynamic_() const;
StringRef name_;
const char *object_id_c_str_{nullptr};
#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;
}
uint32_t fnv1_hash(const std::string &str) {
uint32_t fnv1_hash(const char *str) {
uint32_t hash = 2166136261UL;
for (char c : str) {
if (str) {
while (*str) {
hash *= 16777619UL;
hash ^= c;
hash ^= *str++;
}
}
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);
/// 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.
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.
"""
from __future__ import annotations
from collections.abc import Awaitable, Callable, Generator, Iterator
import enum
import functools
import heapq
import inspect
@@ -53,6 +56,79 @@ from typing import Any
_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]]:
"""Decorator to apply to methods to convert them to ESPHome coroutines."""
if getattr(func, "_esphome_coroutine", False):
@@ -95,15 +171,16 @@ def coroutine(func: Callable[..., Any]) -> Callable[..., Awaitable[Any]]:
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.
: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):
coro = coroutine(func)
coro.priority = priority
coro.priority = float(priority)
return coro
return decorator
@@ -173,7 +250,7 @@ class _Task:
self.iterator = iterator
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)
@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"]