Everything Presence Lite: Ignore Targets within a Zone

I recently got a bunch of Everything Presence Lites and they really are amazing as human presence sensors! They are mmWave sensors that can track slight movements from up to 3 distinct targets simultaneously. In my setup, I had to mount one unit in the ceiling above our dining table to track people eating a meal. The trouble is that a pendant light hangs between the sensor and the table, which means that whenever the pendant swings (eg. due to wind), the unit detects the light.

Fortunately they are ESPHome-based, which makes them very moddable. I modified the original code to implement an “ignore zone” where a target that falls within a certain volume of space does not get counted for the purpose of presence detection.

In a local copy of this file, add the following under the number component. This creates number entities in Home Assistant where you can specify the coordinates of the volume of space that you want to ignore:

  - platform: template
    name: "Ignore Target Begin X"
    id: ignore_target_begin_x
    max_value: 4000
    min_value: -4000
    unit_of_measurement: "mm"
    step: 10
    entity_category: config
    optimistic: True
    restore_value: True
  - platform: template
    name: "Ignore Target End X"
    id: ignore_target_end_x
    max_value: 4000
    min_value: -4000
    unit_of_measurement: "mm"
    step: 10
    entity_category: config
    optimistic: True
    restore_value: True
  - platform: template
    name: "Ignore Target Begin Y"
    id: ignore_target_begin_y
    max_value: 6000
    min_value: 0
    unit_of_measurement: "mm"
    step: 10
    entity_category: config
    optimistic: True
    restore_value: True
  - platform: template
    name: "Ignore Target End Y"
    id: ignore_target_end_y
    max_value: 6000
    min_value: 0
    unit_of_measurement: "mm"
    step: 10
    entity_category: config
    optimistic: True
    restore_value: True
  - platform: template
    name: "Ignore Target Max Angle"
    id: ignore_target_max_angle
    max_value: 90
    min_value: -90
    step: 1
    entity_category: config
    optimistic: True
    restore_value: True
    unit_of_measurement: "°"
    initial_value: 0
  - platform: template
    name: "Ignore Target Min Angle"
    id: ignore_target_min_angle
    max_value: 90
    min_value: -90
    step: 1
    entity_category: config
    optimistic: True
    restore_value: True
    unit_of_measurement: "°"
    initial_value: 0
  - platform: template
    name: "Ignore Target Max Distance"
    id: ignore_target_max_distance
    max_value: 6000
    min_value: 0
    step: 10
    entity_category: config
    optimistic: True
    restore_value: True
    unit_of_measurement: "mm"
    initial_value: 0
  - platform: template
    name: "Ignore Target Min Distance"
    id: ignore_target_min_distance
    max_value: 6000
    min_value: 0
    step: 10
    entity_category: config
    optimistic: True
    restore_value: True
    unit_of_measurement: "mm"
    initial_value: 0

Under the binary_sensor component, add the following. These return true if the corresponding target (total of 3 can be tracked simultaneously) falls inside the ignore zone:

  - platform: template
    name: Ignore Target 1
    id: ignore_target1
    lambda: |-
      return (id(target1_distance).state >= id(ignore_target_min_distance).state && id(target1_distance).state <= id(ignore_target_max_distance).state && 
              id(target1_x).state >= id(ignore_target_begin_x).state && id(target1_x).state <= id(ignore_target_end_x).state && 
              id(target1_y).state >= id(ignore_target_begin_y).state && id(target1_y).state <= id(ignore_target_end_y).state && 
              id(target1_angle).state >= id(ignore_target_min_angle).state && id(target1_angle).state <= id(ignore_target_max_angle).state);
  - platform: template
    name: Ignore Target 2
    id: ignore_target2
    lambda: |-
      return (id(target2_distance).state >= id(ignore_target_min_distance).state && id(target2_distance).state <= id(ignore_target_max_distance).state && 
              id(target2_x).state >= id(ignore_target_begin_x).state && id(target2_x).state <= id(ignore_target_end_x).state && 
              id(target2_y).state >= id(ignore_target_begin_y).state && id(target2_y).state <= id(ignore_target_end_y).state && 
              id(target2_angle).state >= id(ignore_target_min_angle).state && id(target2_angle).state <= id(ignore_target_max_angle).state);
  - platform: template
    name: Ignore Target 3
    id: ignore_target3
    lambda: |-
      return (id(target3_distance).state >= id(ignore_target_min_distance).state && id(target3_distance).state <= id(ignore_target_max_distance).state && 
              id(target3_x).state >= id(ignore_target_begin_x).state && id(target3_x).state <= id(ignore_target_end_x).state && 
              id(target3_y).state >= id(ignore_target_begin_y).state && id(target3_y).state <= id(ignore_target_end_y).state && 
              id(target3_angle).state >= id(ignore_target_min_angle).state && id(target3_angle).state <= id(ignore_target_max_angle).state);

The lambda of the uart component outputs the sensor readings reported to Home Assistant on the target coordinates. Add && not id(ignore_target1).state, && not id(ignore_target2).state, && not id(ignore_target3).state into this section of the lambda so that targets falling within the ignore zone aren’t counted as presence in that zone (in my case, the ignore zone fall within Zone 1 - a max of 4 zones can be defined).

          int zone1_count = 0;
          if (id(target1_active).state == true ) {
              if ((id(target1_x).state >= id(zone1_begin_x).state && id(target1_x).state <= id(zone1_end_x).state) &&
                  (id(target1_y).state >= id(zone1_begin_y).state && id(target1_y).state <= id(zone1_end_y).state) && 
                  not id(ignore_target1).state) {
                  zone1_count++;
              }
          }

          if (id(target2_active).state == true ) {
              if ((id(target2_x).state >= id(zone1_begin_x).state && id(target2_x).state <= id(zone1_end_x).state) &&
                  (id(target2_y).state >= id(zone1_begin_y).state && id(target2_y).state <= id(zone1_end_y).state) && 
                  not id(ignore_target2).state) {
                  zone1_count++;
              }
          }

          if (id(target3_active).state == true ) {
              if ((id(target3_x).state >= id(zone1_begin_x).state && id(target3_x).state <= id(zone1_end_x).state) &&
                  (id(target3_y).state >= id(zone1_begin_y).state && id(target3_y).state <= id(zone1_end_y).state) && 
                  not id(ignore_target3).state) {
                  zone1_count++;
              }
          }

In the ESPHome config for the unit, I then replaced dashboard_import and packages with the following (though tbh I am not quite clear what are the consequences of removing dashboard_import):

packages:
  EverythingSmartTechnology.Everything_Presence_Lite.device_base: github://everythingsmarthome/everything-presence-lite/common/everything-presence-lite-base.yaml@main
  custom_ld2450: !include path_to_your/local_copy.yaml
  EverythingSmartTechnology.Everything_Presence_Lite.bluetooth_base: github://everythingsmarthome/everything-presence-lite/common/bluetooth-base.yaml@main

With that, you can then observe the range of sensor values that the unit reports in Home Assistant when it detects the false positive that you wish to ignore. Set the min and max values of X, Y, angle and distance for the ignore zone accordingly. Then the presence status reported by the sensor will ignore any target that falls within that zone.

Hope this helps to expand your options for where you can mount one of these sensors to be most useful in your setup!

2 Likes

Very nice. I will be giving this a go at some point. Thank you.

This is really cool! Could you make a pull requests to the original repository to add this functionality? Or are you open to me making the pull request?

Hi, thanks for your feedback! Sure, please feel free to adapt this approach into a real PR for the device’s firmware. I’m afraid that is not within my capabilities at the moment!