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

This commit is contained in:
J. Nick Koston
2025-11-16 21:00:03 -06:00
10 changed files with 89 additions and 41 deletions

View File

@@ -4,8 +4,7 @@
#include "esphome/core/automation.h"
#include "cover.h"
namespace esphome {
namespace cover {
namespace esphome::cover {
template<typename... Ts> class OpenAction : public Action<Ts...> {
public:
@@ -131,5 +130,4 @@ class CoverClosedTrigger : public Trigger<> {
}
};
} // namespace cover
} // namespace esphome
} // namespace esphome::cover

View File

@@ -6,8 +6,7 @@
#include "esphome/core/log.h"
namespace esphome {
namespace cover {
namespace esphome::cover {
static const char *const TAG = "cover";
@@ -212,5 +211,4 @@ void CoverRestoreState::apply(Cover *cover) {
cover->publish_state();
}
} // namespace cover
} // namespace esphome
} // namespace esphome::cover

View File

@@ -7,8 +7,7 @@
#include "cover_traits.h"
namespace esphome {
namespace cover {
namespace esphome::cover {
const extern float COVER_OPEN;
const extern float COVER_CLOSED;
@@ -157,5 +156,4 @@ class Cover : public EntityBase, public EntityBase_DeviceClass {
ESPPreferenceObject rtc_;
};
} // namespace cover
} // namespace esphome
} // namespace esphome::cover

View File

@@ -1,7 +1,6 @@
#pragma once
namespace esphome {
namespace cover {
namespace esphome::cover {
class CoverTraits {
public:
@@ -26,5 +25,4 @@ class CoverTraits {
bool supports_stop_{false};
};
} // namespace cover
} // namespace esphome
} // namespace esphome::cover

View File

@@ -56,11 +56,19 @@ uint32_t ESP8266UartComponent::get_config() {
}
void ESP8266UartComponent::setup() {
if (this->rx_pin_) {
this->rx_pin_->setup();
}
if (this->tx_pin_ && this->rx_pin_ != this->tx_pin_) {
this->tx_pin_->setup();
auto setup_pin_if_needed = [](InternalGPIOPin *pin) {
if (!pin) {
return;
}
const auto mask = gpio::Flags::FLAG_OPEN_DRAIN | gpio::Flags::FLAG_PULLUP | gpio::Flags::FLAG_PULLDOWN;
if ((pin->get_flags() & mask) != gpio::Flags::FLAG_NONE) {
pin->setup();
}
};
setup_pin_if_needed(this->rx_pin_);
if (this->rx_pin_ != this->tx_pin_) {
setup_pin_if_needed(this->tx_pin_);
}
// Use Arduino HardwareSerial UARTs if all used pins match the ones

View File

@@ -133,11 +133,19 @@ void IDFUARTComponent::load_settings(bool dump_config) {
return;
}
if (this->rx_pin_) {
this->rx_pin_->setup();
}
if (this->tx_pin_ && this->rx_pin_ != this->tx_pin_) {
this->tx_pin_->setup();
auto setup_pin_if_needed = [](InternalGPIOPin *pin) {
if (!pin) {
return;
}
const auto mask = gpio::Flags::FLAG_OPEN_DRAIN | gpio::Flags::FLAG_PULLUP | gpio::Flags::FLAG_PULLDOWN;
if ((pin->get_flags() & mask) != gpio::Flags::FLAG_NONE) {
pin->setup();
}
};
setup_pin_if_needed(this->rx_pin_);
if (this->rx_pin_ != this->tx_pin_) {
setup_pin_if_needed(this->tx_pin_);
}
int8_t tx = this->tx_pin_ != nullptr ? this->tx_pin_->get_pin() : -1;

View File

@@ -53,7 +53,7 @@ void LibreTinyUARTComponent::setup() {
auto shouldFallbackToSoftwareSerial = [&]() -> bool {
auto hasFlags = [](InternalGPIOPin *pin, const gpio::Flags mask) -> bool {
return pin && pin->get_flags() & mask != gpio::Flags::FLAG_NONE;
return pin && (pin->get_flags() & mask) != gpio::Flags::FLAG_NONE;
};
if (hasFlags(this->tx_pin_, gpio::Flags::FLAG_OPEN_DRAIN | gpio::Flags::FLAG_PULLUP | gpio::Flags::FLAG_PULLDOWN) ||
hasFlags(this->rx_pin_, gpio::Flags::FLAG_OPEN_DRAIN | gpio::Flags::FLAG_PULLUP | gpio::Flags::FLAG_PULLDOWN)) {

View File

@@ -52,11 +52,19 @@ uint16_t RP2040UartComponent::get_config() {
}
void RP2040UartComponent::setup() {
if (this->rx_pin_) {
this->rx_pin_->setup();
}
if (this->tx_pin_ && this->rx_pin_ != this->tx_pin_) {
this->tx_pin_->setup();
auto setup_pin_if_needed = [](InternalGPIOPin *pin) {
if (!pin) {
return;
}
const auto mask = gpio::Flags::FLAG_OPEN_DRAIN | gpio::Flags::FLAG_PULLUP | gpio::Flags::FLAG_PULLDOWN;
if ((pin->get_flags() & mask) != gpio::Flags::FLAG_NONE) {
pin->setup();
}
};
setup_pin_if_needed(this->rx_pin_);
if (this->rx_pin_ != this->tx_pin_) {
setup_pin_if_needed(this->tx_pin_);
}
uint16_t config = get_config();

View File

@@ -5,7 +5,7 @@ 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.const import CONF_ID, CONF_OTA, CONF_PLATFORM, CONF_WEB_SERVER
from esphome.core import CORE, coroutine_with_priority
from esphome.coroutine import CoroPriority
import esphome.final_validate as fv
@@ -16,8 +16,6 @@ _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)
@@ -47,7 +45,11 @@ def _web_server_ota_final_validate(config: ConfigType) -> None:
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:
if (
merged[CONF_ID].is_manual
and ota_conf[CONF_ID].is_manual
and merged[CONF_ID] != ota_conf[CONF_ID]
):
raise cv.Invalid(
f"Found multiple web_server OTA configurations but {CONF_ID} is inconsistent"
)

View File

@@ -9,11 +9,8 @@ from typing import Any
import pytest
from esphome import config_validation as cv
from esphome.components.web_server.ota import (
CONF_WEB_SERVER,
_web_server_ota_final_validate,
)
from esphome.const import CONF_ID, CONF_OTA, CONF_PLATFORM
from esphome.components.web_server.ota import _web_server_ota_final_validate
from esphome.const import CONF_ID, CONF_OTA, CONF_PLATFORM, CONF_WEB_SERVER
from esphome.core import ID
import esphome.final_validate as fv
@@ -199,6 +196,39 @@ def test_web_server_ota_instance_merging(
fv.full_config.reset(token)
def test_web_server_ota_consistent_manual_ids(
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test that consistent manual IDs can be merged successfully."""
ota_configs = [
{
CONF_PLATFORM: CONF_WEB_SERVER,
CONF_ID: ID("ota_web", is_manual=True),
},
{
CONF_PLATFORM: CONF_WEB_SERVER,
CONF_ID: ID("ota_web", is_manual=True),
},
]
full_conf = {CONF_OTA: ota_configs}
token = fv.full_config.set(full_conf)
try:
with caplog.at_level(logging.WARNING):
_web_server_ota_final_validate({})
updated_conf = fv.full_config.get()
assert len(updated_conf[CONF_OTA]) == 1
assert updated_conf[CONF_OTA][0][CONF_ID].id == "ota_web"
assert any(
"Found and merged" in record.message and "web_server OTA" in record.message
for record in caplog.records
)
finally:
fv.full_config.reset(token)
def test_web_server_ota_inconsistent_manual_ids() -> None:
"""Test that inconsistent manual IDs raise an error."""
ota_configs = [