HLK-LD2450 Initial experiments to connect to HomeAssistant

I have updated to your latest firmware (V230828_2_BETA) and it seems to be working well so far.
One issue that I have found is that I am getting X values from -3500 to 3500 so you may want to extend the limit from -3000 to -3500 and 3000 to 3500.
It may be worth checking with HiLink as to what the minimum and maximum values of X should be.

Edit: Another issue found is that the Zout1 Y range has been restricted to 3000. Should Y be up to 6000?

LD2450-zout1-y-range

1 Like

Hello, I have updated the latest firmware. Zout1 has been successfully detected, but my is a ceiling fan, y begin and y end need at least 4500 to 6000. But the upper limit only reaches 3000. Can this upper limit be adjusted?

Hi, Gus. This appears to be a bug and we will now immediately try to fix it.

@noname.essqq we are fix now.

In hilink’s documentation there is only a vague chart of the detection range, based on the approximate measurements inside it is about 3m left and right, in reality it seems difficult to exceed 4m left and right.
We have 4m set aside now, which should be enough for basic use.

Thanks for applying the updates so quickly.
I have just updated to V230829_1_BETA and its looking good.
Setting the range for X from -4000 to 4000 sounds like the best option as I got a value just over 3500, so 4000 will cover up to the maximum range it is capable of.

1 Like

I read the whole thread and couldn’t find any HW info.
I have several LD2450 sensors here and would like to try this part.
What is the most suitable esp, 32 or 8266 or does it not matter?
What do you use?
thanks

I don’t think it really matters which ESP board is used but an ESP32 would probably be better being a little more powerful.
I have connected my LD2450 to a Wemos D1 Mini ESP32 purchased from Aliexpress.
I had it working previously with a LD2410 and swapped it out for a LD2450 for testing and now have my LD2410 running off bluetooth instead of being connected to an ESP32.

1 Like

It has a relatively simple serial protocol that you can build with a chip you are familiar with.
It’s the same with the ld2410.

1 Like

Tks for your work.
This beta version is also updated on the github?

Yes it has been updated in Github as I have used it to update my LD2450 connected to a Wemos D1 Mini ESP32 board.
Use the following link as the one you have posted is not to the main branch.

Thanks for testing it, i will update the yaml and retry again.
I don’t think so, there’s no curtains in that area.
Also, which hilink firmwarw are you using now?

1 Like

use 1.2,it’s stable version.

I think i’ve got zout working now after some trial and error.
With zout enabled, it doesn’t detect the fan however presence would consistently shift between available or not available the more static your position is. I added 30- 45 seconds delay before switching any device off when presence is not detected. If i fall asleep it would probably just stop detecting

I think this has something to do with sensor that prioritise the more active target (fan) when the other target is static/not moving. Hopefully this gets fixed on the next hlk sensor update.

That is the same thing I am experiencing which makes this sensor problematic for use with multiple zones with the current HiLink firmware. I have setup 3 zones and if there is a person in Zone 1 and another person in Zone 2, the sensor will lose track of the one moving less and so will clear the presence of one of the Zones and if that is setup for the lights, then the lights will turn off.
Hopefully the next firmware release from HiLink will enable the proper 3 target tracking that has been promoted about the LD2450 sensor.

1 Like

I noticed that the LD2450 clears the Zone Presence immediately when it doesn’t detect a target. When there is little movement, it seems to clear the presence and then detect it again in a few seconds. Adding a configurable delay to when the presence is cleared could resolve this issue.

The following code should allow the timeout for each zone to be configured and set:

number:
  - platform: template
    name: "Zone1 Timeout"
    id: zone1_x_timeout
    min_value: 0
    max_value: 600
    mode: box
    device_class: duration
    entity_category: config
    unit_of_measurement: s
    icon: mdi:timer-off
    step: 1
    optimistic: True
    initial_value: 0
    restore_value: True
  - platform: template
    name: "Zone2 Timeout"
    id: zone2_x_timeout
    min_value: 0
    max_value: 600
    mode: box
    device_class: duration
    entity_category: config
    unit_of_measurement: s
    icon: mdi:timer-off
    step: 1
    optimistic: True
    initial_value: 0
    restore_value: True
  - platform: template
    name: "Zone3 Timeout"
    id: zone3_x_timeout
    min_value: 0
    max_value: 600
    mode: box
    device_class: duration
    entity_category: config
    unit_of_measurement: s
    icon: mdi:timer-off
    step: 1
    optimistic: True
    initial_value: 0
    restore_value: True

binary_sensor:
  - platform: template
    name: "Zone1 Presence"
    id: zone1_target_exsits
    device_class: occupancy
    filters:
      - delayed_off: !lambda |-
          return id(zone1_x_timeout).state * 1000.0;
  - platform: template
    name: "Zone2 Presence"
    id: zone2_target_exsits
    device_class: occupancy
    filters:
      - delayed_off: !lambda |-
          return id(zone2_x_timeout).state * 1000.0;
  - platform: template
    name: "Zone3 Presence"
    id: zone3_target_exsits
    device_class: occupancy
    filters:
      - delayed_off: !lambda |-
          return id(zone3_x_timeout).state * 1000.0;
1 Like

It’s a cool feature, Gus, and we’ll try to incorporate it into the firmware.

1 Like

I was doing this just now, but your solution is way better than mine.

2 Likes

I’m not a developer, but here’s my setup based on the work of screek-workshop and Gus.
I added direction, position, angle (not very accurate but can be useful in some cases) and a general threshold for presence.

esphome:
  name: ld2450b
  friendly_name: ld2450b
  platformio_options:
    board_build.flash_mode: dio
  on_boot:
    - priority: 2000
      then:
        lambda: |-
          id(any_target_exsits).publish_state(false);
          id(zone1_target_exsits).publish_state(false);
          id(zone2_target_exsits).publish_state(false);
          id(zone3_target_exsits).publish_state(false);
          id(zone_ex1_target_exsits).publish_state(false);

external_components:
  - source:
      type: git
      url: https://github.com/screekworkshop/custom_components_support_for_screek_2a
      ref: main
    components: [esp32, uart]
  

globals:
  - id: last_update_ld2450
    type: unsigned long
    restore_value: no
    initial_value: '0'
  - id: init_zone_publish
    type: bool
    restore_value: no
    initial_value: "false"


improv_serial:
  
debug:
  update_interval: 30s

text_sensor:
  - platform: template
    name: "Zone1 Info"
    id: tips_zone1_conf
    icon: mdi:information-outline
    entity_category: config
    lambda: |-
      return {"Configure below" };
    update_interval: 1000s
  - platform: template
    name: "Zone2 Info"
    id: tips_zone2_conf
    icon: mdi:information-outline
    entity_category: config
    lambda: |-
      return {"Configure below" };
    update_interval: 1000s
  - platform: template
    name: "Zone3 Info"
    id: tips_zone3_conf
    icon: mdi:information-outline
    entity_category: config
    lambda: |-
      return {"Configure below" };
    update_interval: 1000s
  - platform: template
    name: "Zout1 Info"
    id: tips_zone_ex1_conf
    icon: mdi:information-outline
    entity_category: config
    lambda: |-
      return {"Zone Exclusion 1" };
    update_interval: 1000s

  - platform: template
    name: "Target1 Direction"
    id: target1_direction
    icon: mdi:arrow-up-down
  - platform: template
    name: "Target2 Direction"
    id: target2_direction
    icon: mdi:arrow-up-down
  - platform: template
    name: "Target3 Direction"
    id: target3_direction
    icon: mdi:arrow-up-down
  - platform: template
    name: "Target1 Position"
    id: target1_position
    icon: mdi:arrow-left-right
  - platform: template
    name: "Target2 Position"
    id: target2_position
    icon: mdi:arrow-left-right
  - platform: template
    name: "Target3 Position"
    id: target3_position
    icon: mdi:arrow-left-right

number:
  - platform: template
    name: Area X-Begin
    id: area_x_begin
    min_value: -4000
    max_value: 4000
    initial_value: -4000
    mode: box
    device_class: distance
    entity_category: config
    unit_of_measurement: mm
    icon: mdi:arrow-left-bold
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Area X-End
    id: area_x_end
    mode: box
    min_value: -4000
    max_value: 4000
    initial_value: 4000
    device_class: distance
    unit_of_measurement: mm
    entity_category: config
    icon: mdi:arrow-right-bold
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Area Y-Begin
    id: area_y_begin
    mode: box
    min_value: 0
    max_value: 6000
    initial_value: 0
    device_class: distance
    entity_category: config
    icon: mdi:arrow-up-bold
    unit_of_measurement: mm
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Area Y-End
    id: area_y_end
    icon: mdi:arrow-down-bold
    mode: box
    min_value: 0
    max_value: 6000
    initial_value: 6000
    entity_category: config
    device_class: distance
    unit_of_measurement: mm
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Area Angle-Begin
    id: area_angle_begin
    icon: mdi:angle-acute
    mode: box
    min_value: -130 # In the readings, I obtained values of approximately 120Âș when passing behind the sensor
    max_value: 130 # In the readings, I obtained values of approximately 120Âș when passing behind the sensor
    initial_value: -130 # In the readings, I obtained values of approximately 120Âș when passing behind the sensor
    entity_category: config
    # device_class: distance
    unit_of_measurement: 'Âș'
    step: 1
    optimistic: True
    restore_value: True
  - platform: template
    name: Area Angle-End
    id: area_angle_end
    icon: mdi:angle-acute
    # mode: box
    min_value: -130 # In the readings, I obtained values of approximately 120Âș when passing behind the sensor
    max_value: 130 # In the readings, I obtained values of approximately 120Âș when passing behind the sensor
    initial_value: 130 # In the readings, I obtained values of approximately 120Âș when passing behind the sensor
    entity_category: config
    # device_class: distance
    unit_of_measurement: 'Âș'
    step: 1
    optimistic: True
    restore_value: True
  - platform: template
    name: Zone1 X-Begin
    id: zone1_x_begin
    min_value: -4000
    max_value: 4000
    initial_value: 0
    # mode: box
    device_class: distance
    entity_category: config
    unit_of_measurement: mm
    icon: mdi:arrow-left-bold
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Zone1 X-End
    id: zone1_x_end
    mode: box
    min_value: -4000
    max_value: 4000
    initial_value: 0
    device_class: distance
    unit_of_measurement: mm
    entity_category: config
    icon: mdi:arrow-right-bold
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Zone1 Y-Begin
    id: zone1_y_begin
    mode: box
    min_value: 0
    max_value: 6000
    initial_value: 0
    device_class: distance
    entity_category: config
    icon: mdi:arrow-up-bold
    unit_of_measurement: mm
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Zone1 Y-End
    id: zone1_y_end
    icon: mdi:arrow-down-bold
    mode: box
    min_value: 0
    max_value: 6000
    initial_value: 0
    entity_category: config
    device_class: distance
    unit_of_measurement: mm
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Zone2 X-Begin
    id: zone2_x_begin
    min_value: -4000
    max_value: 4000
    initial_value: 0
    mode: box
    device_class: distance
    entity_category: config
    unit_of_measurement: mm
    icon: mdi:arrow-left-bold
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Zone2 X-End
    id: zone2_x_end
    mode: box
    min_value: -4000
    max_value: 4000
    initial_value: 0
    device_class: distance
    unit_of_measurement: mm
    entity_category: config
    icon: mdi:arrow-right-bold
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Zone2 Y-Begin
    id: zone2_y_begin
    mode: box
    min_value: 0
    max_value: 6000
    initial_value: 0
    device_class: distance
    entity_category: config
    icon: mdi:arrow-up-bold
    unit_of_measurement: mm
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Zone2 Y-End
    id: zone2_y_end
    icon: mdi:arrow-down-bold
    mode: box
    min_value: 0
    max_value: 6000
    initial_value: 0
    entity_category: config
    device_class: distance
    unit_of_measurement: mm
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Zone3 X-Begin
    id: zone3_x_begin
    min_value: -4000
    max_value: 4000
    initial_value: 0
    mode: box
    device_class: distance
    entity_category: config
    unit_of_measurement: mm
    icon: mdi:arrow-left-bold
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Zone3 X-End
    id: zone3_x_end
    mode: box
    min_value: -4000
    max_value: 4000
    initial_value: 0
    device_class: distance
    unit_of_measurement: mm
    entity_category: config
    icon: mdi:arrow-right-bold
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Zone3 Y-Begin
    id: zone3_y_begin
    mode: box
    min_value: 0
    max_value: 6000
    initial_value: 0
    device_class: distance
    entity_category: config
    icon: mdi:arrow-up-bold
    unit_of_measurement: mm
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Zone3 Y-End
    id: zone3_y_end
    icon: mdi:arrow-down-bold
    mode: box
    min_value: 0
    max_value: 6000
    initial_value: 0
    entity_category: config
    device_class: distance
    unit_of_measurement: mm
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Zout1 X-Begin
    id: zone_ex1_x_begin
    min_value: -4000
    max_value: 4000
    initial_value: 0
    mode: box
    device_class: distance
    entity_category: config
    unit_of_measurement: mm
    icon: mdi:arrow-left-bold
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Zout1 X-End
    id: zone_ex1_x_end
    mode: box
    min_value: -4000
    max_value: 4000
    initial_value: 0
    device_class: distance
    unit_of_measurement: mm
    entity_category: config
    icon: mdi:arrow-right-bold
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Zout1 Y-Begin
    id: zone_ex1_y_begin
    mode: box
    min_value: 0
    max_value: 6000
    initial_value: 0
    device_class: distance
    entity_category: config
    icon: mdi:arrow-up-bold
    unit_of_measurement: mm
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: Zout1 Y-End
    id: zone_ex1_y_end
    icon: mdi:arrow-down-bold
    mode: box
    min_value: 0
    max_value: 6000
    initial_value: 0
    entity_category: config
    device_class: distance
    unit_of_measurement: mm
    step: 10
    optimistic: True
    restore_value: True
  - platform: template
    name: "Zone Any Timeout"
    id: zoneany_x_timeout
    min_value: 0
    max_value: 600
    mode: box
    device_class: duration
    entity_category: config
    unit_of_measurement: s
    icon: mdi:timer-off
    step: 1
    optimistic: True
    initial_value: 0
    restore_value: True
  - platform: template
    name: "Zone1 Timeout"
    id: zone1_x_timeout
    min_value: 0
    max_value: 600
    mode: box
    device_class: duration
    entity_category: config
    unit_of_measurement: s
    icon: mdi:timer-off
    step: 1
    optimistic: True
    initial_value: 0
    restore_value: True
  - platform: template
    name: "Zone2 Timeout"
    id: zone2_x_timeout
    min_value: 0
    max_value: 600
    mode: box
    device_class: duration
    entity_category: config
    unit_of_measurement: s
    icon: mdi:timer-off
    step: 1
    optimistic: True
    initial_value: 0
    restore_value: True
  - platform: template
    name: "Zone3 Timeout"
    id: zone3_x_timeout
    min_value: 0
    max_value: 600
    mode: box
    device_class: duration
    entity_category: config
    unit_of_measurement: s
    icon: mdi:timer-off
    step: 1
    optimistic: True
    initial_value: 0
    restore_value: True

binary_sensor:
  - platform: template
    name: "Any Presence"
    id: any_target_exsits
    device_class: occupancy
    filters:
      - delayed_off: !lambda |-
          return id(zoneany_x_timeout).state * 1000.0;
  - platform: template
    name: "Zone1 Presence"
    id: zone1_target_exsits
    device_class: occupancy
    filters:
      - delayed_off: !lambda |-
          return id(zone1_x_timeout).state * 1000.0;
  - platform: template
    name: "Zone2 Presence"
    id: zone2_target_exsits
    device_class: occupancy
    filters:
      - delayed_off: !lambda |-
          return id(zone2_x_timeout).state * 1000.0;
  - platform: template
    name: "Zone3 Presence"
    id: zone3_target_exsits
    device_class: occupancy
    filters:
      - delayed_off: !lambda |-
          return id(zone3_x_timeout).state * 1000.0;
  - platform: template
    name: "Zout1 Presence"
    id: zone_ex1_target_exsits
    icon: mdi:account-multiple-remove
    device_class: occupancy

sensor:
  - platform: template
    name: "All Target Counts"
    id: all_target_count
    accuracy_decimals: 0
    icon: "mdi:counter"
    unit_of_measurement: "targets"
  - platform: template
    name: "Zone1 Target Counts"
    id: zone1_target_count
    accuracy_decimals: 0
    icon: "mdi:counter"
    unit_of_measurement: "targets"
  - platform: template
    name: "Zone2 Target Counts"
    id: zone2_target_count
    accuracy_decimals: 0
    icon: "mdi:counter"
    unit_of_measurement: "targets"
  - platform: template
    name: "Zone3 Target Counts"
    id: zone3_target_count
    accuracy_decimals: 0
    icon: "mdi:counter"
    unit_of_measurement: "targets"
  - platform: template
    name: "Zout1 Target Counts"
    id: zone_ex1_target_count
    accuracy_decimals: 0
    icon: mdi:account-multiple-minus-outline
    unit_of_measurement: "targets"
  - platform: template
    name: "Target1 X"
    id: target1_x
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance
  - platform: template
    name: "Target1 Y"
    icon: mdi:arrow-up-down
    id: target1_y
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance
  - platform: template
    name: "Target1 Speed"
    id: target1_speed
    accuracy_decimals: 2
    unit_of_measurement: 'm/s'
    state_class: measurement
    device_class: speed
  - platform: template
    name: "Target1 Resolution"
    id: target1_resolution
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance
  - platform: template
    name: "Target2 X"
    id: target2_x
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance
    # update_interval: 1s
  - platform: template
    name: "Target2 Y"
    icon: mdi:arrow-up-down
    id: target2_y
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance
  - platform: template
    name: "Target2 Speed"
    id: target2_speed
    accuracy_decimals: 0
    unit_of_measurement: 'm/s'
    state_class: measurement
    device_class: speed
  - platform: template
    name: "Target2 Resolution"
    id: target2_resolution
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance
  - platform: template
    name: "Target3 X"
    id: target3_x
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance
  - platform: template
    name: "Target3 Y"
    icon: mdi:arrow-up-down
    id: target3_y
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance
  - platform: template
    name: "Target3 Speed"
    id: target3_speed
    accuracy_decimals: 0
    unit_of_measurement: 'm/s'
    state_class: measurement
    device_class: speed
    # update_interval: 1s
  - platform: template
    name: "Target3 Resolution"
    id: target3_resolution
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance
  - platform: template
    name: "Target1 Angle"
    id: target1_angle
    unit_of_measurement: 'Âș'
    icon: mdi:angle-acute
  - platform: template
    name: "Target2 Angle"
    id: target2_angle
    unit_of_measurement: 'Âș'
    icon: mdi:angle-acute
  - platform: template
    name: "Target3 Angle"
    id: target3_angle
    unit_of_measurement: 'Âș'
    icon: mdi:angle-acute

output:
  - platform: ledc
    pin: GPIO2
    id: led

switch:
  - platform: template
    name: Zout1 Enable
    id: zone_ex1_enable
    optimistic: True
    icon: mdi:account-cancel
    entity_category: config
    restore_mode: RESTORE_DEFAULT_OFF

button:
  - platform: restart
    icon: mdi:power-cycle
    name: "ESP Reboot"
    entity_category: diagnostic
  - platform: factory_reset
    name: Factory Reset
    disabled_by_default: false
    icon: mdi:heart-broken

uart:
  id: uart_bus
  tx_pin: 
    number: GPIO25
    mode:
      input: true
      pullup: true
  rx_pin: 
    number: GPIO32
    mode:
      input: true
      pullup: true
  baud_rate: 256000
  parity: NONE
  stop_bits: 1
  data_bits: 8
  debug:
    direction: BOTH
    dummy_receiver: True
    after:
     delimiter: [0X55, 0XCC]
    sequence:
      - lambda: |-
          if ((millis() - id(last_update_ld2450)) <= 500) {
            return;
          };
          id(last_update_ld2450) = millis();
          
          // Calc X, Y, Speed and Resolution //
          
          int16_t p1_x = (uint16_t((bytes[5] << 8) | bytes[4] ));
          if ((bytes[5] & 0x80) >> 7) {
            p1_x -= pow(2, 15);
          } else {
            p1_x = 0 - p1_x;
          }
          
          int16_t p1_y = (uint16_t((bytes[7] << 8) | bytes[6] ));
          if ((bytes[7] & 0x80) >> 7) {
            p1_y -= pow(2, 15);
          } else {
            p1_y = 0 - p1_y;
          }
          
          int p1_speed = (bytes[9] << 8 | bytes[8] );
          if ((bytes[9] & 0x80) >> 7) {
            p1_speed -= pow(2, 15);
          } else {
            p1_speed = 0 - p1_speed;
          }
          int16_t p1_distance_resolution = (uint16_t((bytes[11] << 8) | bytes[10] ));
          
          int16_t p2_x = (uint16_t((bytes[13] << 8) | bytes[12] ));
          if ((bytes[13] & 0x80) >> 7) {
            p2_x -=  pow(2, 15);
          } else {
            p2_x = 0 - p2_x;
          }
          
          int16_t p2_y = (uint16_t((bytes[15] << 8) | bytes[14] ));
          if ((bytes[15] & 0x80) >> 7) {
            p2_y -= pow(2, 15);
          } else {
            p2_y = 0 - p2_y;
          }
          
          int p2_speed = (bytes[17] << 8 | bytes[16] );
          if ((bytes[17] & 0x80) >> 7) {
            p2_speed -= pow(2, 15);
          } else {
            p2_speed = 0 - p2_speed;
          }
          int16_t p2_distance_resolution = (uint16_t((bytes[19] << 8) | bytes[18] ));
          
          int16_t p3_x = (uint16_t((bytes[21] << 8) | bytes[20] ));
          if ((bytes[21] & 0x80) >> 7) {
            p3_x -=  pow(2, 15);
          } else {
            p3_x = 0 - p3_x;
          }
          
          int16_t p3_y = (uint16_t((bytes[23] << 8) | bytes[22] ));
          if ((bytes[23] & 0x80) >> 7) {
            p3_y -= pow(2, 15);
          } else {
            p3_y = 0 - p3_y;
          }
          
          int p3_speed = (bytes[25] << 8 | bytes[24] );
          if ((bytes[25] & 0x80) >> 7) {
            p3_speed -= pow(2, 15);
          } else {
            p3_speed = 0 - p3_speed;
          }
          
          int16_t p3_distance_resolution = (uint16_t((bytes[27] << 8) | bytes[26] ));
          // Calc X, Y, Speed and Resolution //
          
          
          float p1_a = (p1_x);
          float p1_b = (p1_y);
          float p1_c = ((p1_a / p1_b) * 180 / 3.14159265359);
          if (p1_x == 0) {
            id(target1_angle).publish_state(0);
          } else {
            id(target1_angle).publish_state(p1_c);
          }
          
          float p2_a = (p2_x);
          float p2_b = (p2_y);
          float p2_c = ((p2_a / p2_b) * 180 / 3.14159265359);
          if (p2_x == 0) {
            id(target2_angle).publish_state(0);
          } else {
            id(target2_angle).publish_state(p2_c);
          }
          
          float p3_a = (p3_x);
          float p3_b = (p3_y);
          float p3_c = ((p3_a / p3_b) * 180 / 3.14159265359);
          if (p3_x == 0) {
            id(target3_angle).publish_state(0);
          } else {
            id(target3_angle).publish_state(p3_c);
          }
          
          
          int16_t area_x_min = id(area_x_begin).state; // - x_tolerance;
          int16_t area_x_max = id(area_x_end).state; // + x_tolerance;
          int16_t area_y_min = id(area_y_begin).state; // - y_tolerance;
          int16_t area_y_max = id(area_y_end).state; // + y_tolerance;
          
          int16_t area_angle_min = id(area_angle_begin).state; // + y_tolerance;
          int16_t area_angle_max = id(area_angle_end).state; // + y_tolerance;
          
          bool p1_valid = ((p1_x != 0 || p1_y > 0) && p1_x >= area_x_min && p1_x <= area_x_max && p1_y >= area_y_min && p1_y <= area_y_max && p1_c >= area_angle_min && p1_c <= area_angle_max);
          bool p2_valid = ((p2_x != 0 || p2_y > 0) && p2_x >= area_x_min && p2_x <= area_x_max && p2_y >= area_y_min && p2_y <= area_y_max && p2_c >= area_angle_min && p2_c <= area_angle_max);
          bool p3_valid = ((p3_x != 0 || p3_y > 0) && p3_x >= area_x_min && p3_x <= area_x_max && p3_y >= area_y_min && p3_y <= area_y_max && p3_c >= area_angle_min && p3_c <= area_angle_max);
          
          int16_t target_count_in_zone_ex1 = 0;
          
          int16_t zone_ex1_x_min = id(zone_ex1_x_begin).state; // - x_ex_tolerance;
          int16_t zone_ex1_x_max = id(zone_ex1_x_end).state; // + x_ex_tolerance;
          int16_t zone_ex1_y_min = id(zone_ex1_y_begin).state; // - y_ex_tolerance;
          int16_t zone_ex1_y_max = id(zone_ex1_y_end).state; // + y_ex_tolerance;
          
          bool p1_zone_ex_enter = false;
          bool p2_zone_ex_enter = false;
          bool p3_zone_ex_enter = false;
          
          if (id(zone_ex1_enable).state) {
            if (p1_valid) {
              if (p1_x >= zone_ex1_x_min && p1_x <= zone_ex1_x_max && p1_y >= zone_ex1_y_min && p1_y <= zone_ex1_y_max) {
                p1_zone_ex_enter = true;
                target_count_in_zone_ex1 ++;
              }
            }
            if (p2_valid) {
              if (p2_x >= zone_ex1_x_min && p2_x <= zone_ex1_x_max && p2_y >= zone_ex1_y_min && p2_y <= zone_ex1_y_max) {
                p2_zone_ex_enter = true;
                target_count_in_zone_ex1 ++;
              }
            }
            if (p3_valid) {
              if (p3_x >= zone_ex1_x_min && p3_x <= zone_ex1_x_max && p3_y >= zone_ex1_y_min && p3_y <= zone_ex1_y_max) {
                p3_zone_ex_enter = true;
                target_count_in_zone_ex1 ++;
              }
            }
          }
          
          bool has_target_in_zone_ex1 = (target_count_in_zone_ex1 > 0);
          
          int16_t all_target_counts = 0;
          if (p1_valid && !p1_zone_ex_enter) {
            all_target_counts ++;
          }
          if (p2_valid && !p2_zone_ex_enter) {
            all_target_counts ++;
          }
          if (p3_valid && !p3_zone_ex_enter) {
            all_target_counts ++;
          }
          
          bool has_target_in_zone_all = (all_target_counts > 0);
          
          int16_t target_count_in_zone1 = 0;
          int16_t zone1_x_min = id(zone1_x_begin).state; // - x_tolerance;
          int16_t zone1_x_max = id(zone1_x_end).state; // + x_tolerance;
          int16_t zone1_y_min = id(zone1_y_begin).state; // - y_tolerance;
          int16_t zone1_y_max = id(zone1_y_end).state; // + y_tolerance;
          
          if (p1_valid && !p1_zone_ex_enter) {
            if (p1_x >= zone1_x_min && p1_x <= zone1_x_max && p1_y >= zone1_y_min && p1_y <= zone1_y_max) {
              target_count_in_zone1 ++;
            }
          }
          if (p2_valid && !p2_zone_ex_enter) {
            if (p2_x >= zone1_x_min && p2_x <= zone1_x_max && p2_y >= zone1_y_min && p2_y <= zone1_y_max) {
              target_count_in_zone1 ++;
            }
          }
          if (p3_valid && !p3_zone_ex_enter) {
            if (p3_x >= zone1_x_min && p3_x <= zone1_x_max && p3_y >= zone1_y_min && p3_y <= zone1_y_max) {
              target_count_in_zone1 ++;
            }
          }
          bool has_target_in_zone1 = (target_count_in_zone1 > 0);
          
          int16_t target_count_in_zone2 = 0;
          int16_t zone2_x_min = id(zone2_x_begin).state; // - x_tolerance;
          int16_t zone2_x_max = id(zone2_x_end).state; // + x_tolerance;
          int16_t zone2_y_min = id(zone2_y_begin).state; // - y_tolerance;
          int16_t zone2_y_max = id(zone2_y_end).state; // + y_tolerance;
          
          if (p1_valid && !p1_zone_ex_enter) {
            if (p1_x >= zone2_x_min && p1_x <= zone2_x_max && p1_y >= zone2_y_min && p1_y <= zone2_y_max) {
              target_count_in_zone2 ++;
            }
          }
          if (p2_valid && !p2_zone_ex_enter) {
            if (p2_x >= zone2_x_min && p2_x <= zone2_x_max && p2_y >= zone2_y_min && p2_y <= zone2_y_max) {
              target_count_in_zone2 ++;
            }
          }
          if (p3_valid && !p3_zone_ex_enter) {
            if (p3_x >= zone2_x_min && p3_x <= zone2_x_max && p3_y >= zone2_y_min && p3_y <= zone2_y_max) {
              target_count_in_zone2 ++;
            }
          }
          
          bool has_target_in_zone2 = (target_count_in_zone2 > 0);
          
          int16_t target_count_in_zone3 = 0;
          int16_t zone3_x_min = id(zone3_x_begin).state; // - x_tolerance;
          int16_t zone3_x_max = id(zone3_x_end).state; // + x_tolerance;
          int16_t zone3_y_min = id(zone3_y_begin).state; // - y_tolerance;
          int16_t zone3_y_max = id(zone3_y_end).state; // + y_tolerance;
          
          if (p1_valid && !p1_zone_ex_enter) {
            if (p1_x >= zone3_x_min && p1_x <= zone3_x_max && p1_y >= zone3_y_min && p1_y <= zone3_y_max) {
              target_count_in_zone3 ++;
            }
          }
          if (p2_valid && !p2_zone_ex_enter) {
            if (p2_x >= zone3_x_min && p2_x <= zone3_x_max && p2_y >= zone3_y_min && p2_y <= zone3_y_max) {
              target_count_in_zone3 ++;
            }
          }
          if (p3_valid && !p3_zone_ex_enter) {
            if (p3_x >= zone3_x_min && p3_x <= zone3_x_max && p3_y >= zone3_y_min && p3_y <= zone3_y_max) {
              target_count_in_zone3 ++;
            }
          }
          bool has_target_in_zone3 = (target_count_in_zone3 > 0);
          
          if (id(target1_x).state != p1_x) {
            id(target1_x).publish_state(p1_x);
          }
          if (id(target1_y).state != p1_y) {
            id(target1_y).publish_state(p1_y);
          }
          
          float p1_m_speed = float(p1_speed) / 100.0;
          if (id(target1_speed).state != p1_m_speed) {
            id(target1_speed).publish_state(p1_m_speed);
          }
          if (id(target1_resolution).state != p1_distance_resolution) {
            id(target1_resolution).publish_state(p1_distance_resolution);
          }
          
          if (id(target2_x).state != p2_x) {
            id(target2_x).publish_state(p2_x);
          }
          if (id(target2_y).state != p2_y) {
            id(target2_y).publish_state(p2_y);
          }
          if (id(target2_speed).state != p2_speed) {
            id(target2_speed).publish_state(p2_speed);
          }
          if (id(target2_resolution).state != p2_distance_resolution) {
            id(target2_resolution).publish_state(p2_distance_resolution);
          }
          
          if (id(target3_x).state != p3_x) {
            id(target3_x).publish_state(p3_x);
          }
          if (id(target3_y).state != p3_y) {
            id(target3_y).publish_state(p3_y);
          }
          if (id(target3_speed).state != p3_speed) {
            id(target3_speed).publish_state(p3_speed);
          }
          if (id(target3_resolution).state != p3_distance_resolution) {
            id(target3_resolution).publish_state(p3_distance_resolution);
          }
          
          if (id(all_target_count).state != all_target_counts) {
            id(all_target_count).publish_state(all_target_counts);
          }
          if (id(any_target_exsits).state != has_target_in_zone_all) {
            id(any_target_exsits).publish_state(has_target_in_zone_all);
          }
          
          if (id(all_target_count).state != all_target_counts) {
            id(all_target_count).publish_state(all_target_counts);
          }
          if (id(any_target_exsits).state != has_target_in_zone_all) {
            id(any_target_exsits).publish_state(has_target_in_zone_all);
          }
          
          if (id(zone1_target_count).state != target_count_in_zone1) {
            id(zone1_target_count).publish_state(target_count_in_zone1);
          }
          if (id(zone1_target_exsits).state != has_target_in_zone1) {
            id(zone1_target_exsits).publish_state(has_target_in_zone1);
          }
          
          if (id(zone2_target_count).state != target_count_in_zone2) {
            id(zone2_target_count).publish_state(target_count_in_zone2);
          }
          if (id(zone2_target_exsits).state != has_target_in_zone2 ) {
            id(zone2_target_exsits).publish_state(has_target_in_zone2);
          }
          
          if (id(zone3_target_count).state != target_count_in_zone3) {
            id(zone3_target_count).publish_state(target_count_in_zone3);
          }
          if (id(zone3_target_exsits).state != has_target_in_zone3) {
            id(zone3_target_exsits).publish_state(has_target_in_zone3);
          }
          
          if (id(zone_ex1_target_count).state != target_count_in_zone_ex1) {
            id(zone_ex1_target_count).publish_state(target_count_in_zone_ex1);
          }
          
          if (id(zone_ex1_target_exsits).state != has_target_in_zone_ex1) {
            id(zone_ex1_target_exsits).publish_state(has_target_in_zone_ex1);
          }
          
          id(init_zone_publish) = true;
          
          // Angle, Position and Direction //
          
          if (p1_speed == 0) {
            id(target1_direction).publish_state("Static");
          } else if (p1_speed > 0) {
            id(target1_direction).publish_state("Moving away");
          } else if (p1_speed < 0) {
            id(target1_direction).publish_state("Approaching");
          }
          if (p2_speed == 0) {
            id(target2_direction).publish_state("Static");
          } else if (p2_speed > 0) {
            id(target2_direction).publish_state("Moving away");
          } else if (p2_speed < 0) {
            id(target2_direction).publish_state("Approaching");
          }
          if (p3_speed == 0) {
            id(target3_direction).publish_state("Static");
          } else if (p3_speed > 0) {
            id(target3_direction).publish_state("Moving away");
          } else if (p3_speed < 0) {
            id(target3_direction).publish_state("Approaching");
          }
          
          if (p1_x == 0) {
            id(target1_position).publish_state("Static");
          } else if (p1_x > 0) {
            id(target1_position).publish_state("Right");
          } else if (p1_x < 0) {
            id(target1_position).publish_state("Left");
          }
          if (p2_x == 0) {
            id(target2_position).publish_state("Static");
          } else if (p2_x > 0) {
            id(target2_position).publish_state("Right");
          } else if (p2_x < 0) {
            id(target2_position).publish_state("Left");
          }
          if (p3_x == 0) {
            id(target3_position).publish_state("Static");
          } else if (p3_x > 0) {
            id(target3_position).publish_state("Right");
          } else if (p3_x < 0) {
            id(target3_position).publish_state("Left");
          }
          
          
          if ((p1_valid) || (p2_valid) || (p3_valid)) {
          
            id(led).set_level(0.0);
          } else {
            id(led).set_level(1.0);
          }
          
          // Angle, Position and Direction //
          
2 Likes

I just saw @screek-workshop post on static detection with different mmwave sensor on the facebook group.
Apparently LD2450 doesn’t have full static detection?
That would explain why i still have to move around a bit when i was testing in a room with no interference (no fans etc)

1 Like

Hi there, I have looked all over and even asked Hi-Link with no luck. Could you tell me which connecter type you used here?

1 Like