From e034662dc6cf1f82fc19bb15d5a9d9ef109da6f2 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 17 Oct 2026 15:09:32 -1000 Subject: [PATCH] [uart_tcp] Expose the connection entities as platforms (#21008) --- esphome/components/uart_tcp/__init__.py | 23 ++------------ esphome/components/uart_tcp/binary_sensor.py | 25 +++++++++++++++ esphome/components/uart_tcp/sensor.py | 31 +++++++++++++++++++ esphome/components/uart_tcp/uart_tcp.cpp | 6 ++++ esphome/components/uart_tcp/uart_tcp.h | 7 +++++ tests/components/uart_tcp/benchmark.yaml | 5 +-- tests/components/uart_tcp/common.yaml | 8 +++++ .../uart_tcp/test-client.esp32-idf.yaml | 8 +++++ tests/components/uart_tcp/test.host.yaml | 8 +++++ .../integration/fixtures/uart_tcp_bridge.yaml | 8 +++-- 10 files changed, 105 insertions(+), 24 deletions(-) create mode 100644 esphome/components/uart_tcp/binary_sensor.py create mode 100644 esphome/components/uart_tcp/sensor.py diff --git a/esphome/components/uart_tcp/__init__.py b/esphome/components/uart_tcp/__init__.py index 9d62d48d7c2..c7eba4a26a5 100644 --- a/esphome/components/uart_tcp/__init__.py +++ b/esphome/components/uart_tcp/__init__.py @@ -1,8 +1,7 @@ import esphome.codegen as cg -from esphome.components import binary_sensor, sensor, socket, uart +from esphome.components import socket, uart from esphome.components.const import ( CONF_ALLOWED_IPS, - CONF_CONNECTED, CONF_HOST, CONF_RECONNECT_INTERVAL, CONF_ROLE, @@ -15,9 +14,6 @@ from esphome.const import ( CONF_ID, CONF_PORT, CONF_UART_ID, - DEVICE_CLASS_CONNECTIVITY, - ENTITY_CATEGORY_DIAGNOSTIC, - STATE_CLASS_TOTAL_INCREASING, ) from esphome.core import CORE import esphome.final_validate as fv @@ -26,10 +22,10 @@ from esphome.types import ConfigType CODEOWNERS = ["@Bascht74"] DOMAIN = "uart_tcp" DEPENDENCIES = ["network", "uart"] -AUTO_LOAD = ["binary_sensor", "sensor", "socket"] +AUTO_LOAD = ["socket"] MULTI_CONF = True -CONF_DISCONNECTS = "disconnects" +CONF_UART_TCP_ID = "uart_tcp_id" uart_tcp_ns = cg.esphome_ns.namespace("uart_tcp") UartTcp = uart_tcp_ns.class_("UartTcp", cg.Component, uart.UARTDevice) @@ -43,15 +39,6 @@ BASE_SCHEMA = cv.Schema( cv.Optional( CONF_RECONNECT_INTERVAL, default="5s" ): cv.positive_time_period_milliseconds, - cv.Optional(CONF_CONNECTED): binary_sensor.binary_sensor_schema( - device_class=DEVICE_CLASS_CONNECTIVITY, - entity_category=ENTITY_CATEGORY_DIAGNOSTIC, - ), - cv.Optional(CONF_DISCONNECTS): sensor.sensor_schema( - accuracy_decimals=0, - state_class=STATE_CLASS_TOTAL_INCREASING, - entity_category=ENTITY_CATEGORY_DIAGNOSTIC, - ), } ).extend(cv.COMPONENT_SCHEMA) @@ -144,7 +131,3 @@ async def to_code(config: ConfigType) -> None: cg.add(var.set_reconnect_interval(config[CONF_RECONNECT_INTERVAL])) if (host := config.get(CONF_HOST)) is not None: cg.add(var.set_host(host)) - binary_sensors = binary_sensor.sub_binary_sensors(config) - await binary_sensors(CONF_CONNECTED, var.set_connected_sensor) - sensors = sensor.sub_sensors(config) - await sensors(CONF_DISCONNECTS, var.set_disconnects_sensor) diff --git a/esphome/components/uart_tcp/binary_sensor.py b/esphome/components/uart_tcp/binary_sensor.py new file mode 100644 index 00000000000..c8d19319337 --- /dev/null +++ b/esphome/components/uart_tcp/binary_sensor.py @@ -0,0 +1,25 @@ +import esphome.codegen as cg +from esphome.components import binary_sensor +from esphome.components.const import CONF_CONNECTED +import esphome.config_validation as cv +from esphome.const import CONF_ID, DEVICE_CLASS_CONNECTIVITY, ENTITY_CATEGORY_DIAGNOSTIC +from esphome.types import ConfigType + +from . import CONF_UART_TCP_ID, UartTcp + +DEPENDENCIES = ["uart_tcp"] + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_ID): cv.declare_id(cg.EntityBase), + cv.GenerateID(CONF_UART_TCP_ID): cv.use_id(UartTcp), + cv.Optional(CONF_CONNECTED): binary_sensor.binary_sensor_schema( + device_class=DEVICE_CLASS_CONNECTIVITY, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), +} + + +async def to_code(config: ConfigType) -> None: + hub = await cg.get_variable(config[CONF_UART_TCP_ID]) + binary_sensors = binary_sensor.sub_binary_sensors(config) + await binary_sensors(CONF_CONNECTED, hub.set_connected_sensor) diff --git a/esphome/components/uart_tcp/sensor.py b/esphome/components/uart_tcp/sensor.py new file mode 100644 index 00000000000..ad44b56ad09 --- /dev/null +++ b/esphome/components/uart_tcp/sensor.py @@ -0,0 +1,31 @@ +import esphome.codegen as cg +from esphome.components import sensor +import esphome.config_validation as cv +from esphome.const import ( + CONF_ID, + ENTITY_CATEGORY_DIAGNOSTIC, + STATE_CLASS_TOTAL_INCREASING, +) +from esphome.types import ConfigType + +from . import CONF_UART_TCP_ID, UartTcp + +DEPENDENCIES = ["uart_tcp"] + +CONF_DISCONNECTS = "disconnects" + +CONFIG_SCHEMA = { + cv.GenerateID(CONF_ID): cv.declare_id(cg.EntityBase), + cv.GenerateID(CONF_UART_TCP_ID): cv.use_id(UartTcp), + cv.Optional(CONF_DISCONNECTS): sensor.sensor_schema( + accuracy_decimals=0, + state_class=STATE_CLASS_TOTAL_INCREASING, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), +} + + +async def to_code(config: ConfigType) -> None: + hub = await cg.get_variable(config[CONF_UART_TCP_ID]) + sensors = sensor.sub_sensors(config) + await sensors(CONF_DISCONNECTS, hub.set_disconnects_sensor) diff --git a/esphome/components/uart_tcp/uart_tcp.cpp b/esphome/components/uart_tcp/uart_tcp.cpp index d634ac579f2..ca6c2204bdd 100644 --- a/esphome/components/uart_tcp/uart_tcp.cpp +++ b/esphome/components/uart_tcp/uart_tcp.cpp @@ -16,9 +16,11 @@ void UartTcp::setup() { #ifdef USE_SOCKET_TCP_LISTENER this->listener_.begin(TAG); #endif +#ifdef USE_BINARY_SENSOR if (this->connected_sensor_ != nullptr) { this->connected_sensor_->publish_state(false); } +#endif #ifdef USE_SENSOR if (this->disconnects_sensor_ != nullptr) { this->disconnects_sensor_->publish_state(0); @@ -37,7 +39,9 @@ void UartTcp::dump_config() { #ifdef USE_SOCKET_TCP_LISTENER this->listener_.dump_config(); #endif +#ifdef USE_BINARY_SENSOR LOG_BINARY_SENSOR(" ", "Connected", this->connected_sensor_); +#endif #ifdef USE_SENSOR LOG_SENSOR(" ", "Disconnects", this->disconnects_sensor_); #endif @@ -57,9 +61,11 @@ void UartTcp::sync_link_() { // The driver kept whatever arrived while the link was down. this->discard_uart_(); } +#ifdef USE_BINARY_SENSOR if (this->connected_sensor_ != nullptr) { this->connected_sensor_->publish_state(up); } +#endif #ifdef USE_SENSOR // Only edges get here, so down is the falling edge. if (!up && this->disconnects_sensor_ != nullptr) { diff --git a/esphome/components/uart_tcp/uart_tcp.h b/esphome/components/uart_tcp/uart_tcp.h index 256e059133a..6080cc95514 100644 --- a/esphome/components/uart_tcp/uart_tcp.h +++ b/esphome/components/uart_tcp/uart_tcp.h @@ -1,6 +1,9 @@ #pragma once +#include "esphome/core/defines.h" +#ifdef USE_BINARY_SENSOR #include "esphome/components/binary_sensor/binary_sensor.h" +#endif #ifdef USE_SENSOR #include "esphome/components/sensor/sensor.h" #endif @@ -22,7 +25,9 @@ class UartTcp final : public Component, public uart::UARTDevice { void set_host(const char *host) { this->link_.set_host(host); } void set_port(uint16_t port) { this->link_.set_port(port); } void set_reconnect_interval(uint32_t ms) { this->link_.set_reconnect_interval(ms); } +#ifdef USE_BINARY_SENSOR void set_connected_sensor(binary_sensor::BinarySensor *sensor) { this->connected_sensor_ = sensor; } +#endif #ifdef USE_SENSOR void set_disconnects_sensor(sensor::Sensor *sensor) { this->disconnects_sensor_ = sensor; } #endif @@ -53,7 +58,9 @@ class UartTcp final : public Component, public uart::UARTDevice { #ifdef USE_SOCKET_TCP_LISTENER socket::TcpListener listener_; #endif +#ifdef USE_BINARY_SENSOR binary_sensor::BinarySensor *connected_sensor_{nullptr}; +#endif // Loop start time of the last socket-to-UART write; sizes the next paced write. uint32_t last_write_ms_{0}; #ifdef USE_SENSOR diff --git a/tests/components/uart_tcp/benchmark.yaml b/tests/components/uart_tcp/benchmark.yaml index 781dc15b681..ed771f20534 100644 --- a/tests/components/uart_tcp/benchmark.yaml +++ b/tests/components/uart_tcp/benchmark.yaml @@ -1,3 +1,4 @@ -# The disconnects counter is compiled only with USE_SENSOR; declaring the -# sensor domain makes the C++ unit test build define it. +# The connection entities are compiled only with USE_BINARY_SENSOR and +# USE_SENSOR; declaring the domains makes the C++ unit test build define them. +binary_sensor: sensor: diff --git a/tests/components/uart_tcp/common.yaml b/tests/components/uart_tcp/common.yaml index fd34757d0ee..cf86dc9da89 100644 --- a/tests/components/uart_tcp/common.yaml +++ b/tests/components/uart_tcp/common.yaml @@ -10,7 +10,15 @@ uart_tcp: allowed_ips: - 192.168.1.10 - 192.168.1.0/24 + +binary_sensor: + - platform: uart_tcp + uart_tcp_id: bridge connected: name: UART TCP Connected + +sensor: + - platform: uart_tcp + uart_tcp_id: bridge disconnects: name: UART TCP Disconnects diff --git a/tests/components/uart_tcp/test-client.esp32-idf.yaml b/tests/components/uart_tcp/test-client.esp32-idf.yaml index 5ba900347c4..6bce693f854 100644 --- a/tests/components/uart_tcp/test-client.esp32-idf.yaml +++ b/tests/components/uart_tcp/test-client.esp32-idf.yaml @@ -12,7 +12,15 @@ uart_tcp: host: 192.0.2.20 port: 502 reconnect_interval: 10s + +binary_sensor: + - platform: uart_tcp + uart_tcp_id: bridge connected: name: UART TCP Connected + +sensor: + - platform: uart_tcp + uart_tcp_id: bridge disconnects: name: UART TCP Disconnects diff --git a/tests/components/uart_tcp/test.host.yaml b/tests/components/uart_tcp/test.host.yaml index a0b82c568df..b793ae144c3 100644 --- a/tests/components/uart_tcp/test.host.yaml +++ b/tests/components/uart_tcp/test.host.yaml @@ -8,7 +8,15 @@ uart_tcp: uart_id: uart_bus host: 127.0.0.1 port: 44502 + +binary_sensor: + - platform: uart_tcp + uart_tcp_id: bridge connected: name: UART TCP Connected + +sensor: + - platform: uart_tcp + uart_tcp_id: bridge disconnects: name: UART TCP Disconnects diff --git a/tests/integration/fixtures/uart_tcp_bridge.yaml b/tests/integration/fixtures/uart_tcp_bridge.yaml index 7ad28316f75..cf6c8fad64b 100644 --- a/tests/integration/fixtures/uart_tcp_bridge.yaml +++ b/tests/integration/fixtures/uart_tcp_bridge.yaml @@ -24,11 +24,15 @@ uart_tcp: port: 18126 allowed_ips: - 127.0.0.1 - connected: - name: Bridge Connected - id: denied_bridge uart_id: denied_bus role: server port: 18127 allowed_ips: - 192.0.2.1 + +binary_sensor: + - platform: uart_tcp + uart_tcp_id: bridge + connected: + name: Bridge Connected