ESPHome Ultrasonic sensor SR04T via UART

Hi HA users!

I’m trying to get my ultrasonic sensor to work with ESPHome. The sensor is a JSN-SR04T-AJ-SR04M which is similar to the HC-SR04 but not exactly the same. So using the default ESPHome template ‘ultrasonic’ doesn’t work (wrong distance values are show, only 2 out of 10measurements are somewhat correct).

The SR04 has different modes, I soldered a 47kΩ resistor into the R27 Pin to enable the “contious mode”. In this mode the distance calculation is done on device all the time. To get the distance on can use the UART to retrieve the data.

Now I’m struggling with implementing this in ESPHome. I read that it is possible to add custom UART components, but I’m not sure if this is necessary in my case, or if I’m able to just receive the data using the regular uart integration.
The code to read the data from the sensor every two seconds looks like this in Python:

import serial
import time
import sys
ser = serial.Serial('/dev/ttyUSB0')  # open serial port
byte = b'\xff' # xff is the start byte
while True:
    x = ser.read()
    if x == byte: #starbyte found
        b1 = ser.read(1)
        b2 = ser.read(1)
        x1 = int.from_bytes(b1, sys.byteorder)
        dist = (((x1 << 8) + int.from_bytes(b2, sys.byteorder)) / 10) # some bitshift magic, no idea what's happening here
        print(dist - 5) # for some reason the distance value is 5cm off, remove them before printing the value
        clear = ser.read_all()
        ser.flushOutput()
    time.sleep(2)

There is also a german blogpost with some arduino examples for the different modes of the sensor, which I used to implement my python example above:

I hope that someone could give me a hint in the right direction since I’m not an arduino pro as you can probably see, thanks in advance for helping me out :slight_smile:

I faced the same challenge. Here my solution based on a custom sensor. Hope it will help you out…

esphome:
  name: test-level
  includes:
    - AJ_SR04M_Sensor.h

uart:
  id: uart_bus
  tx_pin: GPIO14
  rx_pin: GPIO12
  baud_rate: 9600
  stop_bits: 1

sensor:
- platform: custom
  lambda: |-
    auto my_sensor = new AJ_SR04M_Sensor(id(uart_bus));
    App.register_component(my_sensor);
    return {my_sensor};
  sensors:
    unit_of_measurement: cm
    accuracy_decimals: 1
    name: "Distance"

AJ_SR04M_Sensor.h:

#include "esphome.h"
 
class AJ_SR04M_Sensor : public PollingComponent, public UARTDevice, public Sensor {
 public:

  AJ_SR04M_Sensor(UARTComponent *parent) : PollingComponent(5000), UARTDevice(parent) {}

// AJ_SR04M_Sensor format:
// Trigger: 0x00
// Response: Byte1          Byte2  Byte3  Byte4               Byte5
//           Start Byte=FF  MSB    LSB    Checksum (LSB+MSB)  00

  void update() override {
  
    char frame[5];
    int pos = 0;
    float value = 0.0;

    write(0x00);
    while (available()) {
      frame[pos] = read();
      pos++;
      if(pos==5) {
        if ((frame[0] == 0xFF) && (frame[4] == 0x00) && ((frame[1]+frame[2])==frame[3])) {
          value = ((frame[1]<<8) + frame[2]) / 10.0;
          publish_state(value);
        }
        break;
      }
    }
  }
};

The update interval is fixed to 5 seconds but you can change it accordingly.

1 Like

Hi,
I am trying to use your code but the sensor is not updated.

Distance
Unknown

Any tips?

I managed to make it work:


#include "esphome.h"

class AJ_SR04M_Sensor : public PollingComponent, public UARTDevice, public Sensor {
  public:

    AJ_SR04M_Sensor(UARTComponent *parent) : PollingComponent(1000), UARTDevice(parent) {}

    void update() override {

      byte frame[5];
      int pos = 0;
      float value = 0.0;

      //write(0x00); // Try this
      write(0x55); // Try this
      //write(0x01); // Try this
      while (available()) {

        frame[pos] = read();

        pos++;

        if (pos == 4) {

	  if ((frame[0] == 0xFF) && (frame[4] == 0x00) && (((frame[0] + frame[1] + frame[2]) & 0x00ff) == frame[3])){
            value = ((frame[1] << 8) + frame[2]) / 10.0;
            publish_state(value);
          }
          break;


        }
      }
    }
};