Esphome read UART data and use it as sensor (Qoltec 6KW)

Hi,

I have connected esp32 to rs232 and i get some connection/reply with PV inverter.

Thats my code:

button:
  - platform: template
    name: "QPIRI"
    on_press:
      - uart.write: [0x51, 0x50, 0x49, 0x52, 0x49, 0xF8, 0x54, 0x0D]
      - delay: 1s
  - platform: template
    name: "QPIGS"
    on_press:
      - uart.write: [0x51, 0x50, 0x49, 0x47, 0x53, 0xB7, 0xA9, 0x0D]
      - delay: 1s

Replay what i get:

[D][button:010]: 'QPIGS' Pressed.
[D][uart_debug:158]: >>> "QPIGS\xB7\xA9\r"
[D][uart_debug:158]: <<< "(236.6 50.0 236.6 50.0 0165 0000 002 391 03.30 000 000 0018 00.0 117.0 00.00 00000 00010000 00 00 00000 011 0 00 0000\xC7\xB0\r"

And need to use replay string as multiple sensors to print on web and homeassistant.

I found on other post command like that:

uart:
  baud_rate: 2400
  tx_pin: 16
  rx_pin: 17
  id: UART3
  debug:
    direction: BOTH
    dummy_receiver: true
    after:
      delimiter: "\r\n"
    sequence:
      - lambda: |-
          UARTDebug::log_string(direction, bytes);
          int sensorID=0;
          float sensorTEMP=0; 
          std::string str(bytes.begin(), bytes.end());
          
          //there are 4 sensors
          //where<<< id:temperature:humidity
          //"3:37.86:10\r\n"
          if (sscanf(str.c_str(), "%d:%f:%f", &sensorID, &sensorTEMP, &sensorRH) == 3 ) {
            if(sensorID==1) {
              id(temp1).publish_state(sensorTEMP); 
            }
            if(sensorID==2) {
              id(temp2).publish_state(sensorTEMP); 
            }
          }

sensor:
  - platform: template
    name: "Temp 1"
    id: "temp1"
  - platform: template
    name: "Temp 2"
    id: "temp2"

But dont know how to format it properly.

Im trying like that:

uart:
  baud_rate: 2400
  tx_pin: 16
  rx_pin: 17
  id: UART3
  debug:
    direction: BOTH
    dummy_receiver: true
    after:
      delimiter: "\r\n"
    sequence:
      - lambda: |-
          UARTDebug::log_string(direction, bytes);
          int sensorID=0;
          float sensor_inverter_1=0;
          float sensor_inverter_2=0; 
          std::string str(bytes.begin(), bytes.end());
          
          //there are 4 sensors
          //where<<< id:temperature:humidity
          //"3:37.86:10\r\n"

          if (sscanf(str.c_str(), "%d:%f:%f", &sensorID, &sensor_inverter_1, &sensor_inverter_2) != 3 ) {
            if(sensorID!=0) {
              id(inverter_1).publish_state(sensor_inverter_1);
              id(inverter_2).publish_state(sensor_inverter_2);
            }
          }

sensor:
  - platform: template
    name: "1"
    id: "inverter_1"
  - platform: template
    name: "2"
    id: "inverter_2"

But not working

The "%d:%f:%f" in the sscanf function needs to be formatted to parse the expected reply from the inverter.

Based on your sample response
[D][uart_debug:158]: <<< "(236.6 50.0 236.6 50.0 0165 0000 002 391 03.30 000 000 0018 00.0 117.0 00.00 00000 00010000 00 00 00000 011 0 00 0000\xC7\xB0\r"

So "(%f %f %f %f" for the scanf format should convert the leading “(” and first 4 floats values to number you can use to publish the sensors.

logger:
  baud_rate: 0
  level: DEBUG

uart:
  baud_rate: 2400
  tx_pin: 16
  rx_pin: 17
  id: uart_inverter
  debug:
    direction: BOTH
    dummy_receiver: true
    after:
      delimiter: "\r\n"
    sequence:
      - lambda: |-
          UARTDebug::log_string(direction, bytes);
          float s1=0;
          float s2=0;
          float s3=0;
          float s4=0;
          float s5=0;
          float s6=0;
          float s7=0;
          float s8=0;
          float s9=0;
          float s10=0;
          float s11=0;
          float s12=0;
          float s13=0;
          float s14=0;
          float s15=0;
          float s16=0;
          float s17=0;
          float s18=0;
          float s19=0;
          float s20=0;
          float s21=0;
          float s22=0;
          float s23=0;
          float s24=0;
          std::string str(bytes.begin(), bytes.end());

          if (sscanf(str.c_str(), "(%f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f", &s1, &s2, &s3, &s4, &s5, &s6, &s7, &s8, &s9, &s10, &s11, &s12, &s13, &s14, &s15, &s16, &s17, &s18, &s19, &s20, &s21, &s22, &s23, &s24) ) {
            id(inverter_1).publish_state(s1);
            id(inverter_2).publish_state(s2);
            id(inverter_3).publish_state(s3);
            id(inverter_4).publish_state(s4);
            id(inverter_5).publish_state(s5);
            id(inverter_6).publish_state(s6);
            id(inverter_7).publish_state(s7);
            id(inverter_8).publish_state(s8);
            id(inverter_9).publish_state(s9);
            id(inverter_10).publish_state(s10);
            id(inverter_11).publish_state(s11);
            id(inverter_12).publish_state(s12);
            id(inverter_13).publish_state(s13);
            id(inverter_14).publish_state(s14);
            id(inverter_15).publish_state(s15);
            id(inverter_16).publish_state(s16);
            id(inverter_17).publish_state(s17);
            id(inverter_18).publish_state(s18);
            id(inverter_19).publish_state(s19);
            id(inverter_20).publish_state(s20);
            id(inverter_21).publish_state(s21);
            id(inverter_22).publish_state(s22);
            id(inverter_23).publish_state(s23);
            id(inverter_24).publish_state(s24);
          }

sensor:
  # AC IN
  - platform: template
    name: "inverter_ac_in_voltage"
    id: "inverter_1"
    device_class: voltage
    unit_of_measurement: 'V'
  - platform: template
    name: "inverter_ac_in_frequency"
    id: "inverter_2"
    device_class: frequency
    unit_of_measurement: 'Hz'
  # AC OUT
  - platform: template
    name: "inverter_ac_out_voltage"
    id: "inverter_3"
    device_class: voltage
    unit_of_measurement: 'V'
  - platform: template
    name: "inverter_ac_out_frequency"
    id: "inverter_4"
    device_class: frequency
    unit_of_measurement: 'Hz'
  - platform: template
    name: "inverter_ac_out_apparent_power"
    id: "inverter_5"
    device_class: apparent_power
    unit_of_measurement: 'VA'
  - platform: template
    name: "inverter_ac_out_active_power"
    id: "inverter_6"
    device_class: power
    unit_of_measurement: 'W'
  # BUS
  - platform: template
    name: "inverter_bus_utilization"
    id: "inverter_7"
    unit_of_measurement: '%'
  - platform: template
    name: "inverter_bus_voltage"
    id: "inverter_8"
    device_class: voltage
    unit_of_measurement: 'V'
  # BATTERY
  - platform: template
    name: "inverter_battery_voltage"
    id: "inverter_9"
    device_class: voltage
    unit_of_measurement: 'V'
  - platform: template
    name: "inverter_battery_ac_charging_current"
    id: "inverter_10"
    device_class: current
    unit_of_measurement: 'A'
  - platform: template
    name: "inverter_battery_capacity"
    id: "inverter_11"
    device_class: battery
    unit_of_measurement: '%'
  # TEMPERATURE
  - platform: template
    name: "inverter_temperature"
    id: "inverter_12"
    device_class: temperature
    unit_of_measurement: '°C'
  # PV
  - platform: template
    name: "inverter_battery_pv_charging_current"
    id: "inverter_13"
    device_class: current
    unit_of_measurement: 'A'
  - platform: template
    name: "inverter_pv_in_voltage"
    id: "inverter_14"
    device_class: voltage
    unit_of_measurement: 'V'
  # BATTERY
  - platform: template
    name: "inverter_battery_voltage_scc"
    id: "inverter_15"
    device_class: voltage
    unit_of_measurement: 'V'
  - platform: template
    name: "inverter_battery_discharge_current"
    id: "inverter_16"
    device_class: current
    unit_of_measurement: 'A'
  # ???
  - platform: template
    name: "inverter_17"
    id: "inverter_17"
  - platform: template
    name: "inverter_18"
    id: "inverter_18"
  - platform: template
    name: "inverter_19"
    id: "inverter_19"
  - platform: template
    name: "inverter_20"
    id: "inverter_20"
  - platform: template
    name: "inverter_21"
    id: "inverter_21"
  - platform: template
    name: "inverter_22"
    id: "inverter_22"
  - platform: template
    name: "inverter_23"
    id: "inverter_23"
  - platform: template
    name: "inverter_24"
    id: "inverter_24"


button:
  - platform: template
    name: "Send QPIRI"
    on_press:
      - uart.write: [0x51, 0x50, 0x49, 0x52, 0x49, 0xF8, 0x54, 0x0D]
  - platform: template
    name: "Send QPIGS"
    on_press:
      - uart.write: [0x51, 0x50, 0x49, 0x47, 0x53, 0xB7, 0xA9, 0x0D]


interval:
  - interval:
      seconds: 30
    then:
      # Send QPIGS
      - uart.write: [0x51, 0x50, 0x49, 0x47, 0x53, 0xB7, 0xA9, 0x0D]

Thats part of new code
But i dont like the output

[D][uart_debug:158]: >>> "QPIGS\xB7\xA9\r"
[D][uart_debug:158]: <<< "(235.0 50.1 235.0 50.1 0000 0000 000 303 03.00 000 000 0017 00.0 000.0 00.00 00000 00010000 00 00 00000 011 0 00 0000\x98n\r"
[D][sensor:094]: 'inverter_ac_in_voltage': Sending state 235.00000 V with 1 decimals of accuracy
[D][sensor:094]: 'inverter_ac_in_frequency': Sending state 50.10000 Hz with 1 decimals of accuracy
[D][sensor:094]: 'inverter_ac_in_frequency': Sending state 50.10000 Hz with 1 decimals of accuracy
[D][sensor:094]: 'inverter_ac_out_voltage': Sending state 235.00000 V with 1 decimals of accuracy
[D][sensor:094]: 'inverter_ac_out_frequency': Sending state 50.10000 Hz with 1 decimals of accuracy
[D][sensor:094]: 'inverter_ac_out_apparent_power': Sending state 0.00000 VA with 1 decimals of accuracy
[D][sensor:094]: 'inverter_ac_out_active_power': Sending state 0.00000 W with 1 decimals of accuracy
[D][sensor:094]: 'inverter_bus_utilization': Sending state 0.00000 % with 1 decimals of accuracy
[D][sensor:094]: 'inverter_bus_voltage': Sending state 303.00000 V with 1 decimals of accuracy
[D][sensor:094]: 'inverter_battery_voltage': Sending state 3.00000 V with 1 decimals of accuracy
[D][sensor:094]: 'inverter_battery_voltage': Sending state 3.00000 V with 1 decimals of accuracy
[D][sensor:094]: 'inverter_battery_ac_charging_current': Sending state 0.00000 A with 1 decimals of accuracy
[D][sensor:094]: 'inverter_battery_capacity': Sending state 0.00000 % with 1 decimals of accuracy
[D][sensor:094]: 'inverter_temperature': Sending state 17.00000 °C with 1 decimals of accuracy
[D][sensor:094]: 'inverter_battery_pv_charging_current': Sending state 0.00000 A with 1 decimals of accuracy
[D][sensor:094]: 'inverter_pv_in_voltage': Sending state 0.00000 V with 1 decimals of accuracy
[D][sensor:094]: 'inverter_battery_voltage_scc': Sending state 0.00000 V with 1 decimals of accuracy
[D][sensor:094]: 'inverter_battery_discharge_current': Sending state 0.00000 A with 1 decimals of accuracy
[D][sensor:094]: 'inverter_17': Sending state 10000.00000  with 1 decimals of accuracy
[D][sensor:094]: 'inverter_21': Sending state 0.00000  with 1 decimals of accuracy
[D][sensor:094]: 'inverter_18': Sending state 0.00000  with 1 decimals of accuracy
[D][sensor:094]: 'inverter_19': Sending state 0.00000  with 1 decimals of accuracy
[D][sensor:094]: 'inverter_20': Sending state 0.00000  with 1 decimals of accuracy
[D][sensor:094]: 'inverter_23': Sending state 0.00000  with 1 decimals of accuracy
[W][component:232]: Component uart took a long time for an operation (369 ms).
[W][component:233]: Components should block for at most 30 ms.
[D][uart_debug:158]: <<< "(NAKss\r"
[D][uart_debug:158]: <<< "(NAKss\r"
[D][uart_debug:158]: <<< "(NAKss\r"
[D][uart_debug:158]: <<< "(NAKss\r"
[D][uart_debug:158]: <<< "(NAKss\r"

Why i get multiple “(NAKss\r” replay back? Do i send something more?

Or esp32 is too slow for that? and will be better to pass that string to nodered?

Lot of garbage

[W][component:232]: Component uart took a long time for an operation (1660 ms).
[W][component:233]: Components should block for at most 30 ms.
[D][uart_debug:158]: <<< "(NAKss\r(NAKss\r(NAKss\r(NAKss\r(NAKss\r(NAKss\r(NAKss\r(NAKss\r(NAKss\r(NAKss\r(NAKss\r"
[D][uart_debug:158]: <<< "(NAKss\r"
[D][uart_debug:158]: <<< "(NAKss\r"
[D][uart_debug:158]: <<< "(NAKss\r"
[D][uart_debug:158]: <<< "(NAKss\r"
[D][uart_debug:158]: >>> "QPIGS\xB7\xA9\r"
[D][uart_debug:158]: <<< "(NAKss\r"
logger:
  baud_rate: 0
  level: DEBUG

uart:
  baud_rate: 2400
  tx_pin: 16
  rx_pin: 17
  id: uart_bus

text_sensor:
- platform: custom
  lambda: |-
    auto my_custom_sensor = new UartReadLineSensor(id(uart_bus));
    App.register_component(my_custom_sensor);
    return {my_custom_sensor};
  text_sensors:
    id: "uart_readline"
    name: "inverter_uart"

interval:
  - interval:
      seconds: 5
    then:
      # Send QPIGS
      - uart.write: [0x51, 0x50, 0x49, 0x47, 0x53, 0xB7, 0xA9, 0x0D]
[D][text_sensor:064]: 'inverter_uart': Sending state '(236.6 49.9 236.6 49.9 0189 0050 003 305 03.00 000 000 0017 00.0 000.0 00.00 00'
[D][text_sensor:064]: 'inverter_uart': Sending state '(236.1 49.9 236.1 49.9 0000 0000 000 304 03.00 000 000 0017 00.0 000.0 00.00 00'
[D][text_sensor:064]: 'inverter_uart': Sending state '(236.0 49.9 236.0 49.9 0165 0046 002 304 03.00 000 000 0017 00.0 000.0 00.00 00'
[D][text_sensor:064]: 'inverter_uart': Sending state '(236.0 49.9 236.0 49.9 0000 0000 000 303 03.00 000 000 0017 00.0 000.0 00.00 00'
[D][text_sensor:064]: 'inverter_uart': Sending state '(236.1 49.9 236.1 49.9 0212 0080 003 303 03.00 000 000 0017 00.0 000.0 00.00 00'

its much more cleaner and lightweight

Direction should be just RX, otherwise all the TX messages get logged and attempted to process.

Delimiter should just be ‘\r’ so each message triggers debug lambda separately. There are no ‘\r\n’ in the response samples posted, so debug lambda gets triggered via the timeout

Hello,
I have a little problem with the decimals in uart. I need at least 3 decimal places. What is wrong here? I can’t get any decimal places. I’m a beginner and can’t find the error.

uart:
  id: uart_bus
  tx_pin: GPIO2
  rx_pin: GPIO14
  baud_rate: 9600
  stop_bits: 1
  data_bits: 8
  debug:
    direction: BOTH
    dummy_receiver: true
    after:
      delimiter: "\r\n"
    sequence:
    - lambda: |-
       UARTDebug::log_string(direction, bytes);
         int val1=1;
         std::string str(bytes.begin(), bytes.end());

       if (sscanf(str.c_str(), "%d", &val1) == 1 ) {
       id(voltage).publish_state(val1);
          }