EDIT: in this post we have been discussing the use of VL53L0X and VL53L1X to count people passing through a door. The use of the VL53L0X has been very successful but the downside is that you need two units to count people. With the VL53L1X you only need one, and people have experienced stability issues.
I also changed the title to describe this post better.
Hello everyone!
Newbie here…
I’m trying to count how many people are in a room by knowing the direction that the person passes through a door. I’m using two VL53L0X ToF sensors setting them up to provide a binary_sensor state instead of the distance by giving a true value when the distance is < than 70cm and false value when the distance is > 70cm. this part is working great. I created a flow on Node-Red to count the people and it is doing its job well. But I would like to make the ESP32 give the count value and not using Node-red to make the calculation.
Basically what I’m trying to do is store values on the “seq” variables according to the sensors states and then check if the sequence correspond to a person going IN or OUT of the room.
Here drawing for reference (credits to OnlineGuz, his post here):
This is my code on ESPHome:
esphome:
name: lab_sensors
platform: ESP32
board: esp-wrover-kit
wifi:
ssid: <deleted>
password: <deleted>
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Lab Sensors Fallback Hotspot"
password: "YcSmQRKGWols"
captive_portal:
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
i2c:
sda: GPIO21
scl: GPIO22
scan: True
id: bus_a
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'
binary_sensor:
- platform: template
id: lab_inside_door_laser
name: "Lab Inside Door Laser"
filters:
- delayed_off: 100ms
lambda: !lambda |-
return id(sens_1).state < 0.7f;
- platform: template
id: lab_outside_door_laser
name: "Lab Outside Door Laser"
filters:
- delayed_off: 100ms
lambda: !lambda |-
return id(sens_2).state < 0.7f;
- platform: gpio
pin: GPIO2
name: "Lab PIR Sensor"
device_class: motion
sensor:
- platform: template
name: "People in Lab"
lambda: !lambda |-
if(id(lab_inside_door_laser).state == false && id(lab_outside_door_laser).state == false){
seq1 = seq2;
seq2 = seq3;
seq3 = seq4;
id(seq4) = 0;
}else if(id(lab_inside_door_laser).state == false && id(lab_outside_door_laser).state == true){
seq1 = seq2;
seq2 = seq3;
seq3 = seq4;
id(seq4) = 1;
}else if(id(lab_inside_door_laser).state == true && id(lab_outside_door_laser).state == false){
seq1 = seq2;
seq2 = seq3;
seq3 = seq4;
id(seq4) = 2;
}else if(id(lab_inside_door_laser).state == true && id(lab_outside_door_laser).state == true){
seq1 = seq2;
seq2 = seq3;
seq3 = seq4;
id(seq4) = 3;
}
if(id(seq1) == 1 && id(seq2) == 3 && id(seq3) == 2 && id(seq4) == 0){
count++;
}else if(id(seq1) == 2 && id(seq2) == 3 && id(seq3) == 1 && id(seq4) == 0){
count--;
}return id(count);
- 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
- platform: adc
pin: A3
name: "Lab Illuminance"
unit_of_measurement: lx
filters:
- median:
- lambda: |-
return (x / 10000.0) * 2000000.0;
attenuation: 11db
update_interval: 5s
- platform: dht
pin: GPIO17
temperature:
filters:
- offset: -6.0
- median:
name: "Lab Temperature"
humidity:
name: "Lab Humidity"
filters:
- median:
update_interval: 5s
model: AM2302
and this is my flow on Node-Red:
[{"id":"7cba67a5.05eb88","type":"change","z":"67487c43.97ecf4","name":"inside","rules":[{"t":"set","p":"topic","pt":"msg","to":"inside","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":510,"y":80,"wires":[["cfa760ae.b9ac6"]]},{"id":"c6315233.fe28","type":"change","z":"67487c43.97ecf4","name":"outside","rules":[{"t":"set","p":"topic","pt":"msg","to":"outside","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":520,"y":160,"wires":[["cfa760ae.b9ac6"]]},{"id":"51704eaa.0141e","type":"api-call-service","z":"67487c43.97ecf4","name":"","server":"13f57a0.20e1386","version":1,"debugenabled":false,"service_domain":"input_number","service":"increment","entityId":"input_number.people_in_lab","data":"","dataType":"jsonata","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1080,"y":80,"wires":[[]]},{"id":"42f045a6.dc79bc","type":"api-call-service","z":"67487c43.97ecf4","name":"","server":"13f57a0.20e1386","version":1,"debugenabled":false,"service_domain":"input_number","service":"decrement","entityId":"input_number.people_in_lab","data":"","dataType":"jsonata","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1090,"y":160,"wires":[[]]},{"id":"cfa760ae.b9ac6","type":"function","z":"67487c43.97ecf4","name":"","func":"//get stored values if present\ncontext.set(msg.topic,msg.payload);\n\nlet inside = context.get(\"inside\");\nlet outside = context.get(\"outside\");\n\n\n\nif(inside == false && outside == false){\n msg.payload = 0;\n}\nelse if (inside == false && outside == true){\n msg.payload = 1;\n}\nelse if (inside == true && outside == false){\n msg.payload = 2;\n}\nelse {\n msg.payload = 3;\n}\n\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":620,"y":120,"wires":[["e983029b.3566d","6cf27517.220dac"]]},{"id":"e983029b.3566d","type":"sequence-detector","z":"67487c43.97ecf4","name":"Sequence Detector","watch":"payload","sequence":"1\n3\n2\n0","timeout":"3000","matchMessage":"match","resetMessage":"reset","timeoutMessage":"timeout","x":810,"y":80,"wires":[["51704eaa.0141e"],[]]},{"id":"6cf27517.220dac","type":"sequence-detector","z":"67487c43.97ecf4","name":"Sequence Detector","watch":"payload","sequence":"2\n3\n1\n0","timeout":"30000","matchMessage":"match","resetMessage":"reset","timeoutMessage":"timeout","x":810,"y":160,"wires":[["42f045a6.dc79bc"],[]]},{"id":"b770922b.e3e7b","type":"server-state-changed","z":"67487c43.97ecf4","name":"","server":"13f57a0.20e1386","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"binary_sensor.lab_inside_door_laser","entityidfiltertype":"exact","outputinitially":true,"state_type":"habool","haltifstate":"","halt_if_type":"num","halt_if_compare":"lt","outputs":1,"output_only_on_state_change":true,"for":0,"forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":true,"ignoreCurrentStateUnavailable":false,"x":230,"y":80,"wires":[["7cba67a5.05eb88"]]},{"id":"683f32b5.f73d6c","type":"server-state-changed","z":"67487c43.97ecf4","name":"","server":"13f57a0.20e1386","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"binary_sensor.lab_outside_door_laser","entityidfiltertype":"exact","outputinitially":true,"state_type":"habool","haltifstate":"","halt_if_type":"num","halt_if_compare":"lt","outputs":1,"output_only_on_state_change":true,"for":0,"forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":true,"ignoreCurrentStateUnavailable":false,"x":240,"y":160,"wires":[["c6315233.fe28"]]},{"id":"812514c7.b41b18","type":"inject","z":"67487c43.97ecf4","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":740,"y":260,"wires":[["42f045a6.dc79bc"]]},{"id":"3141f0be.35b6e","type":"inject","z":"67487c43.97ecf4","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":740,"y":220,"wires":[["51704eaa.0141e"]]},{"id":"cf203f67.dc451","type":"server-state-changed","z":"67487c43.97ecf4","name":"","server":"13f57a0.20e1386","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_number.people_in_lab","entityidfiltertype":"exact","outputinitially":true,"state_type":"num","haltifstate":"","halt_if_type":"num","halt_if_compare":"gt","outputs":1,"output_only_on_state_change":true,"for":0,"forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"x":210,"y":260,"wires":[[]]},{"id":"13f57a0.20e1386","type":"server","name":"Home Assistant","legacy":false,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true}]
Obviously my lambda is not counting, it gives the value ‘0’ all the time.
Any piece of advice from the gurus here?