mirror of
https://github.com/esphome/esphome.git
synced 2025-11-16 06:45:48 +00:00
88 lines
2.8 KiB
Python
88 lines
2.8 KiB
Python
import logging
|
|
|
|
import esphome.codegen as cg
|
|
from esphome.components.esp32 import add_idf_component
|
|
from esphome.components.ota import BASE_OTA_SCHEMA, OTAComponent, ota_to_code
|
|
from esphome.config_helpers import merge_config
|
|
import esphome.config_validation as cv
|
|
from esphome.const import CONF_ID, CONF_OTA, CONF_PLATFORM
|
|
from esphome.core import CORE, coroutine_with_priority
|
|
from esphome.coroutine import CoroPriority
|
|
import esphome.final_validate as fv
|
|
from esphome.types import ConfigType
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
CODEOWNERS = ["@esphome/core"]
|
|
DEPENDENCIES = ["network", "web_server_base"]
|
|
|
|
CONF_WEB_SERVER = "web_server"
|
|
|
|
web_server_ns = cg.esphome_ns.namespace("web_server")
|
|
WebServerOTAComponent = web_server_ns.class_("WebServerOTAComponent", OTAComponent)
|
|
|
|
|
|
def _web_server_ota_final_validate(config: ConfigType) -> None:
|
|
"""Merge multiple web_server OTA instances into one.
|
|
|
|
Multiple web_server OTA instances register duplicate HTTP handlers for /update,
|
|
causing undefined behavior. Merge them into a single instance.
|
|
"""
|
|
full_conf = fv.full_config.get()
|
|
ota_confs = full_conf.get(CONF_OTA, [])
|
|
|
|
web_server_ota_configs: list[ConfigType] = []
|
|
other_ota_configs: list[ConfigType] = []
|
|
|
|
for ota_conf in ota_confs:
|
|
if ota_conf.get(CONF_PLATFORM) == CONF_WEB_SERVER:
|
|
web_server_ota_configs.append(ota_conf)
|
|
else:
|
|
other_ota_configs.append(ota_conf)
|
|
|
|
if len(web_server_ota_configs) <= 1:
|
|
return
|
|
|
|
# Merge all web_server OTA configs into the first one
|
|
merged = web_server_ota_configs[0]
|
|
for ota_conf in web_server_ota_configs[1:]:
|
|
# Validate that IDs are consistent if manually specified
|
|
if merged[CONF_ID].is_manual and ota_conf[CONF_ID].is_manual:
|
|
raise cv.Invalid(
|
|
f"Found multiple web_server OTA configurations but {CONF_ID} is inconsistent"
|
|
)
|
|
merged = merge_config(merged, ota_conf)
|
|
|
|
_LOGGER.warning(
|
|
"Found and merged %d web_server OTA configurations into one instance",
|
|
len(web_server_ota_configs),
|
|
)
|
|
|
|
# Replace OTA configs with merged web_server + other OTA platforms
|
|
other_ota_configs.append(merged)
|
|
full_conf[CONF_OTA] = other_ota_configs
|
|
fv.full_config.set(full_conf)
|
|
|
|
|
|
CONFIG_SCHEMA = (
|
|
cv.Schema(
|
|
{
|
|
cv.GenerateID(): cv.declare_id(WebServerOTAComponent),
|
|
}
|
|
)
|
|
.extend(BASE_OTA_SCHEMA)
|
|
.extend(cv.COMPONENT_SCHEMA)
|
|
)
|
|
|
|
FINAL_VALIDATE_SCHEMA = _web_server_ota_final_validate
|
|
|
|
|
|
@coroutine_with_priority(CoroPriority.WEB_SERVER_OTA)
|
|
async def to_code(config):
|
|
var = cg.new_Pvariable(config[CONF_ID])
|
|
await ota_to_code(var, config)
|
|
await cg.register_component(var, config)
|
|
cg.add_define("USE_WEBSERVER_OTA")
|
|
if CORE.is_esp32:
|
|
add_idf_component(name="zorxx/multipart-parser", ref="1.0.1")
|