ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
tcp_uart.cpp
Go to the documentation of this file.
1#include "tcp_uart.h"
2
4#include "esphome/core/log.h"
5
6#include <cinttypes>
7#include <cstring>
8
10
11ESPHOME_LOG_TAG(TAG, "tcp_uart");
12
13static constexpr uint32_t DROP_LOG_INTERVAL_MS = 5000;
14
16 this->link_.begin(TAG);
17#ifdef USE_SOCKET_TCP_LISTENER
18 this->listener_.begin(TAG);
19#endif
20 if (this->connected_sensor_ != nullptr) {
21 this->connected_sensor_->publish_state(false);
22 }
23#ifdef USE_SENSOR
24 if (this->disconnects_sensor_ != nullptr) {
26 }
27#endif
28}
29
31 ESP_LOGCONFIG(TAG,
32 "TCP UART:\n"
33 " %s: %s:%u\n"
34 " Reconnect Interval: %" PRIu32 "ms",
35 this->server_ ? LOG_STR_LITERAL("Listen") : LOG_STR_LITERAL("Host"),
36 this->server_ ? LOG_STR_LITERAL("*") : this->link_.host(), this->link_.port(),
37 this->link_.reconnect_interval());
38#ifdef USE_SOCKET_TCP_LISTENER
39 this->listener_.dump_config();
40#endif
41 LOG_BINARY_SENSOR(" ", "Connected", this->connected_sensor_);
42#ifdef USE_SENSOR
43 LOG_SENSOR(" ", "Disconnects", this->disconnects_sensor_);
44#endif
45}
46
48 this->link_.close();
49#ifdef USE_SOCKET_TCP_LISTENER
50 this->listener_.close();
51#endif
52}
53
55 bool up = this->link_.connected();
56 this->link_was_up_ = up;
57 if (up) {
58 // Unread bytes of the last session stay readable while down, never into the next one.
59 this->rx_start_ = this->rx_end_ = 0;
60 }
61 if (this->connected_sensor_ != nullptr) {
63 }
64#ifdef USE_SENSOR
65 // Only edges get here, so down is the falling edge.
66 if (!up && this->disconnects_sensor_ != nullptr) {
67 this->disconnects_++;
69 }
70#endif
71}
72
74 if (this->rx_start_ != 0) {
75 this->rx_end_ -= this->rx_start_;
76 std::memmove(this->rx_, this->rx_ + this->rx_start_, this->rx_end_);
77 this->rx_start_ = 0;
78 }
79 size_t room = RX_BUFFER_SIZE - this->rx_end_;
80 if (room == 0) {
81 // Only a read that filled all free space gets here, so rx_pending_ is already set.
82 return;
83 }
84 ssize_t count = this->link_.read(this->rx_ + this->rx_end_, room);
85 if (count <= 0) {
86 // A dropped link (-1) is seen by sync_link_() on the next loop.
87 if (count == 0) {
88 this->rx_pending_ = false;
89 }
90 return;
91 }
92 this->rx_end_ += static_cast<uint16_t>(count);
93 this->rx_pending_ = static_cast<size_t>(count) == room;
94}
95
97#ifdef USE_SOCKET_TCP_LISTENER
98 if (this->server_) {
99 // link_was_up_ holds the accept until the previous drop's edge has run,
100 // so the sensor sees the disconnect and the new session's edge clears RX.
101 this->listener_.poll(this->link_, !this->link_was_up_);
102 } else {
103 this->link_.poll();
104 }
105#else
106 this->link_.poll();
107#endif
108 if (this->link_.connected() != this->link_was_up_) {
109 this->sync_link_();
110 }
111 if (!this->link_was_up_) {
112 return;
113 }
114 if (this->rx_pending_ || this->link_.ready()) {
115 this->read_socket_();
116 }
117 this->link_.flush_tx();
118}
119
120void TcpUart::write_array(const uint8_t *data, size_t len) {
121 size_t queued = this->link_.queue(data, len);
122 if (queued < len) {
124 if (this->last_drop_log_ms_ == 0 || now - this->last_drop_log_ms_ >= DROP_LOG_INTERVAL_MS) {
125 ESP_LOGW(TAG, "%s, dropped %u bytes",
126 this->link_.connected() ? LOG_STR_LITERAL("TX buffer full") : LOG_STR_LITERAL("Not connected"),
127 static_cast<unsigned>(len - queued));
128 this->last_drop_log_ms_ = now;
129 }
130 }
131}
132
133bool TcpUart::peek_byte(uint8_t *data) {
134 if (this->rx_start_ == this->rx_end_) {
135 return false;
136 }
137 *data = this->rx_[this->rx_start_];
138 return true;
139}
140
141bool TcpUart::read_array(uint8_t *data, size_t len) {
142 if (this->available() < len) {
143 return false;
144 }
145 std::memcpy(data, this->rx_ + this->rx_start_, len);
146 this->rx_start_ += static_cast<uint16_t>(len);
147 return true;
148}
149
151 bool emptied = this->link_.flush_tx();
152 if (!this->link_.connected()) {
153 // A down link cannot have delivered anything, whether this flush dropped
154 // it or an earlier loop() write did.
156 }
158}
159
160} // namespace esphome::tcp_uart
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
void publish_state(bool new_state)
Publish a new state to the front-end.
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:65
void poll(TcpClientLink &link, bool may_accept)
Server state machine; call every loop.
void begin(const char *tag)
Call from setup(); tag names the log lines.
void dump_config() const
One config line per allowed network.
bool read_array(uint8_t *data, size_t len) override
Definition tcp_uart.cpp:141
socket::TcpClientLink link_
Definition tcp_uart.h:63
void write_array(const uint8_t *data, size_t len) override
Definition tcp_uart.cpp:120
size_t available() override
Definition tcp_uart.h:46
binary_sensor::BinarySensor * connected_sensor_
Definition tcp_uart.h:67
void setup() override
Definition tcp_uart.cpp:15
void dump_config() override
Definition tcp_uart.cpp:30
void on_shutdown() override
Definition tcp_uart.cpp:47
static constexpr size_t RX_BUFFER_SIZE
Definition tcp_uart.h:61
uint8_t rx_[RX_BUFFER_SIZE]
Definition tcp_uart.h:81
uart::UARTFlushResult flush() override
Definition tcp_uart.cpp:150
bool peek_byte(uint8_t *data) override
Definition tcp_uart.cpp:133
sensor::Sensor * disconnects_sensor_
Definition tcp_uart.h:69
socket::TcpListener listener_
Definition tcp_uart.h:65
unsigned count
Definition gif.cpp:51
__int64 ssize_t
Definition httplib.h:178
ESPHOME_LOG_TAG(TAG, "tcp_uart")
UARTFlushResult
Result of a flush() call.
@ UART_FLUSH_RESULT_SUCCESS
Confirmed: all bytes left the TX FIFO.
@ UART_FLUSH_RESULT_FAILED
Confirmed: driver or hardware error.
@ UART_FLUSH_RESULT_TIMEOUT
Confirmed: timed out before TX completed.
const void size_t len
Definition hal.h:68
Application App
Global storage of Application pointer - only one Application can exist.
static void uint32_t