Same code with UART works with one board, not with another

Hi folks!

I’m having a bit of a UART problem…
I have a project that uses an ESP32 board with ESPHome to interact with my Mitsubishi heatpump.
I had it somewhat working with an ESP8266 (Wemos D1 mini) but it kept crashing.
I tried to move it to two different ESP32 (still Wemos D1 mini style), but UART would not work on either of them!

I moved it to an Olimex ESP32-POE, and everything works just fine.

However, the ESP32-POE form factor is not ideal for my use, so I wanted to move it to an Olimex ESP32-Gateway-EA; but again, no way to make UART work at all…
I’ve even been in touch with Olimex support and we ensured UART was working properly on the selected pins (GPIO16 & 32) using Arduino IDE.

Do you have any idea what could cause this code to work on some boards but not others?
(BTW, I did make sure to use the proper board, at least for esp32-poe and esp32-gateway, for the D1 mini I can’t remember)

Thanks!

Post your wiring, your code and your logs, so someone can have a look…
I have no reason to think plain Esp32 (D1 mini) has any UART problems with esphome.
Bad soldering?

Sure!
[ Edit: bad solder joints was the first thing I suspected; so on each board that didn’t work I tried re-flowing the joints, and even replacing the pins ]

substitutions:
  name: heat-pump
  friendlyName: Heat Pump

esphome:
  name: ${name}
  friendly_name: ${friendlyName}
  devices:
    - id: zone1_device
      name: "1st floor"
      area_id: zone1_area
    - id: zone2_device
      name: "2nd floor"
      area_id: zone2_area

  areas:
    - id: zone1_area
      name: "1st floor"
    - id: zone2_area
      name: "2nd floor"
    - id: utility_area
      name: "Utility room"

esp32:
  board: esp32-gateway
  # board: esp32dev
  framework:
    type: esp-idf

# Enable logging
logger:

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

ota:
  - platform: esphome
    password: "***"

external_components:
  - source: github://Ulrar/esphome-ecodan-heatpump@develop
    refresh: 0s
    components: [ ecodan ]

mdns:
  disabled: true

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

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

  manual_ip:
    static_ip: 10.0.0.195
    gateway: 10.0.0.1
    subnet: 255.255.255.0
  use_address: 10.0.0.195

captive_portal:

# Enable Web server.
web_server:
  port: 80

# Sync time with Home Assistant.
time:
  - platform: homeassistant
    id: homeassistant_time

uart:
  id: ecodan_uart
  baud_rate: 2400
  tx_pin: GPIO16
  rx_pin: GPIO32
  rx_buffer_size: 1024
  parity: EVEN

  # debug:
  #   direction: BOTH
  #   dummy_receiver: false
  #   after:
  #     delimiter: "\n"
  #   sequence:
  #     - lambda: UARTDebug::log_string(direction, bytes);

ecodan:
  id: ecodan_instance
  uart_id: ecodan_uart

text_sensor:
  
  # Heat pump general status sensors
  - platform: ecodan
    date_time:
      name: Current date/time
    defrost:
      name: Defrost
    heating_stage:
      name: Heating stage
    operating_mode:
      name: Operating mode
    heat_cool:
      name: Heating/cooling
    date_energy_cons:
      name: Date energy consumption
    date_energy_prod:
      name: Date energy production      
    holiday_mode:
      name: Holiday mode

sensor:
  - platform: uptime
    name: Uptime

  - platform: wifi_signal
    name: WiFi Signal
    update_interval: 60s

  - platform: homeassistant
    name: 2nd Floor temperature
    entity_id: sensor.2nd_floor_temperature
    internal: false
    disabled_by_default: true
    device_class: temperature
    state_class: measurement
    unit_of_measurement: "°C"
    filters:
      - clamp: # Limits values to range accepted by Mitsubishi units
          min_value: 1
          max_value: 40
          ignore_out_of_range: true
      - throttle: 30s
    on_value:
      then:
        - lambda: 'id(ecodan_instance).setRemoteTemperature(x, 2);'

  # # Heat pump general sensors
  - platform: ecodan
    error_code:
      name: Error code
    frequency:
      name: Frequency
    output_power:
      name: Output power
    gas_return_temp_signed:
      name: Gas return temperature
    outside_temperature:
      name: Outside temperature
    water_feed_temp_signed:
      name: Water feed temperature
    water_return_temp_signed:
      name: Water return temperature
    runtime:
      name: Runtime
    water_flow:
      name: Water flow
    energy_cons_yesterday:
      name: Heating energy consumption (yesterday)
      id: energy_cons_yesterday
    energy_prod_yesterday:
      name: Heating energy production (yesterday)
      id: energy_prod_yesterday
    energy_consumed_increasing:
      name: Total energy consumed

  - platform: template
    name: "CoP (yesterday)"
    id: cop_yesterday
    lambda: |-
      float prod = id(energy_prod_yesterday).state;
      float cons = id(energy_cons_yesterday).state;
      if (!std::isfinite(prod) || !std::isfinite(cons) || cons <= 0.0) {
        return NAN;
      }
      return prod / cons;
    state_class: measurement
    accuracy_decimals: 2

switch:
  # Heat pump general switches
  - platform: ecodan
    power_state:
      name: Power state
    holiday_mode:
      name: Holiday Mode

select:
  # Heat pump general selects
  - platform: ecodan
    mode_select_zone1:
      name: Mode
      device_id: zone1_device
    mode_select_zone2:
      name: Mode
      device_id: zone2_device

number:
  - platform: ecodan
    zone1_flow_temp_setpoint:
      name: Flow temperature setpoint
      device_id: zone1_device
    zone2_flow_temp_setpoint:
      name: Flow temperature setpoint
      device_id: zone2_device
  
# Climate entities for zone temperature control (alternative to number entities above)
climate:
  - platform: ecodan
    zone1:
      name: Thermostat
      device_id: zone1_device
    zone2:
      name: Thermostat
      device_id: zone2_device

With that, I have the following connections:

ESP32 Heat Pump
5v in 5v out
GND GND
GPIO16 (TX) RX
GPIO32 (RX) TX

And the logs I have (with UART debug enabled):

[10:40:51.700][D][ecodan:763]: Initialization attempt 5/10
[10:40:51.815][D][uart_debug:158]: >>> "\xFCZ\x02z\x02\xCA\x01]"
[10:40:53.702][D][ecodan:763]: Initialization attempt 6/10
[10:40:53.813][D][uart_debug:158]: >>> "\xFCZ\x02z\x02\xCA\x01]"
[10:40:55.707][D][ecodan:763]: Initialization attempt 7/10
[10:40:55.821][D][uart_debug:158]: >>> "\xFCZ\x02z\x02\xCA\x01]"
[10:40:57.724][D][ecodan:763]: Initialization attempt 8/10
[10:40:57.833][D][uart_debug:158]: >>> "\xFCZ\x02z\x02\xCA\x01]"
[10:40:59.731][D][ecodan:763]: Initialization attempt 9/10
[10:40:59.843][D][uart_debug:158]: >>> "\xFCZ\x02z\x02\xCA\x01]"
[10:41:01.742][D][ecodan:763]: Initialization attempt 10/10
[10:41:01.854][D][uart_debug:158]: >>> "\xFCZ\x02z\x02\xCA\x01]"
[10:41:03.763][E][ecodan:768]: Failed to initialize after 10 attempts, resetting retry counter

Once it reaches 10 attempts, it just loops back and restarts with attempt 1/10.

Look, I was hoping to debug this with “Esp32 d1 mini”. That Olimex gateway complicates things and there are many revisions to read.
Just a quick look at pinout gives:

So according to that your free non strapping I/O pins are 4, 13 and 32.

Yeah, I know, it’s a weird one :grimacing:
The end goal of the project was to use the Olimex board, so that’s why I’m focusing on it.
The board I have is a revision I, so that’s the pinout you provided!

The GPIO16 & 32 were a suggestion from Olimex support (because I went to them first with this problem), but I had also tried with 4, 12 and 13 with the same results.
Olimex support also provided an Arduino sketch to confirm that both GPIO16 & 32 are able to transmit and receive serial data by connecting them both together and transmitting on one an reading on the other.

Turn on the UART debug to see what’s going on.

I I was you I would focus to:

The UART debug was on, those are the lines with uart_debug.
All I see is UART data going out, but nothing coming in. But I can’t even be sure the TX is actually sending the data at this point.

And ultimately, I won’t be using the D1 minis, so I won’t spend time trying with them.

My problem is that I have a config that I know is working (on an ESP32-POE), and a board that I know is working (with serial data from an Arduino sketch), but when mixing the two together, UART does not work at all.

Inconsistent , your yaml didn’t have uart debugging on…

I understand, but your problem is very hard to debug.
Send yaml (with valid uart pins) and corresponding logs.
Obviously I expect your Ecodan parameters are from working setup.

Huh? I’m telling you I literally use the same config in both cases (only switching GPIOs), even to the point that I forgot to change the board type when switching back to the ESP32-POE, so yes, this IS the config that produced the debug logs you see.

Do you want me to reproduce the problem with the ESP32-Gateway to send the same logs?
Or do you want a working example of logs?

I believe 32 d1 mini approach is easiest one here.