diff --git a/esphome/components/cover/automation.h b/esphome/components/cover/automation.h index 752e0398c1..c0345a7cc6 100644 --- a/esphome/components/cover/automation.h +++ b/esphome/components/cover/automation.h @@ -4,8 +4,7 @@ #include "esphome/core/automation.h" #include "cover.h" -namespace esphome { -namespace cover { +namespace esphome::cover { template class OpenAction : public Action { public: @@ -131,5 +130,4 @@ class CoverClosedTrigger : public Trigger<> { } }; -} // namespace cover -} // namespace esphome +} // namespace esphome::cover diff --git a/esphome/components/cover/cover.cpp b/esphome/components/cover/cover.cpp index 3062dba28a..8f735982f1 100644 --- a/esphome/components/cover/cover.cpp +++ b/esphome/components/cover/cover.cpp @@ -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 diff --git a/esphome/components/cover/cover.h b/esphome/components/cover/cover.h index d5db6cfb4f..6c69c05e71 100644 --- a/esphome/components/cover/cover.h +++ b/esphome/components/cover/cover.h @@ -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 diff --git a/esphome/components/cover/cover_traits.h b/esphome/components/cover/cover_traits.h index 79001c3b03..723516318b 100644 --- a/esphome/components/cover/cover_traits.h +++ b/esphome/components/cover/cover_traits.h @@ -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 diff --git a/esphome/components/number/automation.cpp b/esphome/components/number/automation.cpp index bfc59d0465..78ffc255fe 100644 --- a/esphome/components/number/automation.cpp +++ b/esphome/components/number/automation.cpp @@ -1,8 +1,7 @@ #include "automation.h" #include "esphome/core/log.h" -namespace esphome { -namespace number { +namespace esphome::number { static const char *const TAG = "number.automation"; @@ -52,5 +51,4 @@ void ValueRangeTrigger::on_state_(float state) { this->rtc_.save(&in_range); } -} // namespace number -} // namespace esphome +} // namespace esphome::number diff --git a/esphome/components/number/automation.h b/esphome/components/number/automation.h index 79eba883c4..a7cd04f083 100644 --- a/esphome/components/number/automation.h +++ b/esphome/components/number/automation.h @@ -4,8 +4,7 @@ #include "esphome/core/automation.h" #include "esphome/core/component.h" -namespace esphome { -namespace number { +namespace esphome::number { class NumberStateTrigger : public Trigger { public: @@ -91,5 +90,4 @@ template class NumberInRangeCondition : public Condition float max_{NAN}; }; -} // namespace number -} // namespace esphome +} // namespace esphome::number diff --git a/esphome/components/number/number.cpp b/esphome/components/number/number.cpp index f12e0e9e1e..992100ead0 100644 --- a/esphome/components/number/number.cpp +++ b/esphome/components/number/number.cpp @@ -3,8 +3,7 @@ #include "esphome/core/controller_registry.h" #include "esphome/core/log.h" -namespace esphome { -namespace number { +namespace esphome::number { static const char *const TAG = "number"; @@ -43,5 +42,4 @@ void Number::add_on_state_callback(std::function &&callback) { this->state_callback_.add(std::move(callback)); } -} // namespace number -} // namespace esphome +} // namespace esphome::number diff --git a/esphome/components/number/number.h b/esphome/components/number/number.h index da91d70d53..472e06ad61 100644 --- a/esphome/components/number/number.h +++ b/esphome/components/number/number.h @@ -6,8 +6,7 @@ #include "number_call.h" #include "number_traits.h" -namespace esphome { -namespace number { +namespace esphome::number { class Number; void log_number(const char *tag, const char *prefix, const char *type, Number *obj); @@ -53,5 +52,4 @@ class Number : public EntityBase { CallbackManager state_callback_; }; -} // namespace number -} // namespace esphome +} // namespace esphome::number diff --git a/esphome/components/number/number_call.cpp b/esphome/components/number/number_call.cpp index 669dd65184..27a857c112 100644 --- a/esphome/components/number/number_call.cpp +++ b/esphome/components/number/number_call.cpp @@ -2,8 +2,7 @@ #include "number.h" #include "esphome/core/log.h" -namespace esphome { -namespace number { +namespace esphome::number { static const char *const TAG = "number"; @@ -125,5 +124,4 @@ void NumberCall::perform() { this->parent_->control(target_value); } -} // namespace number -} // namespace esphome +} // namespace esphome::number diff --git a/esphome/components/number/number_call.h b/esphome/components/number/number_call.h index 807207f0ec..0f6889dcb6 100644 --- a/esphome/components/number/number_call.h +++ b/esphome/components/number/number_call.h @@ -4,8 +4,7 @@ #include "esphome/core/log.h" #include "number_traits.h" -namespace esphome { -namespace number { +namespace esphome::number { class Number; @@ -44,5 +43,4 @@ class NumberCall { bool cycle_; }; -} // namespace number -} // namespace esphome +} // namespace esphome::number diff --git a/esphome/components/number/number_traits.cpp b/esphome/components/number/number_traits.cpp index 89035661f5..1e4239ceca 100644 --- a/esphome/components/number/number_traits.cpp +++ b/esphome/components/number/number_traits.cpp @@ -1,10 +1,8 @@ #include "esphome/core/log.h" #include "number_traits.h" -namespace esphome { -namespace number { +namespace esphome::number { static const char *const TAG = "number"; -} // namespace number -} // namespace esphome +} // namespace esphome::number diff --git a/esphome/components/number/number_traits.h b/esphome/components/number/number_traits.h index fa68c2390a..5ccbb9ba48 100644 --- a/esphome/components/number/number_traits.h +++ b/esphome/components/number/number_traits.h @@ -3,8 +3,7 @@ #include "esphome/core/entity_base.h" #include "esphome/core/helpers.h" -namespace esphome { -namespace number { +namespace esphome::number { enum NumberMode : uint8_t { NUMBER_MODE_AUTO = 0, @@ -35,5 +34,4 @@ class NumberTraits : public EntityBase_DeviceClass, public EntityBase_UnitOfMeas NumberMode mode_{NUMBER_MODE_AUTO}; }; -} // namespace number -} // namespace esphome +} // namespace esphome::number diff --git a/esphome/components/uart/uart_component_esp8266.cpp b/esphome/components/uart/uart_component_esp8266.cpp index 7a453dbb50..c84a877ef4 100644 --- a/esphome/components/uart/uart_component_esp8266.cpp +++ b/esphome/components/uart/uart_component_esp8266.cpp @@ -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 diff --git a/esphome/components/uart/uart_component_esp_idf.cpp b/esphome/components/uart/uart_component_esp_idf.cpp index 70a13c9e37..61ca8c1c0c 100644 --- a/esphome/components/uart/uart_component_esp_idf.cpp +++ b/esphome/components/uart/uart_component_esp_idf.cpp @@ -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; diff --git a/esphome/components/uart/uart_component_libretiny.cpp b/esphome/components/uart/uart_component_libretiny.cpp index 8d1d28fce4..1e408b169b 100644 --- a/esphome/components/uart/uart_component_libretiny.cpp +++ b/esphome/components/uart/uart_component_libretiny.cpp @@ -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)) { diff --git a/esphome/components/uart/uart_component_rp2040.cpp b/esphome/components/uart/uart_component_rp2040.cpp index c78691653d..cd3905b5c1 100644 --- a/esphome/components/uart/uart_component_rp2040.cpp +++ b/esphome/components/uart/uart_component_rp2040.cpp @@ -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(); diff --git a/esphome/components/web_server/ota/__init__.py b/esphome/components/web_server/ota/__init__.py index 144d9e76cd..260e6aea6d 100644 --- a/esphome/components/web_server/ota/__init__.py +++ b/esphome/components/web_server/ota/__init__.py @@ -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" ) diff --git a/tests/component_tests/ota/test_web_server_ota.py b/tests/component_tests/ota/test_web_server_ota.py index d4630ff203..794eaac9be 100644 --- a/tests/component_tests/ota/test_web_server_ota.py +++ b/tests/component_tests/ota/test_web_server_ota.py @@ -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 = [