esphome-docs/components/uart.rst

285 lines
12 KiB
ReStructuredText

.. _uart:
UART Bus
========
.. seo::
:description: Instructions for setting up a UART serial bus on ESPs
:image: uart.svg
:keywords: UART, serial bus
UART is a common serial protocol for a lot of devices. For example, when uploading a binary to your ESP
you have probably used UART to access the chip. UART (or for Arduino often also called Serial) usually
consists of 2 pins:
- **TX**: This line is used to send data to the device at the other end.
- **RX**: This line is used to receive data from the device at the other end.
Please note that the naming of these two pins depends on the chosen perspective and can be ambiguous. For example,
while the ESP might send (``TX``) on pin A and receive (``RX``) data on pin B, from the other device's
perspective these two pins are switched (i.e. *it* sends on pin B and receives on pin A). So you might
need to try with the two pins switched if it doesn't work immediately.
Additionally, each UART bus can operate at different speeds (baud rates), so ESPHome needs to know what speed to
receive/send data at using the ``baud_rate`` option. The most common baud rates are 9600 and 115200.
In some cases only **TX** or **RX** exists as the device at the other end only accepts data or sends data.
.. note::
On the ESP32, this component uses the hardware UART units and is thus very accurate. On the ESP8266 however,
ESPHome has to use a software implementation as there are no other hardware UART units available other than the
ones used for logging. Therefore the UART data on the ESP8266 can have occasional data glitches especially with
higher baud rates.
.. note::
From ESPHome 2021.8 the ``ESP8266SoftwareSerial`` UART ``write_byte`` function had the parity bit fixed to be correct
for the data being sent. This could cause unexpected issues if you are using the Software UART and have devices that
explicity check the parity. Most likely you will need to flip the ``parity`` flag in YAML.
.. note::
UART implementation for the host platform does not use TX and RX pins but port names.
.. code-block:: yaml
# Example configuration entry
uart:
tx_pin: GPIOXX
rx_pin: GPIOXX
baud_rate: 9600
Configuration variables:
------------------------
- **baud_rate** (**Required**, int): The baud rate of the UART bus.
- **tx_pin** (*Optional*, :ref:`config-pin`): The pin to send data to from the ESP's perspective. Use the full pin schema and set ``inverted: true`` to invert logic levels. Not supported by host platform.
- **rx_pin** (*Optional*, :ref:`config-pin`): The pin to receive data on from the ESP's perspective. Use the full pin schema and set ``inverted: true`` to invert logic levels. Not supported by host platform.
- **port** (*Optional*, string): Host platform only. Unix style name of the port to use.
- **rx_buffer_size** (*Optional*, int): The size of the buffer used for receiving UART messages. Increase if you use an integration that needs to read big payloads from UART. Defaults to ``256``.
- **data_bits** (*Optional*, int): The number of data bits used on the UART bus. Options: 5 to 8. Defaults to 8.
- **parity** (*Optional*): The parity used on the UART bus. Options: ``NONE``, ``EVEN``, ``ODD``. Defaults to ``NONE``.
- **stop_bits** (*Optional*, int): The number of stop bits to send. Options: 1, 2. Defaults to 1.
- **id** (*Optional*, :ref:`config-id`): Manually specify the ID for this UART hub if you need multiple UART hubs.
- **debug** (*Optional*, mapping): Options for debugging communication on the UART hub, see :ref:`uart-debugging`.
.. _uart-hardware_uarts:
Hardware UARTs
--------------
Whenever possible, ESPHome will use the hardware UART unit on the ESP8266 for fast and accurate communication.
When the hardware UARTs are all occupied, ESPHome will fall back to a software implementation that may not
be accurate at higher baud rates.
``UART0`` is (by default) used by the :doc:`logger component </components/logger>`, using ``tx_pin: GPIO1`` and
``rx_pin: GPIO3``. If you configure a UART that overlaps with these pins, you can share the hardware with the
logger and leave others available. If you have configured the logger to use a different hardware UART, the pins
used for hardware sharing change accordingly.
The ESP32 has three UARTs. ESP32 lite variant chips (ESP32-S3, ESP32-C3, ESP32-S2, etc) may have fewer UARTs (usually two). Any pair of GPIO pins can be used, as long as they support the proper output/input modes.
The ESP8266 has two UARTs; the second of which is TX-only. Only a limited set of pins can be used. ``UART0`` may
use either ``tx_pin: GPIO1`` and ``rx_pin: GPIO3``, or ``tx_pin: GPIO15`` and ``rx_pin: GPIO13``. ``UART1`` must
use ``tx_pin: GPIO2``. Any other combination of pins will result in use of a software UART.
.. note::
The Software UART is only available on the ESP8266. It is not available on ESP32 and variants.
.. _uart-write_action:
``uart.write`` Action
---------------------
This :ref:`Action <config-action>` sends a defined UART signal to the given UART bus.
.. code-block:: yaml
on_...:
- uart.write: 'Hello World'
# For escape characters, you must use double quotes!
- uart.write: "Hello World\r\n"
# Raw data
- uart.write: [0x00, 0x20, 0x42]
# Templated, return type is std::vector<uint8_t>
- uart.write: !lambda
return {0x00, 0x20, 0x42};
# in case you need to specify the uart id
- uart.write:
id: my_second_uart
data: 'other data'
.. _uart-debugging:
Debugging
---------
If you need insight in the communication that is being sent and/or received over a UART bus, then you can make use
of the debugging feature.
.. code-block:: yaml
# Example configuration entry
uart:
baud_rate: 115200
debug:
direction: BOTH
dummy_receiver: false
after:
delimiter: "\n"
sequence:
- lambda: UARTDebug::log_string(direction, bytes);
# Minimal configuration example, logs hex strings by default
uart:
baud_rate: 9600
debug:
- **direction** (*Optional*, enum): The direction of communication to debug, one of: "RX" (receive, incoming),
"TX" (send, outgoing) or "BOTH". Defaults to "BOTH".
- **dummy_receiver** (*Optional*, boolean): Whether or not to enable the dummy receiver feature. The debugger
will only accumulate bytes that are actually read or sent by a UART device component. This feature is
useful when you want to debug all incoming communication, while no UART device component is configured
for the UART bus (yet). This is especially useful for developers. Normally you'd want to leave this
option disabled. Defaults to false.
- **after** (*Optional*, mapping): The debugger accumulates bytes of communication. This option defines when
to trigger publishing the accumulated bytes. The possible options are:
- **bytes** (*Optional*, int): Trigger after accumulating the specified number of bytes. Defaults to 150.
- **timeout** (*Optional*, :ref:`config-time`): Trigger after no communication has been seen during the
specified timeout, while one or more bytes have been accumulated. Defaults to 100ms.
- **delimiter** (*Optional*, string or list of bytes): Trigger after the specified sequence of bytes is
detected in the communication.
- **sequence** (*Optional*, :ref:`Action <config-action>`): Action(s) to perform for publishing debugging data.
Defaults to an action that logs the bytes in hex format. The actions can make use of the following variables:
- **direction**: ``uart::UART_DIRECTION_RX`` or ``uart::UART_DIRECTION_TX``
- **bytes**: ``std::vector<uint8_t>`` containing the accumulated bytes
**Helper functions for logging**
Helper functions are provided to make logging of debug data in various formats easy:
- **UARTDebug::log_hex(direction, bytes, char separator)** Log the bytes as hex values, separated by the provided
separator character.
- **UARTDebug::log_string(direction, bytes)** Log the bytes as string values, escaping unprintable characters.
- **UARTDebug::log_int(direction, bytes, char separator)** Log the bytes as integer values, separated by the provided
separator character.
- **UARTDebug::log_binary(direction, bytes, char separator)** Log the bytes as ``<binary> (<hex>)`` values,
separated by the provided separator character.
**Logger buffer size**
Beware that the ``logger`` component uses a limited buffer size of 512 bytes by default. If the UART
debugger log lines become too long, then you will notice that they end up truncated in the log output.
In that case, either make sure that the debugger outputs less data per log line (e.g. by setting the
``after.bytes`` option to a lower value) or increase the logger buffer size using the logger
``tx_buffer_size`` option.
.. _uart-runtime_change:
Changing at runtime
-------------------
There are scenarios where you might need to adjust UART parameters during runtime to enhance communication efficiency
and adapt to varying operational conditions. ESPHome facilitates this through lambda calls.
Below are the methods to read current settings and modify them dynamically:
- **Reading Current Settings:** Access UART's current configuration using these read-only attributes:
.. code-block:: cpp
// RX buffer size
id(my_uart).get_rx_buffer_size();
// Stop bits
id(my_uart).get_stop_bits();
// Data bits
id(my_uart).get_data_bits();
// Parity
id(my_uart).get_parity();
// Baud rate
id(my_uart).get_baud_rate();
- **Modifying Settings at Runtime:** You can change certain UART parameters during runtime.
After setting new values, invoke ``load_settings()`` (ESP only) to apply these changes:
.. code-block:: yaml
select:
- id: change_baud_rate
name: Baud rate
platform: template
options:
- "2400"
- "9600"
- "38400"
- "57600"
- "115200"
- "256000"
- "512000"
- "921600"
initial_option: "115200"
optimistic: true
restore_value: True
internal: false
entity_category: config
icon: mdi:swap-horizontal
set_action:
- lambda: |-
id(my_uart).flush();
uint32_t new_baud_rate = stoi(x);
ESP_LOGD("change_baud_rate", "Changing baud rate from %i to %i",id(my_uart).get_baud_rate(), new_baud_rate);
if (id(my_uart).get_baud_rate() != new_baud_rate) {
id(my_uart).set_baud_rate(new_baud_rate);
id(my_uart).load_settings();
}
Available methods for runtime changes:
.. code-block:: cpp
// Set TX/RX pins
id(my_uart).set_tx_pin(InternalGPIOPin *tx_pin);
id(my_uart).set_rx_pin(InternalGPIOPin *rx_pin);
// RX buffer size
id(my_uart).set_rx_buffer_size(size_t rx_buffer_size);
// Stop bits
id(my_uart).set_stop_bits(uint8_t stop_bits);
// Data bits
id(my_uart).set_data_bits(uint8_t data_bits);
// Parity
id(my_uart).set_parity(UARTParityOptions parity);
// Baud rate
id(my_uart).set_baud_rate(uint32_t baud_rate);
This flexibility allows for dynamic adaptation to different communication requirements, enhancing the versatility of your ESPHome setup.
UART component with the host platform
-------------------------------------
Since the host platform does not have physical UART pins, the UART component is implemented using Unix-style ports. Instead of using pins,
you can specify the port name to use. This implementation also supports components that have ``require_tx`` and ``require_rx`` options such as
smt100 etc.
.. code-block:: yaml
# Example configuration entry for host platform
uart:
baud_rate: 9600
port: "/dev/ttyUSB0"
See Also
--------
- :doc:`/components/logger`
- :apiref:`uart/uart.h`
- :ghedit:`Edit`