People counter passing through a door using VL53L0X or VL53L1X

Where does the “f” come from/is for?

There’s also this product although continually oos due to component supply issues,

the “f” is to make sure it is comparing the values as a float variable.

Looks like a nice device, also pricey.

And the 0.7?

That is the 70cm.
That line of code is comparing the measurement from the sensor and comparing it against 0.7m, if is less than that it will return a true value meaning that something is on the path of the laser.

Ah I see… I am trying to rebuild/reuse your code to make my sensors (just 2 binairy ones) work. It works, but partially. It misses some motions…

This is what I did and have. Any help/clue appreciated to fit to my sensors greatly appreciated.

globals:
  - id: seq1
    type: int
    restore_value: no
    initial_value: '0'
  - id: seq2
    type: int
    restore_value: no
    initial_value: '0'
  - id: seq3
    type: int
    restore_value: no
    initial_value: '0'
  - id: seq4
    type: int
    restore_value: no
    initial_value: '0'
    
  - id: count
    type: int
    restore_value: no
    initial_value: '0'
    
  - id: inside_previous_value
    type: bool
    restore_value: no
    initial_value: 'false'
    
  - id: outside_previous_value
    type: bool
    restore_value: no
    initial_value: 'false'

binary_sensor:
  - platform: gpio
    pin: 
      number: GPIO21
      mode: INPUT_PULLUP
    id: sens_1
    name: "Sensor 1"
    device_class: motion
#    internal: true
    
  - platform: gpio
    pin:
      number: GPIO22
      mode: INPUT_PULLUP
    name: "Sensor 2"
    id: sens_2
    device_class: motion
#    internal: true

  - platform: template
    id: inside_door_sensor
    name: "Inside Door Sensor"
    lambda: !lambda |-
        if((id(sens_1).state < 0.7f) != id(inside_previous_value)){
          id(inside_previous_value) = (id(sens_1).state < 0.7f);
          if(((id(sens_1).state < 0.7f) == false) && ((id(sens_2).state < 0.7f) == false)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 0;
          }else if(((id(sens_1).state < 0.7f) == false) && ((id(sens_2).state < 0.7f) == true)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 1;
          }else if(((id(sens_1).state < 0.7f) == true) && ((id(sens_2).state < 0.7f) == false)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 2;
          }else if(((id(sens_1).state < 0.7f) == true) && ((id(sens_2).state < 0.7f) == true)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 3;
          }
          if((id(seq1) == 1) && (id(seq2) == 3) && (id(seq3) == 2) && (id(seq4) == 0)){
            id(count) ++;
            id(people_in).publish_state(id(count));
          }else if((id(seq1) == 2) && (id(seq2) == 3) && (id(seq3) == 1) && (id(seq4) == 0)){
            id(count) --;
            if(id(count) < 0){
              id(count) = 0;
            }
            id(people_in).publish_state(id(count));
          }
        }
        return id(sens_1).state < 0.7f;

  - platform: template
    id: outside_door_sensor
    name: "Outside Door Sensor"
    lambda: !lambda |-
        if((id(sens_2).state < 0.7f) != id(outside_previous_value)){
          id(outside_previous_value) = (id(sens_2).state < 0.7f);
          if(((id(sens_1).state < 0.7f) == false) && ((id(sens_2).state < 0.7f) == false)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 0;
          }else if(((id(sens_1).state < 0.7f) == false) && ((id(sens_2).state < 0.7f) == true)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 1;
          }else if(((id(sens_1).state < 0.7f) == true) && ((id(sens_2).state < 0.7f) == false)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 2;
          }else if(((id(sens_1).state < 0.7f) == true) && ((id(sens_2).state < 0.7f) == true)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 3;
          }
          if((id(seq1) == 1) && (id(seq2) == 3) && (id(seq3) == 2) && (id(seq4) == 0)){
            id(count)++;
            id(people_in).publish_state(id(count));
          }else if((id(seq1) == 2) && (id(seq2) == 3) && (id(seq3) == 1) && (id(seq4) == 0)){
            id(count)--;
            if(id(count) < 0){
              id(count) = 0;
            }
            id(people_in).publish_state(id(count));
          }
        }
        return id(sens_2).state < 0.7f;
        
sensor:
  - platform: template
    id: people_in
    name: "People Inside"
    lambda: !lambda |-
      return id(count);

EDIT: Disclaimer: I am no coder at all, just a copy-cat with understanding of logics (some sort of :slight_smile: )

As per your picture, you are using binary sensors, this code is made for the VL53L0X sensors that measure distance.

it should not dificult to acomodate it to binary sensors. I’ll take a look tomorrow, is too late now and my brain is not working.

1 Like

I amended like below. It now works better. But I have 1 strange behavior. When I test the setup it counts well one way and also the other way. But when I count let’s say forward it counts and when I do backward it misses the last one and vice versa. So lets say someone walks in it counts it, but walking out not and the wen walking in and out it does not count it anymore unless a second one passes. Get me :)?

globals:
  - id: seq1
    type: int
    restore_value: no
    initial_value: '0'
  - id: seq2
    type: int
    restore_value: no
    initial_value: '0'
  - id: seq3
    type: int
    restore_value: no
    initial_value: '0'
  - id: seq4
    type: int
    restore_value: no
    initial_value: '0'
    
  - id: count
    type: int
    restore_value: no
    initial_value: '0'
    
  - id: inside_previous_value
    type: bool
    restore_value: no
    initial_value: 'false'
    
  - id: outside_previous_value
    type: bool
    restore_value: no
    initial_value: 'false'

binary_sensor:
  - platform: gpio
    pin: 
      number: GPIO21
      mode: INPUT_PULLUP
    id: sens_1
    name: "Sensor 1"
    device_class: motion
#    internal: true
    
  - platform: gpio
    pin:
      number: GPIO22
      mode: INPUT_PULLUP
    name: "Sensor 2"
    id: sens_2
    device_class: motion
#    internal: true

  - platform: template
    id: inside_door_sensor
    name: "Inside Door Sensor"
    lambda: !lambda |-
        if((id(sens_1).state < 1) != id(inside_previous_value)){
          id(inside_previous_value) = (id(sens_1).state < 1);
          if(((id(sens_1).state < 1) == false) && ((id(sens_2).state < 1) == false)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 0;
          }else if(((id(sens_1).state < 1) == false) && ((id(sens_2).state < 1) == true)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 1;
          }else if(((id(sens_1).state < 1) == true) && ((id(sens_2).state < 1) == false)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 2;
          }else if(((id(sens_1).state < 1) == true) && ((id(sens_2).state < 1) == true)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 3;
          }
          if((id(seq1) == 1) && (id(seq2) == 3) && (id(seq3) == 2) && (id(seq4) == 0)){
            id(count) ++;
            id(people_in).publish_state(id(count));
          }else if((id(seq1) == 2) && (id(seq2) == 3) && (id(seq3) == 1) && (id(seq4) == 0)){
            id(count) --;
            if(id(count) < 0){
              id(count) = 0;
            }
            id(people_in).publish_state(id(count));
          }
        }
        return id(sens_1).state < 1;

  - platform: template
    id: outside_door_sensor
    name: "Outside Door Sensor"
    lambda: !lambda |-
        if((id(sens_2).state < 1) != id(outside_previous_value)){
          id(outside_previous_value) = (id(sens_2).state < 1);
          if(((id(sens_1).state < 1) == false) && ((id(sens_2).state < 1) == false)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 0;
          }else if(((id(sens_1).state < 1) == false) && ((id(sens_2).state < 1) == true)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 1;
          }else if(((id(sens_1).state < 1) == true) && ((id(sens_2).state < 1) == false)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 2;
          }else if(((id(sens_1).state < 1) == true) && ((id(sens_2).state < 1) == true)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 3;
          }
          if((id(seq1) == 1) && (id(seq2) == 3) && (id(seq3) == 2) && (id(seq4) == 0)){
            id(count)++;
            id(people_in).publish_state(id(count));
          }else if((id(seq1) == 2) && (id(seq2) == 3) && (id(seq3) == 1) && (id(seq4) == 0)){
            id(count)--;
            if(id(count) < 0){
              id(count) = 0;
            }
            id(people_in).publish_state(id(count));
          }
        }
        return id(sens_2).state < 1;
        
sensor:
  - platform: template
    id: people_in
    name: "People Inside"
    lambda: !lambda |-
      return id(count);

This should do the work

I added a 10ms de-bounce for your binary sensors and treated as a boolean on the “if” statements (on my original code I treated as a number)

globals:
  - id: seq1
    type: int
    restore_value: no
    initial_value: '0'
  - id: seq2
    type: int
    restore_value: no
    initial_value: '0'
  - id: seq3
    type: int
    restore_value: no
    initial_value: '0'
  - id: seq4
    type: int
    restore_value: no
    initial_value: '0'
    
  - id: count
    type: int
    restore_value: no
    initial_value: '0'
    
  - id: inside_previous_value
    type: bool
    restore_value: no
    initial_value: 'false'
  
  - id: outside_previous_value
    type: bool
    restore_value: no
    initial_value: 'false'
  
binary_sensor:
  - platform: gpio
    pin: 
      number: GPIO21
      mode: INPUT_PULLUP
    id: sens_1
    name: "Sensor 1"
    device_class: motion
    filters:
      - delayed_on: 10ms
#    internal: true
    
  - platform: gpio
    pin:
      number: GPIO22
      mode: INPUT_PULLUP
    name: "Sensor 2"
    id: sens_2
    device_class: motion
    filters:
      - delayed_on: 10ms
#    internal: true

  - platform: template
    id: inside_door_sensor
    name: "Inside Door Sensor"
    lambda: !lambda |-
        if(id(sens_1).state != id(inside_previous_value)){
          id(inside_previous_value) = id(sens_1).state;
          if((id(sens_1).state == false) && (id(sens_2).state == false)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 0;
          }else if((id(sens_1).state == false) && (id(sens_2).state == true)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 1;
          }else if((id(sens_1).state == true) && (id(sens_2).state == false)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 2;
          }else if((id(sens_1).state == true) && (id(sens_2).state == true)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 3;
          }
          if((id(seq1) == 1) && (id(seq2) == 3) && (id(seq3) == 2) && (id(seq4) == 0)){
            id(count) ++;
            id(people_in).publish_state(id(count));
          }else if((id(seq1) == 2) && (id(seq2) == 3) && (id(seq3) == 1) && (id(seq4) == 0)){
            id(count) --;
            if(id(count) < 0){
              id(count) = 0;
            }
            id(people_in).publish_state(id(count));
          }
        }
        return id(sens_1).state;

  - platform: template
    id: outside_door_sensor
    name: "Outside Door Sensor"
    lambda: !lambda |-
        if(id(sens_2).state != id(outside_previous_value)){
          id(outside_previous_value) = id(sens_2).state;
          if((id(sens_1).state == false) && (id(sens_2).state == false)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 0;
          }else if((id(sens_1).state == false) && (id(sens_2).state == true)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 1;
          }else if((id(sens_1).state == true) && (id(sens_2).state == false)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 2;
          }else if((id(sens_1).state == true) && (id(sens_2).state == true)){
            id(seq1) = id(seq2);
            id(seq2) = id(seq3);
            id(seq3) = id(seq4);
            id(seq4) = 3;
          }
          if((id(seq1) == 1) && (id(seq2) == 3) && (id(seq3) == 2) && (id(seq4) == 0)){
            id(count)++;
            id(people_in).publish_state(id(count));
          }else if((id(seq1) == 2) && (id(seq2) == 3) && (id(seq3) == 1) && (id(seq4) == 0)){
            id(count)--;
            if(id(count) < 0){
              id(count) = 0;
            }
            id(people_in).publish_state(id(count));
          }
        }
        return id(sens_2).state;
        
sensor:
  - platform: template
    id: people_in
    name: "People Inside"
    lambda: !lambda |-
      return id(count);
1 Like

Thank you for publishing your code. I would like to use M5Stack distance sensors M5StickC ToF HAT (VL53L0X). I guess it should work.
VL53L0X

Yeah, it should work, it uses the same chip.

Thank you!

Do you have a photo or wire diagram of the hardware? I’m very interested trying to do this at my house.

You could just implement the two beams as the A and B lines of a Rotary Encoder.
The built-in state machine would then tell your code when a person moved inward, or outward, through the beams, just as it can tell when the rotary encoder is turned one way or the other.
And it’d all be handled in one simple entity reference.

I’m testing your code and it works very well.
I have the sensors next to each other at a distance of 15 cm.
Question: you have been tested at the smallest distance it is possible to place sensors next to each other so that they do not affect each other.
Thank you

Hey @Shannondalebreaux, no, I don’t have any diagrams, but it is easy to figure it out from the code.

I’m going to omit the power part of it because it just connecting the correct voltage to the Vin pin for and the ground to the GND pin for each device.

The sensors have 3 pins for data and control, the Enable pin is setup as follow:

  - platform: vl53l0x
    name: "Sensor 1"
    id: sens_1
    i2c_id: bus_a
    address: 0x41
    update_interval: 50ms
    enable_pin: GPIO25
    timeout: 500us
    internal: true
    
    
  - platform: vl53l0x
    name: "Sensor 2"
    id: sens_2
    i2c_id: bus_a
    address: 0x42
    update_interval: 50ms
    enable_pin: GPIO32
    timeout: 500us
    internal: true

So you connect the enable pin of the sensor 1 to the GPIO25 of the ESP32 and the enable pin of the sensor 2 to the GPIO32.

Then the data pins for both sensors goes like this:

i2c:
  sda: GPIO21
  scl: GPIO22
  scan: True
  id: bus_a

Where the SDA pin of both sensors goes to the GPIO21 and the SCL to the GPIO22.

and that should be it if you are using an ESP32 and the vl53l0x sensor. You can modify the code according to your setup.

@glyndon Yeah, that was my first approach, but it didn’t work consistently. Maybe I didn’t coded it right.

@pepe59 I’m glad you find this code working good for you.

Yes, I have them separated by 6cm each other and I installed them into a door frame to count people that go in and out of my lab. It works very well.

Thank you very much. So far, I’m testing at the kitchen door on the shelf and I wanted to find out the distance from each other when I use other sensors in the door frame. Haven’t you looked at the VL53L1X sensor? Unfortunately, it does not yet have support in ESPhome, but it would also be an interesting solution.