mirror of
https://github.com/esphome/esphome.git
synced 2025-09-21 20:52:20 +01:00
2
Doxyfile
2
Doxyfile
@@ -48,7 +48,7 @@ PROJECT_NAME = ESPHome
|
|||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
# control system is used.
|
# control system is used.
|
||||||
|
|
||||||
PROJECT_NUMBER = 2025.9.0
|
PROJECT_NUMBER = 2025.9.1
|
||||||
|
|
||||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||||
# for a project that appears at the top of each page and should give viewer a
|
# for a project that appears at the top of each page and should give viewer a
|
||||||
|
@@ -212,7 +212,7 @@ def has_mqtt_logging() -> bool:
|
|||||||
if CONF_TOPIC not in log_topic:
|
if CONF_TOPIC not in log_topic:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return log_topic[CONF_LEVEL] != "NONE"
|
return log_topic.get(CONF_LEVEL, None) != "NONE"
|
||||||
|
|
||||||
|
|
||||||
def has_mqtt() -> bool:
|
def has_mqtt() -> bool:
|
||||||
|
@@ -10,7 +10,8 @@ from esphome.const import (
|
|||||||
PLATFORM_LN882X,
|
PLATFORM_LN882X,
|
||||||
PLATFORM_RTL87XX,
|
PLATFORM_RTL87XX,
|
||||||
)
|
)
|
||||||
from esphome.core import CORE, CoroPriority, coroutine_with_priority
|
from esphome.core import CORE, coroutine_with_priority
|
||||||
|
from esphome.coroutine import CoroPriority
|
||||||
|
|
||||||
AUTO_LOAD = ["web_server_base", "ota.web_server"]
|
AUTO_LOAD = ["web_server_base", "ota.web_server"]
|
||||||
DEPENDENCIES = ["wifi"]
|
DEPENDENCIES = ["wifi"]
|
||||||
@@ -40,7 +41,7 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@coroutine_with_priority(CoroPriority.COMMUNICATION)
|
@coroutine_with_priority(CoroPriority.CAPTIVE_PORTAL)
|
||||||
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])
|
||||||
|
|
||||||
|
@@ -16,7 +16,8 @@ from esphome.const import (
|
|||||||
CONF_SAFE_MODE,
|
CONF_SAFE_MODE,
|
||||||
CONF_VERSION,
|
CONF_VERSION,
|
||||||
)
|
)
|
||||||
from esphome.core import CoroPriority, coroutine_with_priority
|
from esphome.core import coroutine_with_priority
|
||||||
|
from esphome.coroutine import CoroPriority
|
||||||
import esphome.final_validate as fv
|
import esphome.final_validate as fv
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@@ -121,7 +122,7 @@ CONFIG_SCHEMA = (
|
|||||||
FINAL_VALIDATE_SCHEMA = ota_esphome_final_validate
|
FINAL_VALIDATE_SCHEMA = ota_esphome_final_validate
|
||||||
|
|
||||||
|
|
||||||
@coroutine_with_priority(CoroPriority.COMMUNICATION)
|
@coroutine_with_priority(CoroPriority.OTA_UPDATES)
|
||||||
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]))
|
||||||
|
@@ -6,6 +6,7 @@ namespace gpio {
|
|||||||
|
|
||||||
static const char *const TAG = "gpio.binary_sensor";
|
static const char *const TAG = "gpio.binary_sensor";
|
||||||
|
|
||||||
|
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
|
||||||
static const LogString *interrupt_type_to_string(gpio::InterruptType type) {
|
static const LogString *interrupt_type_to_string(gpio::InterruptType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case gpio::INTERRUPT_RISING_EDGE:
|
case gpio::INTERRUPT_RISING_EDGE:
|
||||||
@@ -22,6 +23,7 @@ static const LogString *interrupt_type_to_string(gpio::InterruptType type) {
|
|||||||
static const LogString *gpio_mode_to_string(bool use_interrupt) {
|
static const LogString *gpio_mode_to_string(bool use_interrupt) {
|
||||||
return use_interrupt ? LOG_STR("interrupt") : LOG_STR("polling");
|
return use_interrupt ? LOG_STR("interrupt") : LOG_STR("polling");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void IRAM_ATTR GPIOBinarySensorStore::gpio_intr(GPIOBinarySensorStore *arg) {
|
void IRAM_ATTR GPIOBinarySensorStore::gpio_intr(GPIOBinarySensorStore *arg) {
|
||||||
bool new_state = arg->isr_pin_.digital_read();
|
bool new_state = arg->isr_pin_.digital_read();
|
||||||
|
@@ -3,7 +3,8 @@ 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 CoroPriority, coroutine_with_priority
|
from esphome.core import coroutine_with_priority
|
||||||
|
from esphome.coroutine import CoroPriority
|
||||||
|
|
||||||
from .. import CONF_HTTP_REQUEST_ID, HttpRequestComponent, http_request_ns
|
from .. import CONF_HTTP_REQUEST_ID, HttpRequestComponent, http_request_ns
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@coroutine_with_priority(CoroPriority.COMMUNICATION)
|
@coroutine_with_priority(CoroPriority.OTA_UPDATES)
|
||||||
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)
|
||||||
|
@@ -11,7 +11,8 @@ from esphome.const import (
|
|||||||
CONF_SERVICES,
|
CONF_SERVICES,
|
||||||
PlatformFramework,
|
PlatformFramework,
|
||||||
)
|
)
|
||||||
from esphome.core import CORE, CoroPriority, coroutine_with_priority
|
from esphome.core import CORE, coroutine_with_priority
|
||||||
|
from esphome.coroutine import CoroPriority
|
||||||
|
|
||||||
CODEOWNERS = ["@esphome/core"]
|
CODEOWNERS = ["@esphome/core"]
|
||||||
DEPENDENCIES = ["network"]
|
DEPENDENCIES = ["network"]
|
||||||
@@ -72,7 +73,7 @@ def mdns_service(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@coroutine_with_priority(CoroPriority.COMMUNICATION)
|
@coroutine_with_priority(CoroPriority.NETWORK_SERVICES)
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
if config[CONF_DISABLED] is True:
|
if config[CONF_DISABLED] is True:
|
||||||
return
|
return
|
||||||
|
@@ -10,7 +10,8 @@ from esphome.const import (
|
|||||||
CONF_TRIGGER_ID,
|
CONF_TRIGGER_ID,
|
||||||
PlatformFramework,
|
PlatformFramework,
|
||||||
)
|
)
|
||||||
from esphome.core import CORE, CoroPriority, coroutine_with_priority
|
from esphome.core import CORE, coroutine_with_priority
|
||||||
|
from esphome.coroutine import CoroPriority
|
||||||
|
|
||||||
CODEOWNERS = ["@esphome/core"]
|
CODEOWNERS = ["@esphome/core"]
|
||||||
AUTO_LOAD = ["md5", "safe_mode"]
|
AUTO_LOAD = ["md5", "safe_mode"]
|
||||||
@@ -82,7 +83,7 @@ BASE_OTA_SCHEMA = cv.Schema(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@coroutine_with_priority(CoroPriority.COMMUNICATION)
|
@coroutine_with_priority(CoroPriority.OTA_UPDATES)
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
cg.add_define("USE_OTA")
|
cg.add_define("USE_OTA")
|
||||||
|
|
||||||
|
@@ -121,15 +121,11 @@ def transport_schema(cls):
|
|||||||
return TRANSPORT_SCHEMA.extend({cv.GenerateID(): cv.declare_id(cls)})
|
return TRANSPORT_SCHEMA.extend({cv.GenerateID(): cv.declare_id(cls)})
|
||||||
|
|
||||||
|
|
||||||
# Build a list of sensors for this platform
|
|
||||||
CORE.data[DOMAIN] = {CONF_SENSORS: []}
|
|
||||||
|
|
||||||
|
|
||||||
def get_sensors(transport_id):
|
def get_sensors(transport_id):
|
||||||
"""Return the list of sensors for this platform."""
|
"""Return the list of sensors for this platform."""
|
||||||
return (
|
return (
|
||||||
sensor
|
sensor
|
||||||
for sensor in CORE.data[DOMAIN][CONF_SENSORS]
|
for sensor in CORE.data.setdefault(DOMAIN, {}).setdefault(CONF_SENSORS, [])
|
||||||
if sensor[CONF_TRANSPORT_ID] == transport_id
|
if sensor[CONF_TRANSPORT_ID] == transport_id
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -137,7 +133,8 @@ def get_sensors(transport_id):
|
|||||||
def validate_packet_transport_sensor(config):
|
def validate_packet_transport_sensor(config):
|
||||||
if CONF_NAME in config and CONF_INTERNAL not in config:
|
if CONF_NAME in config and CONF_INTERNAL not in config:
|
||||||
raise cv.Invalid("Must provide internal: config when using name:")
|
raise cv.Invalid("Must provide internal: config when using name:")
|
||||||
CORE.data[DOMAIN][CONF_SENSORS].append(config)
|
conf_sensors = CORE.data.setdefault(DOMAIN, {}).setdefault(CONF_SENSORS, [])
|
||||||
|
conf_sensors.append(config)
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
@@ -3,7 +3,8 @@ 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, CoroPriority, coroutine_with_priority
|
from esphome.core import CORE, coroutine_with_priority
|
||||||
|
from esphome.coroutine import CoroPriority
|
||||||
|
|
||||||
CODEOWNERS = ["@esphome/core"]
|
CODEOWNERS = ["@esphome/core"]
|
||||||
DEPENDENCIES = ["network", "web_server_base"]
|
DEPENDENCIES = ["network", "web_server_base"]
|
||||||
@@ -22,7 +23,7 @@ CONFIG_SCHEMA = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@coroutine_with_priority(CoroPriority.COMMUNICATION)
|
@coroutine_with_priority(CoroPriority.WEB_SERVER_OTA)
|
||||||
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)
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
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, CoroPriority, coroutine_with_priority
|
from esphome.core import CORE, coroutine_with_priority
|
||||||
|
from esphome.coroutine import CoroPriority
|
||||||
|
|
||||||
CODEOWNERS = ["@esphome/core"]
|
CODEOWNERS = ["@esphome/core"]
|
||||||
DEPENDENCIES = ["network"]
|
DEPENDENCIES = ["network"]
|
||||||
@@ -26,7 +27,7 @@ CONFIG_SCHEMA = cv.Schema(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@coroutine_with_priority(CoroPriority.COMMUNICATION)
|
@coroutine_with_priority(CoroPriority.WEB_SERVER_BASE)
|
||||||
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)
|
||||||
|
@@ -4,7 +4,7 @@ from enum import Enum
|
|||||||
|
|
||||||
from esphome.enum import StrEnum
|
from esphome.enum import StrEnum
|
||||||
|
|
||||||
__version__ = "2025.9.0"
|
__version__ = "2025.9.1"
|
||||||
|
|
||||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||||
VALID_SUBSTITUTIONS_CHARACTERS = (
|
VALID_SUBSTITUTIONS_CHARACTERS = (
|
||||||
|
@@ -90,11 +90,30 @@ class CoroPriority(enum.IntEnum):
|
|||||||
# Examples: status_led (80)
|
# Examples: status_led (80)
|
||||||
STATUS = 80
|
STATUS = 80
|
||||||
|
|
||||||
|
# Web server infrastructure
|
||||||
|
# Examples: web_server_base (65)
|
||||||
|
WEB_SERVER_BASE = 65
|
||||||
|
|
||||||
|
# Network portal services
|
||||||
|
# Examples: captive_portal (64)
|
||||||
|
CAPTIVE_PORTAL = 64
|
||||||
|
|
||||||
# Communication protocols and services
|
# Communication protocols and services
|
||||||
# Examples: web_server_base (65), captive_portal (64), wifi (60), ethernet (60),
|
# Examples: wifi (60), ethernet (60)
|
||||||
# mdns (55), ota_updates (54), web_server_ota (52)
|
|
||||||
COMMUNICATION = 60
|
COMMUNICATION = 60
|
||||||
|
|
||||||
|
# Network discovery and management services
|
||||||
|
# Examples: mdns (55)
|
||||||
|
NETWORK_SERVICES = 55
|
||||||
|
|
||||||
|
# OTA update services
|
||||||
|
# Examples: ota_updates (54)
|
||||||
|
OTA_UPDATES = 54
|
||||||
|
|
||||||
|
# Web-based OTA services
|
||||||
|
# Examples: web_server_ota (52)
|
||||||
|
WEB_SERVER_OTA = 52
|
||||||
|
|
||||||
# Application-level services
|
# Application-level services
|
||||||
# Examples: safe_mode (50)
|
# Examples: safe_mode (50)
|
||||||
APPLICATION = 50
|
APPLICATION = 50
|
||||||
|
42
tests/components/mdns/test-comprehensive.esp8266-ard.yaml
Normal file
42
tests/components/mdns/test-comprehensive.esp8266-ard.yaml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# Comprehensive ESP8266 test for mdns with multiple network components
|
||||||
|
# Tests the complete priority chain:
|
||||||
|
# wifi (60) -> mdns (55) -> ota (54) -> web_server_ota (52)
|
||||||
|
|
||||||
|
esphome:
|
||||||
|
name: mdns-comprehensive-test
|
||||||
|
|
||||||
|
esp8266:
|
||||||
|
board: esp01_1m
|
||||||
|
|
||||||
|
logger:
|
||||||
|
level: DEBUG
|
||||||
|
|
||||||
|
wifi:
|
||||||
|
ssid: MySSID
|
||||||
|
password: password1
|
||||||
|
|
||||||
|
# web_server_base should run at priority 65 (before wifi)
|
||||||
|
web_server:
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
# mdns should run at priority 55 (after wifi at 60)
|
||||||
|
mdns:
|
||||||
|
services:
|
||||||
|
- service: _http
|
||||||
|
protocol: _tcp
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
# OTA should run at priority 54 (after mdns)
|
||||||
|
ota:
|
||||||
|
- platform: esphome
|
||||||
|
password: "otapassword"
|
||||||
|
|
||||||
|
# Test status LED at priority 80
|
||||||
|
status_led:
|
||||||
|
pin:
|
||||||
|
number: GPIO2
|
||||||
|
inverted: true
|
||||||
|
|
||||||
|
# Include API at priority 40
|
||||||
|
api:
|
||||||
|
password: "apipassword"
|
@@ -13,7 +13,12 @@ def test_coro_priority_enum_values() -> None:
|
|||||||
assert CoroPriority.CORE == 100
|
assert CoroPriority.CORE == 100
|
||||||
assert CoroPriority.DIAGNOSTICS == 90
|
assert CoroPriority.DIAGNOSTICS == 90
|
||||||
assert CoroPriority.STATUS == 80
|
assert CoroPriority.STATUS == 80
|
||||||
|
assert CoroPriority.WEB_SERVER_BASE == 65
|
||||||
|
assert CoroPriority.CAPTIVE_PORTAL == 64
|
||||||
assert CoroPriority.COMMUNICATION == 60
|
assert CoroPriority.COMMUNICATION == 60
|
||||||
|
assert CoroPriority.NETWORK_SERVICES == 55
|
||||||
|
assert CoroPriority.OTA_UPDATES == 54
|
||||||
|
assert CoroPriority.WEB_SERVER_OTA == 52
|
||||||
assert CoroPriority.APPLICATION == 50
|
assert CoroPriority.APPLICATION == 50
|
||||||
assert CoroPriority.WEB == 40
|
assert CoroPriority.WEB == 40
|
||||||
assert CoroPriority.AUTOMATION == 30
|
assert CoroPriority.AUTOMATION == 30
|
||||||
@@ -70,7 +75,12 @@ def test_float_and_enum_are_interchangeable() -> None:
|
|||||||
(CoroPriority.CORE, 100.0),
|
(CoroPriority.CORE, 100.0),
|
||||||
(CoroPriority.DIAGNOSTICS, 90.0),
|
(CoroPriority.DIAGNOSTICS, 90.0),
|
||||||
(CoroPriority.STATUS, 80.0),
|
(CoroPriority.STATUS, 80.0),
|
||||||
|
(CoroPriority.WEB_SERVER_BASE, 65.0),
|
||||||
|
(CoroPriority.CAPTIVE_PORTAL, 64.0),
|
||||||
(CoroPriority.COMMUNICATION, 60.0),
|
(CoroPriority.COMMUNICATION, 60.0),
|
||||||
|
(CoroPriority.NETWORK_SERVICES, 55.0),
|
||||||
|
(CoroPriority.OTA_UPDATES, 54.0),
|
||||||
|
(CoroPriority.WEB_SERVER_OTA, 52.0),
|
||||||
(CoroPriority.APPLICATION, 50.0),
|
(CoroPriority.APPLICATION, 50.0),
|
||||||
(CoroPriority.WEB, 40.0),
|
(CoroPriority.WEB, 40.0),
|
||||||
(CoroPriority.AUTOMATION, 30.0),
|
(CoroPriority.AUTOMATION, 30.0),
|
||||||
@@ -164,8 +174,13 @@ def test_enum_priority_comparison() -> None:
|
|||||||
assert CoroPriority.NETWORK_TRANSPORT > CoroPriority.CORE
|
assert CoroPriority.NETWORK_TRANSPORT > CoroPriority.CORE
|
||||||
assert CoroPriority.CORE > CoroPriority.DIAGNOSTICS
|
assert CoroPriority.CORE > CoroPriority.DIAGNOSTICS
|
||||||
assert CoroPriority.DIAGNOSTICS > CoroPriority.STATUS
|
assert CoroPriority.DIAGNOSTICS > CoroPriority.STATUS
|
||||||
assert CoroPriority.STATUS > CoroPriority.COMMUNICATION
|
assert CoroPriority.STATUS > CoroPriority.WEB_SERVER_BASE
|
||||||
assert CoroPriority.COMMUNICATION > CoroPriority.APPLICATION
|
assert CoroPriority.WEB_SERVER_BASE > CoroPriority.CAPTIVE_PORTAL
|
||||||
|
assert CoroPriority.CAPTIVE_PORTAL > CoroPriority.COMMUNICATION
|
||||||
|
assert CoroPriority.COMMUNICATION > CoroPriority.NETWORK_SERVICES
|
||||||
|
assert CoroPriority.NETWORK_SERVICES > CoroPriority.OTA_UPDATES
|
||||||
|
assert CoroPriority.OTA_UPDATES > CoroPriority.WEB_SERVER_OTA
|
||||||
|
assert CoroPriority.WEB_SERVER_OTA > CoroPriority.APPLICATION
|
||||||
assert CoroPriority.APPLICATION > CoroPriority.WEB
|
assert CoroPriority.APPLICATION > CoroPriority.WEB
|
||||||
assert CoroPriority.WEB > CoroPriority.AUTOMATION
|
assert CoroPriority.WEB > CoroPriority.AUTOMATION
|
||||||
assert CoroPriority.AUTOMATION > CoroPriority.BUS
|
assert CoroPriority.AUTOMATION > CoroPriority.BUS
|
||||||
|
@@ -1226,6 +1226,18 @@ def test_has_mqtt_logging_no_log_topic() -> None:
|
|||||||
setup_core(config={})
|
setup_core(config={})
|
||||||
assert has_mqtt_logging() is False
|
assert has_mqtt_logging() is False
|
||||||
|
|
||||||
|
# Setup MQTT config with CONF_LOG_TOPIC but no CONF_LEVEL (regression test for #10771)
|
||||||
|
# This simulates the default configuration created by validate_config in the MQTT component
|
||||||
|
setup_core(
|
||||||
|
config={
|
||||||
|
CONF_MQTT: {
|
||||||
|
CONF_BROKER: "mqtt.local",
|
||||||
|
CONF_LOG_TOPIC: {CONF_TOPIC: "esphome/debug"},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
assert has_mqtt_logging() is True
|
||||||
|
|
||||||
|
|
||||||
def test_has_mqtt() -> None:
|
def test_has_mqtt() -> None:
|
||||||
"""Test has_mqtt function."""
|
"""Test has_mqtt function."""
|
||||||
|
Reference in New Issue
Block a user