mmWave Presence Detection - ESPHome style

You mean this!!?

text_sensor:
  - platform: template
    name: uptime_human_readable
    id: uptime_human_readable
    icon: mdi:clock-start
    update_interval: 60s

On my computer of course! Dunno where that bit went when copy/paste. It isn’t required for the sensor in any way.

Likely have an update tomorrow with additional configuration parameter synchronization once I have a good day under my belt…

1 Like

Hi, so with the proposed orientation (GPIO pins on the bottom, 3pads up, 2 pads wide) the 100° are horizontal and 40° vertical? thanks for clearing this up

So I adapted the config from top to my because I attached some other sensor too. Like PIR, temp and others. The mmWave sensor detects if someone is there, great. But I can not make the configuration work. SO I can change sensitivity, distance, led but nothing changes. When clicking the buttons for get range, get latency they show nothing. As far as I understood they should show the saved values, right?

Can someone check my config if I missed something? The config runs without other problems, only while compiling I get a warning about “$JYRPO”.

Also num_targets stays at 0.0 even if move sensor goes to “on” because someone was detects. Same for target distance.

Here is my code

substitutions:
  device_name: workingroom

esphome:
  name: workingroom-multisensor
  platform: ESP32
  board: esp32dev
  includes:
    - uart_read_line_sensor.h # https://esphome.io/cookbook/uart_text_sensor.html


# Enable logging
logger:
  logs:
    text_sensor: INFO
    sensor: INFO

# Enable Home Assistant API
api:
  services:
      # Service to send a command directly to the display. Useful for testing
    - service: send_command
      variables:
        cmd: string
      then:
        - uart.write: !lambda
            std::string command = to_string(cmd) +"\r";
            return std::vector<uint8_t>(command.begin(), command.end());

http_request:
  useragent: esphome/${device_name}
  timeout: 2s

ota:
  password: "xxxxxxxxxxxxxxxxxxxxxxxx"

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "${device_name}-Multisensor"
    password: "xxxxxxxxxxxxxxxxxxxxxxxx"

captive_portal:

web_server:
  port: 80
  version: 2
  include_internal: true
  ota: true

uart:
  id: uart_bus
  tx_pin: GPIO19
  rx_pin: GPIO18
  baud_rate: 115200
  debug:
    direction: BOTH
    after:
      delimiter: "\n"
    sequence:
      - lambda: UARTDebug::log_string(direction, bytes);


i2c:
  sda: GPIO21
  scl: GPIO22
  scan: true

sensor:
  - platform: bme280
    temperature:
      name: "${device_name} Temperature"
      oversampling: 16x
    pressure:
      name: "${device_name} Pressure"
    humidity:
      name: "${device_name} Humidity"
    address: 0x76
    update_interval: 60s
  - platform: bh1750
    name: "${device_name} Illuminance"
    address: 0x23
    update_interval: 1s
    filters:
    - or:
      - throttle: 10s
      - delta: 1.0

  - platform: template
    name: target_1_distance_m
    id: target_1_distance_m
    internal: true

  - platform: template
    name: target_2_distance_m
    id: target_2_distance_m
    internal: true

  - platform: template
    name: target_3_distance_m
    id: target_3_distance_m
    internal: true

  - platform: template
    name: target_4_distance_m
    id: target_4_distance_m
    internal: true

  - platform: template
    name: target_1_SNR
    id: target_1_SNR
    internal: true

  - platform: template
    name: target_2_SNR
    id: target_2_SNR
    internal: true

  - platform: template
    name: target_3_SNR
    id: target_3_SNR
    internal: true

  - platform: template
    name: target_4_SNR
    id: target_4_SNR
    internal: true

  - platform: template
    name: num_targets
    id: num_targets
    # internal: true

binary_sensor:
  - platform: gpio
    pin: GPIO23
    filters:
      - delayed_on: 100ms
      - delayed_off: 2000ms
    name: "${device_name} PIR Sensor"
    device_class: motion

  - platform: gpio
    name: mmwave_in_${device_name}
    id: mmwave_in_${device_name}
    pin:
      number: GPIO23
      mode: INPUT_PULLDOWN
    on_state:
    - if:
        condition:
          - binary_sensor.is_off: mmwave_in_${device_name}
        then:
          - sensor.template.publish:
              id: target_1_distance_m
              state: 0.0
          - sensor.template.publish:
              id: target_1_SNR
              state: 0.0
          - sensor.template.publish:
              id: num_targets
              state: 0.0

switch:
  - platform: safe_mode
    name: use_safe_mode
    entity_category: diagnostic

  - platform: template
    name: mmwave_sensor
    id: mmwave_sensor
    entity_category: config
    optimistic: true
    restore_state: true
    assumed_state: true
    turn_on_action:
      - uart.write: "sensorStart"
    turn_off_action:
      - uart.write: "sensorStop"

  - platform: template
    name: led
    id: "led"
    entity_category: config
    optimistic: true
    restore_state: true
    assumed_state: true
    turn_on_action:
      - switch.turn_off: mmwave_sensor
      - delay: 1s
      - uart.write: "setLedMode 1 0"
      - delay: 1s
      - uart.write: "saveConfig"
      - delay: 3s
      - switch.turn_on: mmwave_sensor
      - delay: 1s
    turn_off_action:
      - switch.turn_off: mmwave_sensor
      - delay: 1s
      - uart.write: "setLedMode 1 1"
      - delay: 1s
      - uart.write: "saveConfig"
      - delay: 3s
      - switch.turn_on: mmwave_sensor
      - delay: 1s

  - platform: template
    name: uart_presence_output
    id: uart_presence_output
    entity_category: diagnostic
    optimistic: true
    restore_state: true
    assumed_state: true
    turn_on_action:
      - switch.turn_off: mmwave_sensor
      - delay: 1s
      - uart.write: "setUartOutput 1 1"
      - delay: 1s
      - uart.write: "saveConfig"
      - delay: 3s
      - switch.turn_on: mmwave_sensor
      - delay: 1s
    turn_off_action:
      - switch.turn_off: mmwave_sensor
      - delay: 1s
      - uart.write: "setUartOutput 1 0"
      - delay: 1s
      - uart.write: "saveConfig"
      - delay: 3s
      - switch.turn_on: mmwave_sensor
      - delay: 1s

  - platform: template
    name: uart_target_output
    id: uart_target_output
    entity_category: diagnostic
    optimistic: true
    restore_state: true
    assumed_state: false
    turn_on_action:
      - switch.turn_off: mmwave_sensor
      - delay: 1s
      - uart.write: "setUartOutput 1 0"
      - delay: 1s
      - uart.write: "setUartOutput 2 1 1 3"
      - delay: 1s
      - uart.write: "saveConfig"
      - delay: 3s
      - switch.turn_on: mmwave_sensor
      - delay: 1s
    turn_off_action:
      - switch.turn_off: mmwave_sensor
      - delay: 1s
      - uart.write: "setUartOutput 2 0"
      - delay: 1s
      - uart.write: "saveConfig"
      - delay: 3s
      - switch.turn_on: mmwave_sensor
      - delay: 1s

number:
  - platform: template
    name: distance
    id: distance
    entity_category: config
    min_value: 0.15
    max_value: 9.45
    initial_value: 3.15
    optimistic: true
    step: 0.15
    restore_value: true
    unit_of_measurement: M
    mode: box
    set_action:
      - switch.turn_off: mmwave_sensor
      - delay: 1s
      - uart.write: !lambda
            std::string range = "setRange 0 " + str_sprintf("%.2f", x);
            return std::vector<unsigned char>(range.begin(), range.end());
      - delay: 1s
      - uart.write: "saveConfig"
      - delay: 1s
      - switch.turn_on: mmwave_sensor
      - delay: 1s

  - platform: template
    name: latency
    id: latency
    entity_category: config
    min_value: 1
    max_value: 600
    initial_value: 90
    optimistic: true
    step: 1
    restore_value: true
    unit_of_measurement: s
    mode: box
    set_action:
      - switch.turn_off: mmwave_sensor
      - delay: 1s
      - uart.write: !lambda
            std::string setL = "setLatency 0.1 " + str_sprintf("%.0f", x);
            return std::vector<unsigned char>(setL.begin(), setL.end());
      - delay: 1s
      - uart.write: "saveConfig"
      - delay: 1s
      - switch.turn_on: mmwave_sensor

  - platform: template
    name: sensitivity
    id: sensitivity
    entity_category: config
    min_value: 0
    max_value: 9
    initial_value: 9
    optimistic: true
    step: 1
    restore_value: true
    set_action:
      - switch.turn_off: mmwave_sensor
      - delay: 1s
      - uart.write: !lambda
            std::string mss = "setSensitivity " + to_string((int)x);
            return std::vector<unsigned char>(mss.begin(), mss.end());
      - delay: 1s
      - uart.write: "saveConfig"
      - delay: 1s
      - switch.turn_on: mmwave_sensor

button:
  - platform: restart
    name: Restart $device_name
    entity_category: diagnostic

  - platform: template
    name: getSensitivity_$device_name
    entity_category: diagnostic
    internal: true
    on_press:
    - uart.write: !lambda
          std::string getS = "getSensitivity";
          return std::vector<unsigned char>(getS.begin(), getS.end());

  - platform: template
    name: getLatency_$device_name
    entity_category: diagnostic
    internal: true
    on_press:
    - uart.write: !lambda
          std::string getL = "getLatency";
          return std::vector<unsigned char>(getL.begin(), getL.end());

  - platform: template
    name: getRange_$device_name
    entity_category: diagnostic
    internal: true
    on_press:
    - uart.write: !lambda
          std::string getR = "getRange";
          return std::vector<unsigned char>(getR.begin(), getR.end());

  - platform: template
    name: factory_reset_dfrobot
    id: factory_reset_dfrobot
    entity_category: config
    on_press:
      - switch.turn_off: mmwave_sensor
      - delay: 1s
      - uart.write: "resetCfg"
      - delay: 3s
      - switch.turn_on: mmwave_sensor

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
      internal: true
      on_value:
        lambda: |-
          std::string line = id(uart_readline).state;
          if (id(uart_target_output).state && line.substr(0, 6) == "$JYRPO")
          {
              auto publishTarget = [](std::string idx, float dist, float snr) {
                  auto sens = App.get_sensors();
                  for(int i = 0; i < sens.size(); i++) {
                    auto name = sens[i]->get_name();
                    auto target = "target_" + to_string(idx);
                    if(name.size() > 10 && name.substr(0, 8) == target) {
                      if(name.substr(9, 3) == "dis") {
                        sens[i]->publish_state(dist);
                      } else if(name.substr(9, 3) == "SNR") {
                        sens[i]->publish_state(snr);
                      }
                    }
                  }
              };

              line = line.substr(6);
              std::vector<std::string> v;
              for(int i = 0; i < line.length(); i++) {
                  if(line[i] == ',') {
                      v.push_back("");
                  } else {
                      v.back() += line[i];
                  }
              }

              id(num_targets).publish_state(parse_number<float>(v[0]).value());

              publishTarget(v[1], parse_number<float>(v[2]).value(), parse_number<float>(v[4]).value());
              for(int i = parse_number<int>(v[0]).value() +1 ; i < 9; i++) publishTarget(to_string(i), 0, 0);
          }

Checked your RX/TX. Turn on uart_target_output, do you see output on the logs?

Sounds like your RX/TX are not correct. You will see a response in the logs.

All symptoms points to incorrect RX/TX.

The RX/TX can be just free GPIO Pins correct? Or do I need to use the TX/RX on my board? Because I only got it working when the TX/RX are from free GPIO Pins

The answer may depend on the specifics of your board…

So all good now?

No, it is still the same, not sure what GPIO Ports I should use for the TX/RX. Does it have to be the designated from board or can I use free GPIO Pins?

I have this esp32dev board. I only got the mmWave sensor working when I use free gpis pins but then the config, buttons, target data does not show up. Any hint what ports are the correct ones?

And I only use the “102” port on the mmWave sensor to connect to my esp32. Do I need the other too? I saw nowhere that both GPIO are configured.

IO2 on the mmWave sensor is purely binary. It goes high if it senses motion and low when it stops. In order to read/change the configuration on the sensor you also need to connect TX/RX to UART TX/RX on the ESP32. Depending on the board you can use other GPIOs for UART TX/RX, but generally I use pins labeled TX/RX if they’re there.

Hope this pictures make it more clear, I use tx/rx pins and also tried the other tx/rx on the board same for just on 25/26 as tx/rx. But the buttons never return values. Config (distance/sensitivity) does not change and also the num_targets or target_1_xxx show no values.

The part_readline is mostly empty, I had it between that it show the number 1 but nothing more.

Swapped out a DFRobot (aka HS2A43A 100×40) for a HS2BC3A (1x0×1x0) today and all working as expected :wink:

The datasheet says 110x120 but Ali seller notes 100x100 so testing is in order…

TX goes to RX and vice versa :wink:

Wait what? :sweat_smile: so tx from mmWave should be Rx on esp?

That’s it :+1:

Noob mistake, don’t feel bad… I ended up buying a USB to TTL because I was doing my connections wrong with my ESP :joy:

So just got my DFRobot sensor and going to solder this up this weekend.

Am I missing something, someone mentioned a wiring diagram that was in the OP, but I cant see it. And people talking about putting this on Github.

Has that happened and I missed it? Is the OP the best YAML to grab? Wiring diagram?

Also hooked up an Acura FP1 this week, that thing is so sensitive that it thinks my Echo Show playing music is enough movement to constitute occupancy LOL

A big shout-out to @hjmcnew for providing us with a simplied installation method (in the OP).

2 Likes

Hi there.

I have set the latency to 1sec. but it turn off in 10sec. How can i change it to turn off immediately?

Reduce the latency.

Check your UART wiring/configuration. Correct UART communication is required for distance/latency/sensitivity/LED changes.

The latency i have changed to 1 sec and the UART is working. I can change the LED on/off. But it turns off in 4-6 seconds. Well I saw in the video of Everything Smart Home that it turn off immediately.
Thnx crlogic

LED turning on/off confirms UART so that’s good.

The problem sounds like a difference between you deciding when you think motion stopped and the sensor actually no longer detects motion.

Latency only controls the time after the time when the sensor stops detecting motion.