esphome / issues

Issue Tracker for ESPHome
https://esphome.io/
290 stars 35 forks source link

ESP32: Multiple UART not working (works on ESP8266) #3669

Open jeroen85 opened 1 year ago

jeroen85 commented 1 year ago

The problem

I configure 3 UART instances on a ESP32 (see YAML below). One for P1 DSMR (utility meter; electricity) Two for Multical (second utility meter; district heating)

Logger UART is disabled (baudrate: 0). Also tried disabling complete logger integration... no help.

Depending on the order of the UART instances, only one of my setups is working. First 2 Multical UART, then 1 DSMR UART configuration --> result: Multical is working First 1 DSMR UART, then 2 Multical UART configuration --> result: DSMR is working

How can I ensure both setups are working?

Same software runs perfectly on a ESP8266 (software UARTs).

As I understand from documentation; ESP32 should have 3 UART instances.

Which version of ESPHome has the issue?

2022.9.4

What type of installation are you using?

Docker

Which version of Home Assistant has the issue?

2022.10

What platform are you using?

ESP32

Board

mhetesp32minikit

Component causing the issue

uart

Example YAML snippet

substitutions:
  device_name: "meterkast-esp32"
  friendly_name: Meterkast 

esp32:
  board: mhetesp32minikit
  framework:
    type: arduino

esphome:
  name: ${device_name}
  includes:
  - includes/multical401.h  

external_components:
- source: github://oxan/esphome-stream-server  

# Disable logging
logger:
  # level: DEBUG
  baud_rate: 0

wifi: 
  manual_ip:
    static_ip: !secret ip_meterkast_esp32

packages:
  general_settings: !include general_settings.yaml
  general_sensors: !include general_sensors.yaml  

uart:    
#Multical UART, 2 instances due to different baud-rates.
- rx_pin: GPIO22
  baud_rate: 1200
  data_bits: 8
  parity: NONE
  stop_bits: 1
  id: uart_rx
- tx_pin: GPIO21
  baud_rate: 300
  data_bits: 8
  parity: NONE
  stop_bits: 1
  id: uart_tx     

#Uart for DSMR P1-meter    
- rx_pin: GPIO23
  baud_rate: 115200
  id: uart_dsmr
  rx_buffer_size: 1700

stream_server:  
  uart_id: uart_dsmr
  port: 8088  

time:
- platform: homeassistant
  id: homeassistant_time  

# Multical Custom Sensor
custom_component:
- lambda: |-
    auto my_sensor = new Multical401(14400000, id(uart_tx), id(uart_rx), id(m_energy), id(m_volume), id(m_tin), id(m_tout), id(m_tdiff), id(m_power), id(m_flow), id(m_status));
    App.register_component(my_sensor);
    return {my_sensor};
  components:
    - id: multical

Anything in the logs that might be useful for us?

No errors or warnings.

First DSMR UART, then 2 Multical UART configurations --> result: DSMR is working

uart:    
#Uart for DSMR P1-meter    
- rx_pin: GPIO23
  baud_rate: 115200
  id: uart_dsmr
  rx_buffer_size: 1700

#Multical UART, 2 instances due to different baud-rates.
- rx_pin: GPIO22
  baud_rate: 1200
  data_bits: 8
  parity: NONE
  stop_bits: 1
  id: uart_rx
- tx_pin: GPIO21
  baud_rate: 300
  data_bits: 8
  parity: NONE
  stop_bits: 1
  id: uart_tx     
[14:06:59][C][logger:275]: Logger:
[14:06:59][C][logger:276]:   Level: DEBUG
[14:06:59][C][logger:277]:   Log Baud Rate: 0
[14:06:59][C][logger:278]:   Hardware UART: UART0
[14:06:59][C][uart.arduino_esp32:107]: UART Bus:
[14:06:59][C][uart.arduino_esp32:109]:   RX Pin: GPIO23
[14:06:59][C][uart.arduino_esp32:111]:   RX Buffer Size: 1700
[14:06:59][C][uart.arduino_esp32:113]:   Baud Rate: 115200 baud
[14:06:59][C][uart.arduino_esp32:114]:   Data Bits: 8
[14:06:59][C][uart.arduino_esp32:115]:   Parity: NONE
[14:06:59][C][uart.arduino_esp32:116]:   Stop bits: 1
[14:06:59][C][uart.arduino_esp32:107]: UART Bus:
[14:06:59][C][uart.arduino_esp32:109]:   RX Pin: GPIO22
[14:06:59][C][uart.arduino_esp32:111]:   RX Buffer Size: 256
[14:06:59][C][uart.arduino_esp32:113]:   Baud Rate: 1200 baud
[14:06:59][C][uart.arduino_esp32:114]:   Data Bits: 8
[14:06:59][C][uart.arduino_esp32:115]:   Parity: NONE
[14:06:59][C][uart.arduino_esp32:116]:   Stop bits: 1
[14:06:59][C][uart.arduino_esp32:107]: UART Bus:
[14:06:59][C][uart.arduino_esp32:108]:   TX Pin: GPIO21
[14:06:59][C][uart.arduino_esp32:113]:   Baud Rate: 300 baud
[14:06:59][C][uart.arduino_esp32:114]:   Data Bits: 8
[14:06:59][C][uart.arduino_esp32:115]:   Parity: NONE
[14:06:59][C][uart.arduino_esp32:116]:   Stop bits: 1
[14:06:59][C][uptime.sensor:031]: Uptime Sensor 'Meterkast Uptime'

First 2 Multical UART, then 1 DSMR UART configuration --> result: Multical is working

uart:    
#Multical UART, 2 instances due to different baud-rates.
- rx_pin: GPIO22
  baud_rate: 1200
  data_bits: 8
  parity: NONE
  stop_bits: 1
  id: uart_rx
- tx_pin: GPIO21
  baud_rate: 300
  data_bits: 8
  parity: NONE
  stop_bits: 1
  id: uart_tx     

#Uart for DSMR P1-meter    
- rx_pin: GPIO23
  baud_rate: 115200
  id: uart_dsmr
  rx_buffer_size: 1700
[14:20:48][C][logger:275]: Logger:
[14:20:48][C][logger:276]:   Level: DEBUG
[14:20:48][C][logger:277]:   Log Baud Rate: 0
[14:20:48][C][logger:278]:   Hardware UART: UART0
[14:20:48][C][uart.arduino_esp32:107]: UART Bus:
[14:20:48][C][uart.arduino_esp32:109]:   RX Pin: GPIO22
[14:20:48][C][uart.arduino_esp32:111]:   RX Buffer Size: 256
[14:20:48][C][uart.arduino_esp32:113]:   Baud Rate: 1200 baud
[14:20:48][C][uart.arduino_esp32:114]:   Data Bits: 8
[14:20:48][C][uart.arduino_esp32:115]:   Parity: NONE
[14:20:48][C][uart.arduino_esp32:116]:   Stop bits: 1
[14:20:48][C][uart.arduino_esp32:107]: UART Bus:
[14:20:48][C][uart.arduino_esp32:108]:   TX Pin: GPIO21
[14:20:48][C][uart.arduino_esp32:113]:   Baud Rate: 300 baud
[14:20:48][C][uart.arduino_esp32:114]:   Data Bits: 8
[14:20:48][C][uart.arduino_esp32:115]:   Parity: NONE
[14:20:48][C][uart.arduino_esp32:116]:   Stop bits: 1
[14:20:48][C][uart.arduino_esp32:107]: UART Bus:
[14:20:48][C][uart.arduino_esp32:109]:   RX Pin: GPIO23
[14:20:48][C][uart.arduino_esp32:111]:   RX Buffer Size: 1700
[14:20:48][C][uart.arduino_esp32:113]:   Baud Rate: 115200 baud
[14:20:48][C][uart.arduino_esp32:114]:   Data Bits: 8
[14:20:48][C][uart.arduino_esp32:115]:   Parity: NONE
[14:20:48][C][uart.arduino_esp32:116]:   Stop bits: 1
[14:20:48][C][uptime.sensor:031]: Uptime Sensor 'Meterkast Uptime'

Additional information

For reference; multical401.h

#include "esphome.h"
#include "esphome/core/component.h"

class Multical401 : public PollingComponent, public UARTDevice {
 public:

  Sensor *sensor_energy {nullptr};
  Sensor *sensor_volume {nullptr};
  Sensor *sensor_tempin {nullptr};
  Sensor *sensor_tempout {nullptr};
  Sensor *sensor_tempdiff {nullptr};
  Sensor *sensor_power {nullptr};
  Sensor *sensor_flow {nullptr};
  TextSensor *textsensor_status {nullptr};

  Multical401(uint32_t update_interval, UARTComponent *uart_tx, UARTComponent *uart_rx, Sensor *m__energy, Sensor *m__volume, Sensor *m__tin, Sensor *m__tout, Sensor *m__tdiff, Sensor *m__power, Sensor *m__flow, TextSensor *m__status) : PollingComponent(update_interval), sensor_energy(m__energy), sensor_volume(m__volume), sensor_tempin(m__tin), sensor_tempout(m__tout), sensor_tempdiff(m__tdiff), sensor_power(m__power), sensor_flow(m__flow), textsensor_status(m__status) {
    _tx = new UARTDevice(uart_tx);
    _rx = new UARTDevice(uart_rx);
  }

  void setup() override { }

  void update() override {

    ESP_LOGD("multical", "Start update"); 

    byte sendmsg1[] = { 175,163,177 };            //   /#1 with even parity

    byte r  = 0;    
    byte to = 0;
    byte i;
    char message[255];
    int parityerrors;

    for (int x = 0; x < 3; x++) {
      _tx->write(sendmsg1[x]);
    }

    to = 0;
    r = 0;
    i = 0;
    parityerrors = 0;
    char *tmpstr;
    float m_energy, m_volume, m_tempin, m_tempout, m_tempdiff, m_power;
    long m_hours, m_flow;
    // String m_status;
    std::string m_status;

    while(r != 0x0A)
    {
      if (_rx->available())
      {
        // receive byte
        r = _rx->read();
        if (parity_check(r))
        {
           parityerrors += 1;
        }
        r = r & 127; // Mask MSB to remove parity

        message[i++] = char(r);                

      }
      else
      {
        to++;
        delay(25);
      }

      if (i>=81)
      {
        if ( parityerrors == 0 )
        {
//          Serial.print("OK: " );

          message[i] = 0;

          tmpstr = strtok(message, " ");

          if (tmpstr)
           // m_energy = atol(tmpstr)/1000.0;
           m_energy = atol(tmpstr)/3.6;
          else
           m_energy = 0;

          tmpstr = strtok(NULL, " ");
          if (tmpstr)
           m_volume = atol(tmpstr)/100.0;
          else
           m_volume = 0;

          tmpstr = strtok(NULL, " ");
          if (tmpstr)
           m_hours = atol(tmpstr);
          else
           m_hours = 0;

          tmpstr = strtok(NULL, " ");
          if (tmpstr)
            m_tempin = atol(tmpstr)/100.0;
          else
            m_tempin = 0;

          tmpstr = strtok(NULL, " ");
          if (tmpstr)
           m_tempout = atol(tmpstr)/100.0;
          else
           m_tempout = 0;

          tmpstr = strtok(NULL, " ");
          if (tmpstr)
           m_tempdiff = atol(tmpstr)/100.0;
          else
           m_tempdiff = 0;

          tmpstr = strtok(NULL, " ");
          if (tmpstr)
           m_power = atol(tmpstr)/10.0;
          else
           m_power = 0;

          tmpstr = strtok(NULL, " ");
          if (tmpstr)
           m_flow = atol(tmpstr);
          else
           m_flow = 0;    

          ESP_LOGD("multical", "Energy: %f kWh", m_energy);  

          ESP_LOGD("multical", "Volume: %f m3", m_volume); 

          ESP_LOGD("multical", "Time: %ld hrs", m_hours); 

          ESP_LOGD("multical", "T_in: %f", m_tempin); 

          ESP_LOGD("multical", "T_out: %f", m_tempout); 

          ESP_LOGD("multical", "T_diff: %f", m_tempdiff); 

          ESP_LOGD("multical", "Power: %f", m_power); 

          ESP_LOGD("multical", "Flow: %ld l/h", m_flow); 

          m_status = "OK";

          sensor_energy->publish_state(m_energy);
          sensor_volume->publish_state(m_volume);
          sensor_tempin->publish_state(m_tempin);
          sensor_tempout->publish_state(m_tempout);
          sensor_tempdiff->publish_state(m_tempdiff);
          sensor_power->publish_state(m_power);
          sensor_flow->publish_state(m_flow);

        }
        else
        {
          message[i] = 0;
          ESP_LOGD("multical", "ERR(PARITY): %f", message); 
          m_status = "ERR(PARITY)";
        }
        break;
      } 
      if (to>100)
      {
        message[i] = 0;
        ESP_LOGD("multical", "ERR(TIMEOUT): %f", message); 
        m_status = "ERR(TIMEOUT)";
        break;
      }
    }

    textsensor_status->publish_state(m_status);

  }
 private:
  bool parity_check(unsigned input) {
    bool inputparity = input & 128;
    int x = input & 127;

    int parity = 0;
    while(x != 0) {
        parity ^= x;
        x >>= 1;
    }

    if ( (parity & 0x1) != inputparity )
      return(1);
    else
      return(0);
  }
//  Sensor *temperature_sensor = new Sensor();
  UARTDevice *_tx;
  UARTDevice *_rx;  

};
JeroenVanOort commented 1 year ago

It should work...

Can you be more specific about UART's not functioning? It would be helpful to know if it is RX and or TX not working in all three cases. Maybe you could do some measurements with a USB-serial-converter/logic analyser/scope.

ssieb commented 1 year ago

In order to use 3 uarts, one of them has to use the default pins for UART0.

jeroen85 commented 1 year ago

In order to use 3 uarts, one of them has to use the default pins for UART0.

It looks like you are correct here. Previously the YAML below was not working (last UART config; TX to my Multical was not functioning). When I change the pin of my first UART instance from GPIO23 to GPIO3, my Multical setup is (also) working :-)

uart:    
#Uart for DSMR P1-meter    
- rx_pin: GPIO3
 #rx_pin: GPIO23
  baud_rate: 115200
  id: uart_dsmr
  rx_buffer_size: 1700

#Multical UART, 2 instances due to different baud-rates.
- rx_pin: GPIO22
  baud_rate: 1200
  data_bits: 8
  parity: NONE
  stop_bits: 1
  id: uart_rx
- tx_pin: GPIO21
  baud_rate: 300
  data_bits: 8
  parity: NONE
  stop_bits: 1
  id: uart_tx   

Documentation seems to be be wrong in this case: The ESP32 has three UARTs. Any pair of GPIO pins can be used, as long as they support the proper output/input modes.

arpiecodes commented 1 year ago

Just wondering if there is a way to solve this without changing the pins to the default for UART0? I am attempting to create an ESPHome set-up with off-the-shelf devices that do not follow the original pinout and where I cannot rearrange them. Same UART configuration utilising all three UART's with the custom pins work well in Arduino-based project, but not in ESPHome. Would be great if we could make this possible.

github-actions[bot] commented 1 year ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

jeroen85 commented 1 year ago

Not solved.