diff --git a/esphome/components/uart/__init__.py b/esphome/components/uart/__init__.py index 0738a127e1..fdc85b40e0 100644 --- a/esphome/components/uart/__init__.py +++ b/esphome/components/uart/__init__.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_NUMBER, CONF_RX_PIN, CONF_TX_PIN, + CONF_FLOW_CONTROL_PIN, CONF_PORT, CONF_UART_ID, CONF_DATA, @@ -116,6 +117,11 @@ def validate_rx_pin(value): raise cv.Invalid("Pins GPIO16 and GPIO17 cannot be used as RX pins on ESP8266.") return value +def validate_flow_control_support(config): + if CONF_FLOW_CONTROL_PIN in config and not CORE.is_esp32: + raise cv.Invalid("Hardware does not support flow control.") + return config + def validate_invert_esp32(config): if ( @@ -239,6 +245,7 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_BAUD_RATE): cv.int_range(min=1), cv.Optional(CONF_TX_PIN): pins.internal_gpio_output_pin_schema, cv.Optional(CONF_RX_PIN): validate_rx_pin, + cv.Optional(CONF_FLOW_CONTROL_PIN): pins.internal_gpio_output_pin_schema, cv.Optional(CONF_PORT): cv.All(validate_port, cv.only_on(PLATFORM_HOST)), cv.Optional(CONF_RX_BUFFER_SIZE, default=256): cv.validate_bytes, cv.Optional(CONF_STOP_BITS, default=1): cv.one_of(1, 2, int=True), @@ -254,6 +261,7 @@ CONFIG_SCHEMA = cv.All( ).extend(cv.COMPONENT_SCHEMA), cv.has_at_least_one_key(CONF_TX_PIN, CONF_RX_PIN, CONF_PORT), validate_invert_esp32, + validate_flow_control_support, validate_host_config, ) @@ -296,6 +304,9 @@ async def to_code(config): if CONF_RX_PIN in config: rx_pin = await cg.gpio_pin_expression(config[CONF_RX_PIN]) cg.add(var.set_rx_pin(rx_pin)) + if CONF_FLOW_CONTROL_PIN in config: + flow_control_pin = await cg.gpio_pin_expression(config[CONF_FLOW_CONTROL_PIN]) + cg.add(var.set_flow_control_pin(flow_control_pin)) if CONF_PORT in config: cg.add(var.set_name(config[CONF_PORT])) cg.add(var.set_rx_buffer_size(config[CONF_RX_BUFFER_SIZE])) diff --git a/esphome/components/uart/uart_component.h b/esphome/components/uart/uart_component.h index a57910c1a1..88df65a859 100644 --- a/esphome/components/uart/uart_component.h +++ b/esphome/components/uart/uart_component.h @@ -82,6 +82,10 @@ class UARTComponent { // @param rx_pin Pointer to the internal GPIO pin used for reception. void set_rx_pin(InternalGPIOPin *rx_pin) { this->rx_pin_ = rx_pin; } + // Sets the flow control pin for the UART bus. + // @param rx_pin Pointer to the internal GPIO pin used for reception. + void set_flow_control_pin(InternalGPIOPin *flow_control_pin) { this->flow_control_pin_ = flow_control_pin; } + // Sets the size of the RX buffer. // @param rx_buffer_size Size of the RX buffer in bytes. void set_rx_buffer_size(size_t rx_buffer_size) { this->rx_buffer_size_ = rx_buffer_size; } @@ -161,6 +165,7 @@ class UARTComponent { InternalGPIOPin *tx_pin_; InternalGPIOPin *rx_pin_; + InternalGPIOPin *flow_control_pin_; size_t rx_buffer_size_; uint32_t baud_rate_; uint8_t stop_bits_; diff --git a/esphome/components/uart/uart_component_esp32_arduino.cpp b/esphome/components/uart/uart_component_esp32_arduino.cpp index b241c03de4..99f0f99f2d 100644 --- a/esphome/components/uart/uart_component_esp32_arduino.cpp +++ b/esphome/components/uart/uart_component_esp32_arduino.cpp @@ -141,6 +141,10 @@ void ESP32ArduinoUARTComponent::load_settings(bool dump_config) { invert = true; this->hw_serial_->setRxBufferSize(this->rx_buffer_size_); this->hw_serial_->begin(this->baud_rate_, get_config(), rx, tx, invert); + if (this->flow_control_pin_ != nullptr) { + this->hw_serial_->setPins(-1, -1, -1, this->flow_control_pin_->get_pin()); + this->hw_serial_->setMode(UART_MODE_RS485_HALF_DUPLEX); + } if (dump_config) { ESP_LOGCONFIG(TAG, "UART %u was reloaded.", this->number_); this->dump_config(); @@ -151,6 +155,7 @@ void ESP32ArduinoUARTComponent::dump_config() { ESP_LOGCONFIG(TAG, "UART Bus %d:", this->number_); LOG_PIN(" TX Pin: ", tx_pin_); LOG_PIN(" RX Pin: ", rx_pin_); + LOG_PIN(" Flow Control Pin: ", flow_control_pin_); if (this->rx_pin_ != nullptr) { ESP_LOGCONFIG(TAG, " RX Buffer Size: %u", this->rx_buffer_size_); } diff --git a/esphome/components/uart/uart_component_esp_idf.cpp b/esphome/components/uart/uart_component_esp_idf.cpp index 122d4105c8..0493bd372a 100644 --- a/esphome/components/uart/uart_component_esp_idf.cpp +++ b/esphome/components/uart/uart_component_esp_idf.cpp @@ -106,6 +106,7 @@ void IDFUARTComponent::setup() { int8_t tx = this->tx_pin_ != nullptr ? this->tx_pin_->get_pin() : -1; int8_t rx = this->rx_pin_ != nullptr ? this->rx_pin_->get_pin() : -1; + int8_t flow_control = this->flow_control_pin_ != nullptr ? this->flow_control_pin_->get_pin() : -1; uint32_t invert = 0; if (this->tx_pin_ != nullptr && this->tx_pin_->is_inverted()) @@ -120,7 +121,7 @@ void IDFUARTComponent::setup() { return; } - err = uart_set_pin(this->uart_num_, tx, rx, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + err = uart_set_pin(this->uart_num_, tx, rx, flow_control, UART_PIN_NO_CHANGE); if (err != ESP_OK) { ESP_LOGW(TAG, "uart_set_pin failed: %s", esp_err_to_name(err)); this->mark_failed(); @@ -138,6 +139,15 @@ void IDFUARTComponent::setup() { this->mark_failed(); return; } + + if (this->flow_control_pin_ != nullptr) { + err = uart_set_mode(this->uart_num_, UART_MODE_RS485_HALF_DUPLEX); + if (err != ESP_OK) { + ESP_LOGW(TAG, "uart_set_mode failed: %s", esp_err_to_name(err)); + this->mark_failed(); + return; + } + } xSemaphoreGive(this->lock_); } @@ -159,6 +169,7 @@ void IDFUARTComponent::dump_config() { ESP_LOGCONFIG(TAG, "UART Bus %u:", this->uart_num_); LOG_PIN(" TX Pin: ", tx_pin_); LOG_PIN(" RX Pin: ", rx_pin_); + LOG_PIN(" Flow Control Pin: ", flow_control_pin_); if (this->rx_pin_ != nullptr) { ESP_LOGCONFIG(TAG, " RX Buffer Size: %u", this->rx_buffer_size_); }