LD2410 esphome tips

Thanks!, i just found it.

I will now try to understand the values…

I attached the LD2410 to a door, and i want to detect the movement through this door. let’s see if i can xD

I got it to work with an ESP32 with one LD2410 over UART, now I would like to connect two or three LD2410 over UART to one ESP32 - how do I configure that in ESPhome (if it is possible)?

I’d agree that the LD2410B doesn’t play well with fans, even if the fan is outside the documented 60˚ cone of detection.

I have an LD2410B on the ceiling, with fan blades as close as 0.8m away and at the same height. The sensor shows an almost continuous moving target peaking at about 4m away, and a strong static target across the full range of 1.5m to 6m. I see no way to filter that out.

I’d guess fans, wind, curtain movement, and the like are problems for many home settings. I’d love to hear if anyone is able to effectively use these devices when dealing with such factors.

1 Like

Have you tested with the code from this link?

Install the dev version of esphome.
You will see which gate is having the most interference from the fan.

2 Likes

I have not. I’ve only looked at it via the HiLink phone app + bluetooth. I’m currently using it with HA via Bluetooth and a bluetooth proxy (with all it’s reconnect problems). I only became aware yesterday that connected (via wires), LD2410 support has significant updates that are not released yet.

Indeed, wind from an open window or simply the vacuum robot passing by are enough to trigger the presence detection. I’m considering installing a simple PIR sensor connected to the same esp board and use it to validate the start of a detection event. If both the PIR and the digital LD2410 output are active the presence signal would be set and it would be reset when the LD2410 digital output becomes inactive.
Does it, in your opinion, make sense?

Marco

1 Like

Theoretically, yes. I’m thinking of doing the same. But I also want to look at how much playing with the sensitivity levels can help, before spending too much time on mmWave.

Does it, in your opinion, make sense?

Sure it does. In fact, all (serious) antiburglar sensors are dual technology: MW + PIR. Alarm is triggered only when both technologies detect intruder, thus avoiding false alarms.
So, it’s a great idea: use both to start triggering, then use only LD’s presence function to detect how long a person is present in the room… If room is “noisy” (as said: curtains, robots…) then whole system can be made in a way that IR must be triggered periodically, too, in order for output to stay active.

2 Likes

This is a great, great idea! We just got 90 radars, and some PIRs, and are doing some tests, and the combination works really well.


3 Likes

Nice. What model is this radar?

Edit: I just found It: LD2410C

Hello all. Been trying everything i can find to get my HLK-LD2410B working with my D1 MINI V3.0.0 - Mini NodeMcu board. Only get unknown status whatever i do…

To make sure, i got 5 of each and all work on their own. However the LD2410 don’t seem to work when powered from the 5v on the esp… So using external power for both.
Then i also tried all combos of yaml files that i can find combined with the .h from GitHub - rain931215/ESPHome-LD2410: ESPHome LD2410 mmWave Radar Sensor Custom Component.
And tried all uart combos…
tx_pin: GPIO15, rx_pin: GPIO13
tx_pin: GPIO1, rx_pin: GPIO3
tx_pin: GPIO3, rx_pin: GPIO1
tx_pin: RX, rx_pin: TX
tx_pin: TX, rx_pin: RX

Using latest esphome 2023.5.0 (dev), and latest HA on a virtual machine.
Read that some had succes reverting to version 2023.3.2 of esphome but that seams impossible on a vm?

Currently my yaml looks like this

esphome:
  name: ld2410
  includes:
    - ld2410_uart.h
  on_boot:
    priority: 600
    # ...
    then:
      - lambda: |-
          auto uart_component = static_cast<LD2410 *>(ld2410);
          uart_component->setNumbers(maxMovingDistanceRange, maxStillDistanceRange, noneDuration);

external_components:
  - source: github://esphome/esphome@dev
    components: [ ld2410 ]

esp8266:
  board: esp01_1m

logger:
  baud_rate: 0

api:
  encryption:
    key: "="

ota:
  password: ""

wifi:
  ssid: 
  password: 

  manual_ip:
    static_ip: 192.168.1.124
    gateway: 192.168.1.1
    subnet: 255.255.255.0

uart:
  id: uart_1
  rx_pin: GPIO3
  tx_pin: GPIO1
  baud_rate: 256000
  data_bits: 8
  stop_bits: 1
  parity: NONE

custom_component:
  - lambda: |-
      return {new LD2410(id(uart_1))};
    components:
      - id: ld2410

binary_sensor:
  - platform: custom
    lambda: |-
      auto uart_component = static_cast<LD2410 *>(ld2410);
      return {uart_component->hasTarget,uart_component->hasMovingTarget,uart_component->hasStillTarget,uart_component->lastCommandSuccess};
    binary_sensors:
      - name: "Has Target"
      - name: "Has Moving Target"
      - name: "Has Still Target"
      - name: "Last Command Success"

sensor:
  - platform: custom
    lambda: |-
      auto uart_component = static_cast<LD2410 *>(ld2410);
      return {uart_component->movingTargetDistance,uart_component->movingTargetEnergy,uart_component->stillTargetDistance,uart_component->stillTargetEnergy,uart_component->detectDistance};
    sensors:
      - name: "Moving Target Distance"
        unit_of_measurement: "cm"
        accuracy_decimals: 0
      - name: "Moving Target Energy"
        unit_of_measurement: "%"
        accuracy_decimals: 0
      - name: "Still Target Distance"
        unit_of_measurement: "cm"
        accuracy_decimals: 0
      - name: "Still Target Energy"
        unit_of_measurement: "%"
        accuracy_decimals: 0
      - name: "Detect Distance"
        unit_of_measurement: "cm"
        accuracy_decimals: 0

number:        
  - platform: template
    name: "Max Moving Distance Range"
    id: maxMovingDistanceRange
    min_value: 1
    max_value: 8
    step: 1
    update_interval: never
    optimistic: true
    set_action:
      - lambda: |-
          auto uart_component = static_cast<LD2410 *>(ld2410);
          uart_component->setMaxDistancesAndNoneDuration(x,id(maxStillDistanceRange).state,id(noneDuration).state);
  - platform: template
    name: "Max Still Distance Range"
    id: maxStillDistanceRange
    min_value: 1
    max_value: 8
    step: 1
    update_interval: never
    optimistic: true
    set_action:
      - lambda: |-
          auto uart_component = static_cast<LD2410 *>(ld2410);
          uart_component->setMaxDistancesAndNoneDuration(id(maxMovingDistanceRange).state,x,id(noneDuration).state);
  - platform: template
    name: "None Duration"
    id: noneDuration
    min_value: 0
    max_value: 32767
    step: 1
    mode: box
    update_interval: never
    optimistic: true
    set_action:
      - lambda: |-
          auto uart_component = static_cast<LD2410 *>(ld2410);
          uart_component->setMaxDistancesAndNoneDuration(id(maxMovingDistanceRange).state,id(maxStillDistanceRange).state,x);

button:
  - platform: template
    name: "Reboot LD2410"
    on_press:
      lambda: 'static_cast<LD2410 *>(ld2410)->reboot();'
  - platform: template
    name: "Turn on config mode"
    on_press:
      - lambda: 'static_cast<LD2410 *>(ld2410)->setConfigMode(true);'
  - platform: template
    name: "Turn off config mode"
    on_press:
      - lambda: 'static_cast<LD2410 *>(ld2410)->setConfigMode(false);'
  - platform: template
    name: "Get config"
    on_press:
      - lambda: 'static_cast<LD2410 *>(ld2410)->queryParameters();'
  - platform: template
    name: "Set baud rate to 256000"
    on_press:
      - lambda: 'static_cast<LD2410 *>(ld2410)->setBaudrate(7);'
  - platform: template
    name: "Set baud rate to 115200"
    on_press:
      - lambda: 'static_cast<LD2410 *>(ld2410)->setBaudrate(5);'
  - platform: template
    name: "Set baud rate to 9600"
    on_press:
      - lambda: 'static_cast<LD2410 *>(ld2410)->setBaudrate(1);'

Anyone have a similar setup with any succes?
If not, any thips for a new esp board that might work better?

Your code is way more complex than necessary to get the LD2410 working with the current version of ESPHome, as it’s been natively supported for a few months now. There is no need for the external_components section or the includes and on_boot content blocks under esphome.

This is the relevant YAML for one of my sensors:

uart:
  tx_pin: GPIO1
  rx_pin: GPIO3
  baud_rate: 256000
  parity: NONE
  stop_bits: 1

ld2410:
  timeout: 5s
  max_move_distance : 6m
  max_still_distance: 6m
    

      
binary_sensor:
  # LD2410
  - platform: ld2410
    has_target:
      name: Presence
    has_moving_target:
      name: Moving Target
    has_still_target:
      name: Still Target
  
sensor:
  - platform: ld2410
    moving_distance:
      name: Moving Distance
    still_distance:
      name: Still Distance
    moving_energy:
      name: Move Energy
    still_energy:
      name: Still Energy
    detection_distance:
      name: Detection Distance
1 Like

Well my code has gotten long over time becuase non of the simpler codes have worked…
Trying your config gives me error on install…

INFO ESPHome 2023.7.0-dev
INFO Reading configuration /config/esphome/esp-1.yaml...
INFO Generating C++ source...
INFO Compiling app...
Processing ld2410 (board: esp01_1m; framework: arduino; platform: platformio/[email protected])
--------------------------------------------------------------------------------
HARDWARE: ESP8266 80MHz, 80KB RAM, 1MB Flash
Dependency Graph
|-- ESP8266WiFi @ 1.0
|-- ESP8266mDNS @ 1.2
|-- noise-c @ 0.1.4
Compiling /data/ld2410/.pioenvs/ld2410/src/main.cpp.o
In file included from src/main.cpp:40:
src/ld2410_uart.h:20:3: error: 'Number' does not name a type
   20 |   Number *maxMovingDistanceRange;
      |   ^~~~~~
src/ld2410_uart.h:21:3: error: 'Number' does not name a type
   21 |   Number *maxStillDistanceRange;
      |   ^~~~~~
src/ld2410_uart.h:24:3: error: 'Number' does not name a type
   24 |   Number *noneDuration;
      |   ^~~~~~
src/ld2410_uart.h:28:19: error: 'Number' has not been declared
   28 |   void setNumbers(Number *maxMovingDistanceRange_, Number *maxStillDistanceRange_, Number *noneDuration_){
      |                   ^~~~~~
src/ld2410_uart.h:28:52: error: 'Number' has not been declared
   28 |   void setNumbers(Number *maxMovingDistanceRange_, Number *maxStillDistanceRange_, Number *noneDuration_){
      |                                                    ^~~~~~
src/ld2410_uart.h:28:84: error: 'Number' has not been declared
   28 |   void setNumbers(Number *maxMovingDistanceRange_, Number *maxStillDistanceRange_, Number *noneDuration_){
      |                                                                                    ^~~~~~
src/ld2410_uart.h: In member function 'void LD2410::setNumbers(int*, int*, int*)':
src/ld2410_uart.h:29:5: error: 'maxMovingDistanceRange' was not declared in this scope; did you mean 'maxMovingDistanceRange_'?
   29 |     maxMovingDistanceRange = maxMovingDistanceRange_;
      |     ^~~~~~~~~~~~~~~~~~~~~~
      |     maxMovingDistanceRange_
src/ld2410_uart.h:30:5: error: 'maxStillDistanceRange' was not declared in this scope; did you mean 'maxStillDistanceRange_'?
   30 |     maxStillDistanceRange = maxStillDistanceRange_;
      |     ^~~~~~~~~~~~~~~~~~~~~
      |     maxStillDistanceRange_
src/ld2410_uart.h:31:5: error: 'noneDuration' was not declared in this scope; did you mean 'noneDuration_'?
   31 |     noneDuration = noneDuration_;
      |     ^~~~~~~~~~~~
      |     noneDuration_
src/ld2410_uart.h: In member function 'void LD2410::handleACKData(char*, int)':
src/ld2410_uart.h:158:7: error: 'maxMovingDistanceRange' was not declared in this scope
  158 |       maxMovingDistanceRange->publish_state(buffer[12]);
      |       ^~~~~~~~~~~~~~~~~~~~~~
src/ld2410_uart.h:159:7: error: 'maxStillDistanceRange' was not declared in this scope
  159 |       maxStillDistanceRange->publish_state(buffer[13]);
      |       ^~~~~~~~~~~~~~~~~~~~~
src/ld2410_uart.h:175:7: error: 'noneDuration' was not declared in this scope
  175 |       noneDuration->publish_state(twoByteToInt(buffer[32], buffer[33]));
      |       ^~~~~~~~~~~~
src/ld2410_uart.h: In member function 'void LD2410::setConfigMode(bool)':
src/ld2410_uart.h:217:27: warning: narrowing conversion of '(enable ? 255 : 254)' from 'int' to 'char' [-Wnarrowing]
  217 |     char cmd[2] = {enable ? 0xFF : 0xFE, 0x00};
      |                    ~~~~~~~^~~~~~~~~~~~~
src/ld2410_uart.h: In member function 'void LD2410::setEngineeringMode(bool)':
src/ld2410_uart.h:245:27: warning: narrowing conversion of '(enable ? 98 : 99)' from 'int' to 'char' [-Wnarrowing]
  245 |     char cmd[2] = {enable ? 0x62 : 0x63, 0x00};
      |                    ~~~~~~~^~~~~~~~~~~~~
In file included from src/main.cpp:40:
src/ld2410_uart.h: In member function 'void LD2410::setBaudrate(int)':
src/ld2410_uart.h:273:22: warning: narrowing conversion of 'index' from 'int' to 'char' [-Wnarrowing]
  273 |     char value[2] = {index, 0x00};
      |                      ^~~~~
/config/esphome/esp-1.yaml: In lambda function:
/config/esphome/esp-1.yaml:10:57: error: expected primary-expression before ')' token
   10 |           auto uart_component = static_cast<LD2410 *>(ld2410);
      |                                                         ^
/config/esphome/esp-1.yaml:11:34: error: 'maxMovingDistanceRange' was not declared in this scope
   11 |           uart_component->setNumbers(maxMovingDistanceRange, maxStillDistanceRange, noneDuration);
      |                                  ^~~~~~~~~~~~~~~~~~~~~~
/config/esphome/esp-1.yaml:11:58: error: 'maxStillDistanceRange' was not declared in this scope
   11 |           uart_component->setNumbers(maxMovingDistanceRange, maxStillDistanceRange, noneDuration);
      |                                                          ^~~~~~~~~~~~~~~~~~~~~
/config/esphome/esp-1.yaml:11:81: error: 'noneDuration' was not declared in this scope
   11 |           uart_component->setNumbers(maxMovingDistanceRange, maxStillDistanceRange, noneDuration);
      |                                                                                 ^~~~~~~~~~~~
In file included from src/esphome.h:68,
                 from src/main.cpp:3:
src/esphome/core/time.h: At global scope:
src/esphome/core/time.h:11:13: warning: 'bool esphome::is_leap_year(uint32_t)' declared 'static' but never defined [-Wunused-function]
   11 | static bool is_leap_year(uint32_t year);
      |             ^~~~~~~~~~~~
src/esphome/core/time.h:13:16: warning: 'uint8_t esphome::days_in_month(uint8_t, uint16_t)' declared 'static' but never defined [-Wunused-function]
   13 | static uint8_t days_in_month(uint8_t month, uint16_t year);
      |                ^~~~~~~~~~~~~
*** [/data/ld2410/.pioenvs/ld2410/src/main.cpp.o] Error 1
========================== [FAILED] Took 2.04 seconds ==========================

The errors look to be from the number: block of your code, which is unnecessary. Unless you’re actively trying to tune the sensor, there’s no need for the button: block either–and the app is a much better method of tuning it. Also, one other thing to try if removing those two blocks doesn’t resolve it is to use the production branch of ESPHome, which is 2023.5.5, instead of the 2023.7.0-dev branch.

uart:
  id: uart_1
  rx_pin: GPIO13  #D7
  tx_pin: GPIO15  #D8
  baud_rate: 256000
  data_bits: 8
  stop_bits: 1
  parity: NONE

ld2410:
  timeout: 1s
  max_move_distance : 6m
  max_still_distance: 6m

binary_sensor:
  - platform: ld2410
    has_target:
      name: "presence"
    has_moving_target:
      name: "movement"
    has_still_target:
      name: "still"
  - platform: gpio
    id: MovOcc_gpio
    pin:
      number: GPIO14
      mode:
        input: true
        pullup: true
    name: "mmWave Pin"
    filters:
      delayed_on: 10ms
    device_class: occupancy

sensor:
  - platform: ld2410
    moving_distance:
      name: Moving Distance
    still_distance:
      name: Still Distance
    moving_energy:
      name: Move Energy
    still_energy:
      name: Still Energy
    detection_distance:
      name: Detection Distance

No luck changing esphome version… Also tired your yaml again, installed, but gave no data over uart. Tried some more changes and changed pins over and over again, no luck.
Now trying only the OUT pin to GPIO14, HA detects when cable is inserted or not, but pressence from the sensor dont change anything…

Is there a way to control the distance using the Out pin only?
So far I have mine setup simply like this:

binary_sensor:
  - platform: gpio
    pin: GPIO0
    name: Presence
    device_class: presence

If you have the LD2410B/C you can use the HLKRadar Tool on your phone to connect to the LD2410 via Bluetooth and you can do all the configuration there. It allows you to set the distance and sensitivity.
The following post near the top of this thread has the link to the tool for Android phones:

Tweaking the sensitivity for each distance gate is a little tricky. Make sure that Engineering mode is turned on and you should see the graphs in the HLK app. The pink/red line on the graphs is the energy value (its like movement percentage, the higher the value the more movement is required before the target is detected) set for each distance gate and the blue line is what the sensor is detecting. Once the blue line goes above the pink/red line, the target is detected.
You can also reduce the number of detection points (max is 8 which is the furthest range of approx 6m) if you don’t want to detect moving or static targets up to the max distance (ie. set it to 5 will cause the sensor to detect up to gate 5 which is 3.75m if gate distance is set to 0.75m).
I suggest having the app open and the graphs displayed and walking around the room to see how the blue line moves as it detects you being still or moving around.

This is great, thank you. The sensor I have now is non-BT LD2410 wired to ESP8266. I am planning on buying BT version soon and I will refer to your explanation.
In the meantime though, is controlling distance with non-BT version only possible with Rx/Tx wired?

There is a Windows app as well but I believe you need to connect it to a USB board but yes for the non-bluetooth version, the easiest option would be to connect the TX/RX pins on the LD2410 to your ESP8266 and then use your ESPHOME yaml to configure it.

There is also an update being worked on to improve the LD2410 integration in HA to allow dynamic configuration from the HA UI so you do not need to upload a new yaml everytime you need to make a change to the config. Its still in the dev channel waiting to be merged into an ESPHOME release. I’m currently using it on my ESP32 D1 Mini compatible board and a LD2410C with no issues.

Add configuration flow abilites to the ld2410 component by regevbr · Pull Request #4434 · esphome/esphome · GitHub

For anyone getting unknown from their UART I would recommend trying a different set of pins for the UART. I know the integration says to use the hardware UART to get the high baud rate to work. However, it has been mentioned in a few posts above that people getting unknown have had success when trying pins other than the recommended pins, so I thank all those posters for their inspiration. There does not appear to be a consistency of which ones work, so I’d suggest that you try until you find a combination that works.

I have 2410B, 2410C, D1-Mini, ESP32S2 mini and ESP32C3 mini. I could not find any configuration that would work with the recommended UART pins on any combination of boards. When I used other pins for the UART then everything burst into life.

For the record, I’ve settled on (Tx and Rx) GPIO15 and GPIO13 for my D1Mini, GPIO18 and GPIO16 for my S2Mini and GPIO5 and GPIO4 for my C3Mini.

I hope this helps?

Chris