LD2410 esphome tips

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

Thanks again, got it now.

Hey everyone,

Just wanted to say a big thank you for this incredible thread! It helped me a lot setting up my LD2410 sensors!

For those who prefer video tutorials, I’ve created a detailed installation guide on integrating the LD2410 with ESPHome, inspired by the valuable insights shared here.

I hope it helps others as much as this thread helped me!

4 Likes

Hello everyone,
can I connect more then one LD2410 sensors to an ESP32 board?

1 Like

Nice tutorial!
One question: what’s the use of the threshold and how to define the values?
gx_move_threshold: ##
gx_still_threshold: ##

If’ve left it in my code and it seems to work normally.

Thanks, I’m glad you found it helpful!

The threshold is divided into 9 gates, from 0 to 8. Each gate controls a different distance from the sensor. For example, gate 3 (g3) controls a range of 1.5m to 2.25m.

The threshold works such that 0 is the most sensitive, and 100 is the least sensitive. It corresponds to the values you see under “Move Energy” and “Still Energy” for each gate, you can get more accurate data using the HLKRadarTool app if you need to.

If it works with the default values, there is no need to change anything. I would only tweak it if you experience false positives.

1 Like

The thresholds are the sensitivity values for each distance gate. The higher the value, the more movement will be required to trigger it. See my explanation of the settings in the app which corresponds to the yaml settings:

Is anyone having trouble updating the firmware on the 2410? I’ve a couple of 2410Bs and Cs that I’ve just built into a couple of sensors, but I can’t update the firmware from V 1.07.22091516 on any of them.

I can see all the devices in the app but when I select more versions I do not get a list of firmware upgrades only the UPGRADE button. If I hit upgrade I get a message sayong “Please select the version!” and eventually I get an error message popup saying “Failed to obtain the firmware:-1”. Appart from not being able update the firmware everything appears to be working OK.

I’ve upgraded the app (on Android) to V1.1.18 and I get the same behaviour.

UPDATE: I was blocking ALL Chinese websites, DOH!

For those who may have trouble with getting the LD2410 working with ESP8266 - D1-Mini, particularly the ones with a CH340G serial to usb chip, try switching to the alternative uart pins:

uart:
tx_pin: GPIO15
rx_pin: GPIO13
baud_rate: 256000
parity: NONE
stop_bits: 1

After much debugging and suspecting bad electronics I finally determined that something about the CH340G chips prevents the serial communication with the LD2410. ESP8266 boards with the CP2104 serial usb chips work.

Docs: UART Bus — ESPHome
The ESP8266 has two UARTs; the second of which is TX-only. Only a limited set of pins can be used. UART0 may use either tx_pin: GPIO1 and rx_pin: GPIO3 , or tx_pin: GPIO15 and rx_pin: GPIO13 . UART1 must use tx_pin: GPIO2 . Any other combination of pins will result in use of a software UART.

Any news about the tests? :grinning:

a few things i do not understand.
bear with me as i trie to explain myself.

for testing i bought a few LD2410Bsensors and D1 Mini Esp8266 boards, to test this out.

so far i have made 2 working sensors with the following “captive portal” in esphome for the boards

uart:
  id: ld2410_uart
  tx_pin: 1
  rx_pin: 3
  baud_rate: 256000
  parity: NONE
  stop_bits: 1

ld2410:
  uart_id: ld2410_uart
  timeout: 150s
  max_move_distance : 6m
  max_still_distance: 6m
  g0_move_threshold: 50
  g0_still_threshold: 0
  g1_move_threshold: 50
  g1_still_threshold: 0
  g2_move_threshold: 40
  g2_still_threshold: 40
  g3_move_threshold: 30
  g3_still_threshold: 40
  g4_move_threshold: 20
  g4_still_threshold: 30
  g5_move_threshold: 15
  g5_still_threshold: 30
  g6_move_threshold: 15
  g6_still_threshold: 20
  g7_move_threshold: 15
  g7_still_threshold: 20
  g8_move_threshold: 15
  g8_still_threshold: 20

binary_sensor:
  - platform: ld2410
    has_target:
      name: "presence"
    has_moving_target:
      name: "movement"
    has_still_target:
      name: "still"

sensor:
  - platform: ld2410
    moving_distance:
      name: "Moving distance (cm)"
    still_distance:
      name: "Still Distance (cm)"
    moving_energy:
      name: "Move Energy (%)"
    still_energy:
      name: "Still Energy (%)"
    detection_distance:
      name: "Distance Detection (cm)"

all is fine and working.

now when i try to put in the following at the sensor code

    g0_move_energy:
      name: g0 move energy
    g0_still_energy:
      name: g0 still energy
    g1_move_energy:
      name: g1 move energy
    g1_still_energy:
      name: g1 still energy
    g2_move_energy:
      name: g2 move energy
    g2_still_energy:
      name: g2 still energy
    g3_move_energy:
      name: g3 move energy
    g3_still_energy:
      name: g3 still energy
    g4_move_energy:
      name: g4 move energy
    g4_still_energy:
      name: g4 still energy
    g5_move_energy:
      name: g5 move energy
    g5_still_energy:
      name: g5 still energy
    g6_move_energy:
      name: g6 move energy
    g6_still_energy:
      name: g6 still energy
    g7_move_energy:
      name: g7 move energy
    g7_still_energy:
      name: g7 still energy
    g8_move_energy:
      name: g8 move energy
    g8_still_energy:
      name: g8 still energy

esphome tells me

[g0_move_energy:] is an invalid option for [sensor.ld2410] did you mean [moving energy]?

same goes for

switch:
  - platform: ld2410
    engineering_mode:
      name: "engineering mode"
    bluetooth:
      name: "control bluetooth"

esphome tells me

platform not found: “switch ld2410”

and

button:
  - platform: ld2410
    factory_reset:
      name: "factory reset"
    restart:
      name: "restart"
    query_params:
      name: query params

esphome is telling me

platform not found: “button ld2410”

and everything posted here on github is not working for me either.

is it because i have the wrong LD2410 sensor, because it is the LD2410B or…
is it because i have the D1 Mini esp2866 instead of ESP32 board ?

It doesn’t look like the code needed for that YAML on GitHub has been merged into ESPHome yet. If/when that gets merged, the new configuration parameters and button/switch functionality will be available.

2 Likes