The UART Bus component provides a write action but no read actions. Typically the UART read is implemented in a custom component that also does the processing. The UART debug sequence can be exploited to act like a call back function whenever there is received data to process. So basically instead of creating a small custom component a large lambda call can be used in the UART debug yaml. This is shared to hopefully help make implementing UART devices a bit easier for average users.
It seems to be well suited for implementing simple UART devices where the code in the lambda would be the majority of the custom component code. If the protocol is more complex with different lengths of types of payload in the packets this isn’t well suited.
Key points are:
-
dummy_receiver: true
to make sure the debug logging gets triggered without another uart component to do the reading - the rx data is returned in
std::vector<uint8_t> bytes
- delimiter and timeout tweaked so rx data is presented in consistent format
- direction: RX if uart.write is used to tx data, otherwise tx data gets processed by lambda as well
- doesn’t have a
setup()
if you need to perform some initialization (esphome.on_boot could be work around) - only gets called when data arrives, additional logic might be required to determine if UART bus is faulted
esphome:
name: uart-hack
esp32:
board: esp32dev
framework:
type: arduino
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
api:
ota:
password: !secret esp_home_ota_pw
logger:
baud_rate: 115200
uart:
baud_rate: 115200
tx_pin: 17
rx_pin: 16
debug:
direction: RX
dummy_receiver: true
after:
delimiter: "\r\n"
sequence:
- lambda: |-
UARTDebug::log_string(direction, bytes); //Still log the data
int sensorID=0;
float sensorTEMP=0;
//Example to convert uart text to string
std::string str(bytes.begin(), bytes.end());
//watch for potential problems with non printable or special characters in string
id(rawString).publish_state(str.c_str());
//Sample uart text protocol that sends id:temperature\r\n packets
if (sscanf(str.c_str(), "%d:%f", &sensorID, &sensorTEMP) == 2 ) {
if(sensorID==1)
id(temp1).publish_state(sensorTEMP);
if(sensorID==2)
id(temp2).publish_state(sensorTEMP);
}
//Sample binary / hex data
if (bytes.size()==9) {
if(bytes[0]==0x40)
id(binData).publish_state( bytes[4] );
}
text_sensor:
- platform: template
name: "Raw String"
id: "rawString"
sensor:
- platform: template
name: "Temp 1"
id: "temp1"
- platform: template
name: "Temp 2"
id: "temp2"
- platform: template
name: "Binary Data"
id: binData
button:
- platform: template
name: "Test Button 1"
on_press:
- uart.write: "1:21.1\r\n"
- platform: template
name: "Test Button 2"
on_press:
- uart.write: "2:21.2\r\n"
- platform: template
name: "Test Button 3"
on_press:
- uart.write: [0x54, 0x65, 0x73, 0x74, 0x20, 0x33, 0x0A, 0x0D]
- platform: template
name: "Test Button 4"
on_press:
- uart.write: "giberish\r\n"
- platform: template
name: "Test Button 5"
on_press:
- uart.write: [0x40, 0x6D, 0x75, 0x6C, 0x63, 0x6D, 0x75, 0x0A, 0x0D]
#if you need to send a request periodically to get response from the uart device
interval:
- interval: 1min
then:
- uart.write: [0x54, 0x65, 0x73, 0x74, 0x20, 0x33, 0x0A, 0x0D]