Help for generating an UART Proxy

I am currently working on a project involving ESPHome and UART communication and have encountered some difficulties. I’m seeking assistance and guidance from the community.

I have set up my ESP32 board with two UART interfaces, one connected to a controller and the other to a heating system. My goal is to capture the data received from the controller over UART, log it, and ideally display it on a text sensor for further anlysis. The data from the controller should then be sent to the heating system and vise versa.

I have tried various configurations, including the uart and text_sensor platforms. However, I’ve been encountering errors and difficulties in implementing this correctly.

I’m looking for guidance on the correct configuration and setup to achieve this integration successfully.

my code just connecting to the two uart devices and show me the communication from both devices in the logs.

esphome:
  name: heater
  friendly_name: Heater

esp32:
  board: nodemcu-32s
  framework:
    type: arduino


# Enable logging
logger:
  baud_rate: 0


# Enable Home Assistant API
api:
  encryption:
    key: "*****"

ota:
  password: "*****"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
    # ...
  manual_ip:
    # Set this to the IP of the ESP
    static_ip: 192.168.0.120
    # Set this to the IP address of the router. Often ends with .1
    gateway: 192.168.0.1
    # The subnet of the network. 255.255.255.0 works for most home networks.
    subnet: 255.255.255.0

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Heater Fallback Hotspot"
    password: "******"

captive_portal:


uart:
  - id: uart_1_controller
    baud_rate: 9600
    tx_pin: 17
    rx_pin: 16
    debug:
      direction: BOTH
      dummy_receiver: true
      after:
        delimiter: "\r\n"
      sequence:
        - lambda: |-
            ESP_LOGD("custom", "Controller:");
            UARTDebug::log_string(direction, bytes);

  - id: uart_2_heater
    baud_rate: 9600
    tx_pin: 1
    rx_pin: 3
    debug:
      direction: BOTH
      dummy_receiver: true
      after:
        delimiter: "\r\n"
      sequence:
        - lambda: |-
            ESP_LOGD("custom", "Heater:");
            UARTDebug::log_string(direction, bytes);

Thank you in advance for your help and support.

So do you basically want a “Man in the middle” setup with the esp listening to and forwarding two-way communication, with the ability to inject commands?

If so, take a look at these options.

The right wiring is important with a “pass through” set-up like this or if won’t work. This is similar and may help. Ignore the “Convertors”. If you only need to listen to and forward commands but not inject your own then the whole thing can be simpler.

My pass through set-up failed because very rapid messages and responses were required. Maybe for your application it is ok.

This is untested, but try only logging the RX side. Otherwise when ESP sends data back out it will get logged again, and again…After receiving and writing the string to the log write the bytes back out to the other UART.

uart:
  - id: uart_1_controller
    baud_rate: 9600
    tx_pin: 17
    rx_pin: 16
    debug:
      direction: RX
      dummy_receiver: true
      after:
        delimiter: "\r\n"
      sequence:
        - lambda: |-
            ESP_LOGD("custom", "Controller:");
            UARTDebug::log_string(direction, bytes);
            id(uart_2_heater).write_array(bytes);   #write bytes out on other uart

  - id: uart_2_heater
    baud_rate: 9600
    tx_pin: 1
    rx_pin: 3
    debug:
      direction: RX
      dummy_receiver: true
      after:
        delimiter: "\r\n"
      sequence:
        - lambda: |-
            ESP_LOGD("custom", "Heater:");
            UARTDebug::log_string(direction, bytes);
            id(uart_1_controller).write_array(bytes);  #write bytes out on other uart

Edit: write_array was originally just write

I also figured out at some point that you can log both directions if you want to but just do stuff for RX if you want.

1 Like

unfortunately this seems not to work:

Compiling .pioenvs/heater/src/main.cpp.o
/config/esphome/heater.yaml: In lambda function:
/config/esphome/heater.yaml:61:27: error: 'class esphome::uart::ESP32ArduinoUARTComponent' has no member named 'write'
              id(uart_1_controller).write(bytes);
                           ^~~~~
/config/esphome/heater.yaml: In lambda function:
/config/esphome/heater.yaml:46:22: error: 'class esphome::uart::ESP32ArduinoUARTComponent' has no member named 'write'
             id(uart_2_heater).write(bytes);
                      ^~~~~
*** [.pioenvs/heater/src/main.cpp.o] Error 1
========================= [FAILED] Took 17.14 seconds =========================

any other idea?

working with the second link, thank you.

uart:
  - id: uart_1_controller
    baud_rate: 9600
    tx_pin: 17
    rx_pin: 16
    debug:
      direction: RX
      dummy_receiver: true
      after:
        delimiter: "\r\n"
      sequence:
        - uart.write: #Write rx to tx.
            id: uart_2_heater
            data: !lambda return bytes ;
        - lambda: |-
            ESP_LOGD("custom", "Controller:");
            UARTDebug::log_string(direction, bytes);


  - id: uart_2_heater
    baud_rate: 9600
    tx_pin: 1
    rx_pin: 3
    debug:
      direction: RX
      dummy_receiver: true
      after:
        delimiter: "\r\n"
      sequence:
        - uart.write: #Write rx to tx.
            id: uart_1_controller
            data: !lambda return bytes ;
        - lambda: |-
            ESP_LOGD("custom", "Heater:");
            UARTDebug::log_string(direction, bytes);

next step would be to inject commands… i just checked the links above, but they did not help… any ideas here?
i need to build a hex command depending on power level, ventilation etc.

Looks like write should have been `write_array’.

Here was sample for sending constant hex values.
- uart.write: [0x40, 0x6D, 0x75, 0x6C, 0x63, 0x6D, 0x75, 0x0A, 0x0D]

is it normal if output looks like this, i mean all the ‘=’ or ‘#’ or even spaces. or are there maybe problem with the wiring and communication is not “clean”

[00:44:44][D][uart_debug:158]: <<< "\xAA\x04\x13\x00\x0F\x00\x01\x00\x1A\x00}\x01+\x00\x00\x00\x00\x00\x00\x00\x00\x00c#\xA4"
[00:44:44][D][custom:048]: Controller:
[00:44:44][D][uart_debug:158]: <<< "\xAA\x03\x01\x00\x11\x14\xB2Q"
[00:44:44][D][custom:066]: Heater:
[00:44:44][D][uart_debug:158]: <<< "\xAA\x04\x01\x00\x11\x14r\xE4"
[00:44:45][D][custom:048]: Controller:
[00:44:45][D][uart_debug:158]: <<< "\xAA\x03\x00\x00\x02\x9D\xBD"
[00:44:45][D][custom:066]: Heater:
[00:44:45][D][uart_debug:158]: <<< "\xAA\x04\x06\x00\x02\x00x\x04\x0F\x00\x05\xB1="

Try log_hex instead of log_string

hmm, seems i need to change something more?!
‘esphome::uart::UARTDebug::log_hex(esphome::uart::UARTDirection&, std::vector&)’
UARTDebug::log_hex(direction, bytes);

edit: separator was missing:

UARTDebug::log_hex(direction, bytes, ‘:’);

now it looks much cleaner :wink:

thanks!

1 Like

Hey Tidle, I’ve similar project.
Just setting up the hardware: stepdown buck , Level shifter and one esp32.
My first approach is logging the Communication between heater device and controller device.
Second one is to inject simple commands (on, off, send actual temperature) and Filter temperature states from controller.

Can you provide your working yaml please?