HLK-LD2450 Initial experiments to connect to HomeAssistant

Thanks, testing it now. I can see the ignore zone in the hlkradar app after making the change on esphome

Just a few questions:

  1. What is ‘single target’ for?
  2. Can I display the exclusion zone using plotly graph in ha?
  3. For the regions type dropdown option, does this mean I can only assign either exclusion zone or detect zone but not both?

image

  1. This is the mode of the sensor in which it detects only one target, it is difficult to say for what purpose this was done by the developers of the sensor.
  2. I don’t see a problem with this.
  3. Yes, the sensor protocol does not allow simultaneous ignoring and detecting zones.
1 Like

Could you add a presense sensor timeout?
This was added with screek/athua’s config because if you remain static enough, the radar would drop the target but does resume tracking in a few seconds. Which makes the presence sensing look like this

It’s very difficult to produce good results for static targets. The sensors are getting better on this but they are far from perfect.

If you add a delay for off then you will also have a delay if you leave the room, which is also not an ideal situation. In my opinion the judgement if there is a static object should be in firmware level and not in the esphome.

If you look in your history the “no presence” sequences are not equal and would be very hard to find the golden delay time.

Exactly, and I hope they would fix it in future updates.
LD2410 is great for static but then you have the interference like fans in the same room which doesn’t make it reliable.

I have an alternative idea. A person can’t disappear into the middle of a room, so I can add entry/exit points. If the last position was in these coordinates, then clearing the presense will be instantaneous. In other cases, with a timeout (my sensor sometimes sees ghosts when I am at the edge of the zone).

1 Like

That’s a very nice approach for the firmware.
They could include customizable entry/exit points and then consider presence based on movement through these points.
Also a nice approach for the situations where the exit / entry points are not in the sensor’s limits, would be: consider no presence if target moves from anywhere to outside the sensor limits (last known position, the zone limit).

Maybe they are all already implemented but due to limitations not easy applicable…

I trust the engineers, they are smarter :wink:

That’s a really interesting approach, looking forward to test it

I added the configuration for presence timeout (it affects only the binary sensor has_target) and added the configuration entry_points, each point is a circle with a radius of 50 cm, when the person is in it, the presence timeout does not work.

1 Like

Thanks, took me a while to realize that i had to adjust the angle to 180 when the target was on other side of the graph. Is there an easy way to determine the correct angle? I had it positioned on the corner of my room.

image

As for the entry points, i guess the most suitable location would be near the door to my room.
I’d still to manually edit the points in the the yaml, correct? I don’t see an option for entry point in the esphome integration

number:
- platform: ld2450
  rotate:
    restore_value: true
    initial_value: 0
    name: "Rotate angle"
  presense_timeout:
    name: "Presense timeout"
  entry_points:
    - x: 0
      y: 0
1 Like

The angle depends on which side up the sensor is located. I set an angle of 45 degrees and inverted the negative coordinates in the widget. Perhaps it is necessary to add a parameter for the inversion of coordinates.

    x:
      - $ex hass.states["sensor.hlk_presense_p0x"].state
    'y':
      - $ex -hass.states["sensor.hlk_presense_p0y"].state

Yes, entrypoints are configured in yaml, I thought there is no point in changing them dynamically.

Oh that makes sense, mine is probably flipped down, I’ll have to take a look again

image

I think it would be better if it can be changed dynamically to determine the best entry/exit points instead of recompiling each time.

Do you mind sharing your codes for the polygraph?

Hmmm, I think this is the wrong position, the sensor should be vertical.

I configure the sensor as follows:

  1. Flash the sensor without inversion of coordinates and without entry points
  2. Make a widget with the plane x[-600, 600] and y[-600, 600]
  3. Stand in front of the sensor at a distance of 1 meter
  4. Rotate the coordinates with the rotate parameter until your position is in the required plane, for example x:100 y:-100
  5. Set the y coordinate inversion parameter
  6. Set the coordinate of the entry point relative to the new coordinates, for example (0, 150) because my sensor is to the right of the entrance at a distance of 150 cm
  7. (Additional) I added additional entry points at (0,0) and (0,100) because the sensor sometimes shows ghosts at these coordinates when I exit

Basically, this approach works, but there are some problems:

  1. If there are two persons in the room and the first person disappears, then the second person becomes the first person, this confuses the algorithm.
  2. When leaving the room, ghosts sometimes appear in random coordinates.

Both of these problems are difficult to solve on the esphome side, maybe the sensor firmware will improve later.

I also added custom zones with a binary sensor to detect presence.

Configuration Widget
type: custom:plotly-graph
title: LD2450
refresh_interval: 10
hours_to_show: current_day
ha_theme: true
layout:
  legend:
    'y': 600
    orientation: h
  autosize: true
  margin:
    autoexpand: true
    l: 50
    r: 20
    t: 20
    b: 40
  showlegend: true
  xaxis:
    dtick: 100
    gridcolor: RGBA(200,200,200,0.15)
    zerolinecolor: RGBA(200,200,200,0.15)
    type: number
    fixedrange: true
    range:
      - 600
      - -600
  yaxis:
    dtick: 100
    gridcolor: RGBA(200,200,200,0.15)
    zerolinecolor: RGBA(200,200,200,0.15)
    scaleanchor: x
    scaleratio: 1
    fixedrange: true
    range:
      - 600
      - -600
entities:
  - entity: ''
    name: Person1
    show_value: true
    unit_of_measurement: cm
    marker:
      size: 12
    line:
      shape: spline
      width: 5
    x:
      - $ex hass.states["sensor.hlk_presenсe_p0x"].state
    'y':
      - $ex hass.states["sensor.hlk_presenсe_p0y"].state
  - entity: ''
    name: Person2
    show_value: true
    unit_of_measurement: cm
    marker:
      size: 12
    line:
      shape: spline
      width: 5
    x:
      - $ex hass.states["sensor.hlk_presenсe_p1x"].state
    'y':
      - $ex hass.states["sensor.hlk_presenсe_p1y"].state
  - entity: ''
    name: Person3
    show_value: true
    unit_of_measurement: cm
    marker:
      size: 12
    line:
      shape: spline
      width: 5
    x:
      - $ex hass.states["sensor.hlk_presenсe_p2x"].state
    'y':
      - $ex hass.states["sensor.hlk_presenсe_p2y"].state
  - entity: ''
    name: Zone1
    mode: lines
    fill: toself
    fillcolor: RGBA(20,200,0,0.1)
    line:
      color: RGBA(20,200,0,0.2)
      shape: line
      width: 2
    x:
      - $ex hass.states["number.hlk_presenсe_r0x0"].state
      - $ex hass.states["number.hlk_presenсe_r0x0"].state
      - $ex hass.states["number.hlk_presenсe_r0x1"].state
      - $ex hass.states["number.hlk_presenсe_r0x1"].state
      - $ex hass.states["number.hlk_presenсe_r0x0"].state
    'y':
      - $ex hass.states["number.hlk_presenсe_r0y0"].state
      - $ex hass.states["number.hlk_presenсe_r0y1"].state
      - $ex hass.states["number.hlk_presenсe_r0y1"].state
      - $ex hass.states["number.hlk_presenсe_r0y0"].state
      - $ex hass.states["number.hlk_presenсe_r0y0"].state
  - entity: ''
    name: Zone2
    mode: lines
    fill: toself
    fillcolor: RGBA(200,0,255,0.1)
    line:
      color: RGBA(200,0,255,0.2)
      shape: line
      width: 2
    x:
      - $ex hass.states["number.hlk_presenсe_r1x0"].state
      - $ex hass.states["number.hlk_presenсe_r1x0"].state
      - $ex hass.states["number.hlk_presenсe_r1x1"].state
      - $ex hass.states["number.hlk_presenсe_r1x1"].state
      - $ex hass.states["number.hlk_presenсe_r1x0"].state
    'y':
      - $ex hass.states["number.hlk_presenсe_r1y0"].state
      - $ex hass.states["number.hlk_presenсe_r1y1"].state
      - $ex hass.states["number.hlk_presenсe_r1y1"].state
      - $ex hass.states["number.hlk_presenсe_r1y0"].state
      - $ex hass.states["number.hlk_presenсe_r1y0"].state
  - entity: ''
    name: Zone3
    mode: lines
    fill: toself
    fillcolor: RGBA(200,120,55,0.1)
    line:
      color: RGBA(200,120,55,0.2)
      shape: line
      width: 2
    x:
      - $ex hass.states["number.hlk_presenсe_r2x0"].state
      - $ex hass.states["number.hlk_presenсe_r2x0"].state
      - $ex hass.states["number.hlk_presenсe_r2x1"].state
      - $ex hass.states["number.hlk_presenсe_r2x1"].state
      - $ex hass.states["number.hlk_presenсe_r2x0"].state
    'y':
      - $ex hass.states["number.hlk_presenсe_r2y0"].state
      - $ex hass.states["number.hlk_presenсe_r2y1"].state
      - $ex hass.states["number.hlk_presenсe_r2y1"].state
      - $ex hass.states["number.hlk_presenсe_r2y0"].state
      - $ex hass.states["number.hlk_presenсe_r2y0"].state
  - entity: ''
    name: Coverage
    mode: lines
    fill: tonexty
    fillcolor: rgba(168, 216, 234, 0.08)
    line:
      shape: line
      width: 1
      dash: dot
    x:
      - 0
      - $ex 600 * Math.sin((2 * Math.PI)/360 * 60)
      - 450
      - 400
      - 300
      - 200
      - 100
      - 0
      - -100
      - -200
      - -300
      - -400
      - -450
      - $ex -600 * Math.sin((2 * Math.PI)/360 * 60)
      - 0
    'y':
      - 0
      - $ex 600 * Math.cos((2 * Math.PI)/360 * 60)
      - $ex Math.sqrt( 600**2 - 450**2 )
      - $ex Math.sqrt( 600**2 - 400**2 )
      - $ex Math.sqrt( 600**2 - 300**2 )
      - $ex Math.sqrt( 600**2 - 200**2 )
      - $ex Math.sqrt( 600**2 - 100**2 )
      - 600
      - $ex Math.sqrt( 600**2 - 100**2 )
      - $ex Math.sqrt( 600**2 - 200**2 )
      - $ex Math.sqrt( 600**2 - 300**2 )
      - $ex Math.sqrt( 600**2 - 400**2 )
      - $ex Math.sqrt( 600**2 - 450**2 )
      - $ex 600 * Math.cos((2 * Math.PI)/360 * 60)
      - 0
raw_plotly_config: true
Widget
type: custom:plotly-graph
title: LD2450
refresh_interval: 0.5
hours_to_show: current_day
ha_theme: true
layout:
  legend:
    orientation: h
  autosize: true
  margin:
    autoexpand: true
    l: 50
    r: 20
    t: 20
    b: 40
  showlegend: true
  xaxis:
    dtick: 50
    gridcolor: RGBA(200,200,200,0.15)
    zerolinecolor: RGBA(200,200,200,0.15)
    type: number
    fixedrange: true
    range:
      - -50
      - 450
  yaxis:
    dtick: 50
    gridcolor: RGBA(200,200,200,0.15)
    zerolinecolor: RGBA(200,200,200,0.15)
    scaleanchor: x
    scaleratio: 1
    fixedrange: true
    range:
      - -50
      - 350
entities:
  - entity: ''
    name: Room
    mode: lines
    line:
      color: RGBA(200,200,200,0.7)
      shape: line
      width: 2
    x:
      - 0
      - 0
      - 400
      - 400
      - 0
    'y':
      - 300
      - 0
      - 0
      - 300
      - 300
  - entity: ''
    name: Sensor
    mode: lines
    fill: toself
    fillcolor: RGBA(200,200,0,1)
    line:
      color: RGBA(200,200,0,0.7)
      shape: line
      width: 2
    x:
      - 0
      - 0
      - 30
      - 0
    'y':
      - 30
      - 0
      - 0
      - 30
  - entity: ''
    name: Person1
    show_value: true
    unit_of_measurement: cm
    marker:
      size: 12
    line:
      shape: spline
      width: 5
    x:
      - $ex hass.states["sensor.hlk_presenсe_p0x"].state
    'y':
      - $ex hass.states["sensor.hlk_presenсe_p0y"].state
  - entity: ''
    name: Person2
    show_value: true
    unit_of_measurement: cm
    marker:
      size: 12
    line:
      shape: spline
      width: 5
    x:
      - $ex hass.states["sensor.hlk_presenсe_p1x"].state
    'y':
      - $ex hass.states["sensor.hlk_presenсe_p1y"].state
  - entity: ''
    name: Person3
    show_value: true
    unit_of_measurement: cm
    marker:
      size: 12
    line:
      shape: spline
      width: 5
    x:
      - $ex hass.states["sensor.hlk_presenсe_p2x"].state
    'y':
      - $ex hass.states["sensor.hlk_presenсe_p2y"].state
raw_plotly_config: true
3 Likes

after the latest update. The sensor can detect presence at a distance of 8m. But it seems that FW sensor 2A is not suitable, it always recognizes 3 presences with a distance of up to 30m. Hopefully there will be an update for sensor 2A soon

In docs page 14 the right position for installation is mentioned. The sensor should be installed vertical with the 2 pairs of the antennas facing up.

1 Like

Thanks @uncle-yura @ChreeceGR for that, I haven’t actually read the sensor’s manual :sweat_smile:

So far, this entry/exit point approach is working rather well for static presence

I can add multiple entry points like this?

  entry_points:
#hallway
    - x: -64
      y: 489
#2nd living room
    - x: - 200
      y: 590

I did notice the ghosting, and sometimes presence get triggered when there’s nobody in the room. It’s probably the balloons inside, so I had those removed, will continue monitoring it.

I was wondering about this if someone else leaves the room when another one is still inside, but seems to work well so far.

Thanks again for this!

It’s great to see the emergence of the very high quality ld2450 library, which reflects the elegance of esphome, and we hope to test this awesome library soon and possibly!

In the foreseeable future, ld2450 could also become very useful and popular like ld2410.

1 Like

By any means, is that PR related to ongoing discussion? The library that you guys doing here looks far more extended than the one in official PR. maybe you’d want to participate there, or join forces with @hareeshmu ?

I can add multiple entry points like this?

Sure


Yesterday there were problems loading the images, so here is an addition to my previous post

My sensor case



Widget screenshots


I didn’t see that PR 5624 existed and made this code before PR 5674 was made, so it’s easier for me to work with my own code.

I’ve reached out to the author of PR 5674 with some suggestions on Discord and he’s ignored me, so I’d rather test my own version and then maybe make an addition to the official repo if that’s necessary of course.