-
-
Save kdorff/245ff51463b4845de6239deaaa21445e to your computer and use it in GitHub Desktop.
## | |
## A standard "break beam sensor" uses a laser or LED with a device on both | |
## sides of an opening and is triggered when something breaks the beam | |
## (such as a customer walking through the beam). Some garage doors use them. | |
## Stores often use them at the entrace to ring a chime when a customer enters | |
## or leaves. | |
## | |
## This is my attempt at using a VL53L0X i2c Time of Flight sensor | |
## as a break beam sensor in Home Assistant using ESPHome. | |
## | |
## The binary sensor 'breakbeam_sensor' is | |
## * A synthetic break beam that is controlled by changes | |
## to 'breakbeam_sensor_dist'. | |
## * Should only send changes when the 'beam is broken': | |
## * 'breakbeam_sensor_dist' becomes < 'minTripDistance' (or) | |
## * 'breakbeam_sensor_dist' becomes to greater than 'minTripDistance' | |
## | |
## The sensor 'breakbeam_sensor_dist' is the actual VL53L0X sensor. | |
## * The maximum reliable "open" distance seems to be to about 1.5 meters. | |
## * This sensor is marked intnernal as to not send distance data to HA. | |
## * When distance first falls less that 'minTripDistance', | |
## 'breakbeam_sensor' will turned on. | |
## * When the distance is first greater than 'minTripDistance', the | |
## 'breakbeam_sensor' will be turned off. | |
## * This will poll at 0.1s. This seems fast enough, but 1s was not. | |
## | |
esphome: | |
name: distance-sensor-0 | |
esp8266: | |
board: esp01_1m | |
# Logging (DEBUG is the standard level) | |
logger: | |
level: INFO | |
# Enable Home Assistant API | |
api: | |
ota: | |
password: "XXXXX" | |
wifi: | |
ssid: !secret wifi_ssid | |
password: !secret wifi_password | |
fast_connect: true | |
# Enable fallback hotspot (captive portal) in case wifi connection fails | |
ap: | |
ssid: "Distance-Sensor-0" | |
password: "XXXXX" | |
captive_portal: | |
# the vl53l0x is i2c | |
i2c: | |
scan: true | |
## | |
## The virutal break beam sensor. | |
## The state of this will be controlled | |
## by breakbeam_sensor_dist's lambda as necessary. | |
## | |
binary_sensor: | |
- name: "Breakbeam Sensor" | |
id: breakbeam_sensor | |
platform: template | |
device_class: motion | |
## | |
## The actual sensor. | |
## This sensor's lambda will control the state of our | |
## virtual break beam sensor, breakbeam_sensor. | |
## | |
sensor: | |
- name: "Breakbeam Sensor Dist" | |
id: breakbeam_sensor_dist | |
platform: vl53l0x | |
address: 0x29 | |
update_interval: 0.1s | |
long_range: true | |
internal: true | |
# | |
# Only send a value back if breakbeam_sensor changes. | |
# | |
filters: | |
- lambda: !lambda |- | |
/** | |
* YOU MIGHT WANT TO CONFIGURE THIS. | |
* Distance below which to trip the virtual break beam sensor. | |
* '0.5' meters is about 20 inches. | |
*/ | |
static double minTripDistance = 0.5; | |
if (x <= minTripDistance) { | |
if (id(breakbeam_sensor).state == true) { | |
// Beam was already broken | |
return {}; | |
} | |
// Beam was just broken | |
id(breakbeam_sensor).publish_state(true); | |
ESP_LOGI("breakbeam_sensor_dist", "Set breakbeam_sensor to Detected"); | |
return {}; | |
} | |
else { | |
if (id(breakbeam_sensor).state == false) { | |
// Beam was already un-broken | |
return {}; | |
} | |
// Beam was just un-broken | |
id(breakbeam_sensor).publish_state(false); | |
ESP_LOGI("breakbeam_sensor_dist", "Set breakbeam_sensor to Cleared"); | |
return {}; | |
} |
@wizardnl I cannot quite tell what you have and where it is in your code because you're not using code blocks in all places. For most effective assistance, try to submit pretty complete code samples use please use code blocks around all code so I can see exactly where things are, the formatting you've used, etc.
I see a code in text with lost formatting that I think is the same as my code sample for breakbeam_sensor_dist
. Then I see a code block, which I believe you say is problematic, but I'm lacking the larger context of where this is in your file.
For what it's worth: the filters.lamba
for breakbeam_sensor_dist2
will need to be part of the breakbeam_sensor_dist2
stanza. It kind of looks like you've tacked it on after the breakbeam_sensor_dist
lambda. Each breakbeam sensor will need have it's own filters.lambda
block. When you look at the value x
in the lambda, that is the current distance reading for a single sensor. So that filters.lambda
needs to be part of that sensor.
@wizardnl additionally you mention address: 0x41
and address: 0x42
for your breakbeams where mine is address: 0x29
(which is the default for vl53l0x). If you changed the addresses, I'm not sure why you'd need the enable_pin
.
Did you change the address on both of your vl53l0x? These seem like odd addresses.
@wizardnl additionally you mention
address: 0x41
andaddress: 0x42
for your breakbeams where mine isaddress: 0x29
(which is the default for vl53l0x). If you changed the addresses, I'm not sure why you'd need theenable_pin
.Did you change the address on both of your vl53l0x? These seem like odd addresses.
Sorry that my previous message wasn't clear. After posting, I did some more testing and, stupidly, I didn't add the filter correctly per sensor as in your example. I got it working later in the afternoon.
To answer your question, if you want to use more than one sensor, you need to change the default 0x29 address and assign an address per sensor. Also, you need to connect the enable pin (Xshunt) per sensor (https://esphome.io/components/sensor/vl53l0x.html).
I now have your code working with 3 sensors on one wemos D1. This is amazing and just what I needed. I want to automate the LED lights for my stairs, and I needed a good way to detect someone who will step on the stairs at the bottom, top, and in the middle part where I have a small platform. With your solution, I can now detect if and where the person is, and based on that, I can automate the LED lights per stair step, so the lights "walk" with you. when you go up and when you go down.
@wizardnl AWESOME! I'm glad you got it all running! Thanks for the heads up about changing address - very useful! I don't think the ESPHome driver did that when I first implemented this (or I missed it). I would have loved to have used just one.
Hello
Thank you so much for your work! It makes a great DIY sensor for my smart home. I have built 2 of them so far and plan on doing more. One of them is working flawlessly but the other one has a small issue. I use the exact code you have published on a Wemos D1 Mini. It works most of the time with no issues. The only issue comes up when there is to much light in the room. The sensor is pointing to the window. Even though it is very low and does not see the window directly, it affects its reliability. I tired to make the reading interval 0.2 seconds and it did the same. I did make it 0.05 seconds to see how long it detects false readings. The result is for just 1 reading. So, I have the idea to keep it 0.05 seconds but create a filter to only make the virtual sensor "detected" if the reading is consistent for 0.2 seconds. This way I can prevent false "detected". The problem is I do not know how to do that. Is there any chance you are able to do this? I looked for it on the internet but I have too little knowledge to understand the things on there. Yes, I could do it in the automation in HA, but it would still have a lot of traffic in my wifi. I rather solve it in the ESP controller.
Thank you so much again!
@kerimtrn
It sounds like you want to remember the last 3 readings and only trigger if the current and the previous 3 entries are correct.
I'd keep an array of readings, and keep track where you are writing in the array so you write to the array over and over. Do some reading about creating a circular buffer using an array.
Alternatively, you could look at what I did with data-smoothing.h
in https://github.com/kdorff/esphome/blob/main/cat-water-sensor/cat-water-sensor.yaml. My code in data-smoothing.h
assumes the data is an int
and would need to be changed to double
, I imagine.
Hello
Thank you for your quick answer. I actually think about simpler solution if it is possible to do. Just like a button filtering, can I use a filter to activate the virtual sensor after 0.2 seconds of activity? I use delay_on on my buttons to prevent fluctuations but it did not work for this one when I tried. Maybe I did something wrong or maybe it is not possible for this kind of entity.
The lamda
, itself, is a filter
. Look at other filtering you can do on sensor https://esphome.io/components/sensor/index.html
Perhaps sliding_window_moving_average
could be helpful? or median
or quantile
? I'm not entirely sure how they would interact with the lambda
but the docs may say or just experimentation.
@wizardnl AWESOME! I'm glad you got it all running! Thanks for the heads up about changing address - very useful! I don't think the ESPHome driver did that when I first implemented this (or I missed it). I would have loved to have used just one.
Had to try it to see if it would work with 14 sensors. ;-) In theory, I can now control every step on my stairs individually. I still need to do some intensive testing, but for now, it works. Thanks again for sharing your code.
@wizardnl Looks like you picked up the ball and ran with it. Sure would be appreciated if you shared the code you came up with in a new gist.
I'am using your script and I'am very satisfied. I would like more people to know about that, so I ask you for permission to publish the script on Home Assistant community blog. Of course all attribution goes to you, I will hide my littleness :-)
I found that HA 2024.6.0 asked for i2c for attribution to GPIO so I write
#the vl53l0x is i2c
i2c:
sda: GPIO2
scl: GPIO3
scan: true
p.s.
If I use code it brings oneliner?
# the vl53l0x is i2c i2c: sda: GPIO2 scl: GPIO3 scan: true
@wizardnl AWESOME! I'm glad you got it all running! Thanks for the heads up about changing address - very useful! I don't think the ESPHome driver did that when I first implemented this (or I missed it). I would have loved to have used just one.
Had to try it to see if it would work with 14 sensors. ;-) In theory, I can now control every step on my stairs individually. I still need to do some intensive testing, but for now, it works. Thanks again for sharing your code.
Hey @wizardnl , have you managed to actually implement this? What is the maximum cable length you have used?
In my experience vl53l0x will not work for long cables. I think i2c isn’t meant to be used that way :|
@kdorff First of all, thank you for uploading your code. It works perfectly and it's exactly what I was looking for to use within a project I'm doing for my home automation. I only need some help, if possible. I want to use your code with two sensors connected to the ESP. I got this part working by modifying your code to add the second sensor and an enable pin for each sensor.
binary_sensor:
name: "Breakbeam Sensor"
id: breakbeam_sensor
platform: template
device_class: motion
name: "Breakbeam Sensor2"
id: breakbeam_sensor2
platform: template
device_class: motion
sensor:
name: "Breakbeam Sensor Dist"
id: breakbeam_sensor_dist
platform: vl53l0x
address: 0x41
enable_pin: D3
update_interval: 500ms
long_range: true
internal: true
name: "Breakbeam Sensor Dist2"
id: breakbeam_sensor_dist2
platform: vl53l0x
address: 0x42
enable_pin: D4
update_interval: 500ms
long_range: true
internal: true
This works perfectly. However, I just can't get the filters part to work. When I add a second filter, I get errors. When I use just one filter, it works with the first sensor. I'm new to this and dont understand how to add several filters. i tried to add them per sensor but it did not work.. Could you guide me in the right direction to get the second filter working?
filters:
- lambda: !lambda |-
/**
* YOU MIGHT WANT TO CONFIGURE THIS.
* Distance below which to trip the virtual break beam sensor.
* '0.5' meters is about 20 inches.
*/
static double minTripDistance = 0.1;
if (x <= minTripDistance) {
if (id(breakbeam_sensor).state == true) {
// Beam was already broken
return {};
}
// Beam was just broken
id(breakbeam_sensor).publish_state(true);
ESP_LOGI("breakbeam_sensor_dist", "Set breakbeam_sensor to Detected");
return {};
}
else {
if (id(breakbeam_sensor).state == false) {
// Beam was already un-broken
return {};
}
// Beam was just un-broken
id(breakbeam_sensor).publish_state(false);
ESP_LOGI("breakbeam_sensor_dist", "Set breakbeam_sensor to Cleared");
return {};