So after a few more hours of trying things, I’ve got this working, to the point I’m happy to move on to the hardware installation and sensor callibration.
I’ve learned to not over complicate things, that there’s a key fundamental difference between a sensor and a binary_sensor, and also that (unsurprisingly) working with yaml is a lot easier that lambdas!
So, I’ve moved the lambda conditions from a sensor to a binary sensor, as this now returns a simple true/false rather than repeated values. I’ve also consolidated most of the conditions into yaml rather than lambdas.
I’ve stuck with incrementing/decrementing numbers for counters rather than variables, as these will still trigger the appropriate lighting effect on_value. I’ve also introduced a timeout for those occasions where an animal (or a human) changes their mind half way up or down the stairs
# Control of LED strip including up/down and on/off wipes
light:
- platform: neopixelbus
variant: WS2812X
id: led_master
pin: 3
num_leds: 254
type: GRB
name: "Stairway"
effects:
- addressable_lambda:
name: "Wipe In Upwards"
lambda: |-
static int x = 0;
if (initial_run) {
x = 0;
it.all() = ESPColor(0,0,0);
}
if (x < it.size()) {
it[x] = current_color;
x += 1;
}
- addressable_lambda:
name: "Wipe In Downwards"
lambda: |-
static int x = 0;
if (initial_run) {
x = it.size();
it.all() = ESPColor(0,0,0);
}
if (x > 0) {
x -= 1;
it[x] = current_color;
}
- addressable_lambda:
name: "Wipe Out Upwards"
lambda: |-
static int x = 0;
if (initial_run) {
x = 0;
it.all() = current_color;
}
if (x < it.size()) {
it[x] = ESPColor(0,0,0);
x += 1;
}
- addressable_lambda:
name: "Wipe Out Downwards"
lambda: |-
static int x = 0;
if (initial_run) {
x = it.size();
}
if (x > 0) {
x -= 1;
it[x] = ESPColor(0,0,0);
}
# Open up the i2c bus for connecting the ToF sensors
i2c:
sda: GPIO4
scl: GPIO5
id: bus_a
scan: true
# Add both ToF sensors
sensor:
- platform: vl53l0x
name: "Sensor Bot"
id: sens_b
i2c_id: bus_a
address: 0x41
update_interval: 1s
enable_pin: GPIO2
timeout: 500us
internal: true
- platform: vl53l0x
name: "Sensor Top"
id: sens_t
i2c_id: bus_a
address: 0x42
update_interval: 1s
enable_pin: GPIO14
timeout: 500us
internal: true
# Logical binary sensors to work the lighting magic
#
# These do a number of things :
# - Check if maximum calculated distance has been reduced (triggered), and return a state of TRUE
# - If state is TRUE then trun the lights on or off
# - If state is also TRUE, then increment or decrement the top or bpttom counters
#
# Changing the counter value will cause the LED strip to be turned on with the appropriate effect
#
binary_sensor:
- platform: template
id: bottom_laser
name: "Bottom Laser"
filters:
- delayed_off: 100ms
lambda: |-
return id(sens_b).state < 0.5f;
on_state:
- if:
condition:
- lambda: return id(bottom_laser).state == true;
- number.in_range:
id: top_counter
below: 0
- light.is_off: led_master
then:
- number.increment:
id: bottom_counter
cycle: false
else:
- if:
condition:
- lambda: return id(bottom_laser).state == true;
- number.in_range:
id: top_counter
below: 0
- light.is_on: led_master
then:
- number.increment:
id: bottom_counter
cycle: false
else:
- if:
condition:
- lambda: return id(bottom_laser).state == true;
- number.in_range:
id: top_counter
above: 1
then:
- number.decrement:
id: top_counter
cycle: false
- platform: template
id: top_laser
name: "Top Laser"
filters:
- delayed_off: 100ms
lambda: !lambda |-
return id(sens_t).state < 0.5f;
on_state:
- if:
condition:
- lambda: return id(top_laser).state == true;
- number.in_range:
id: bottom_counter
below: 0
- light.is_off: led_master
then:
- number.increment:
id: top_counter
cycle: false
else:
- if:
condition:
- lambda: return id(top_laser).state == true;
- number.in_range:
id: bottom_counter
below: 0
- light.is_on: led_master
then:
- number.increment:
id: top_counter
cycle: false
else:
- if:
condition:
- lambda: return id(top_laser).state == true;
- number.in_range:
id: bottom_counter
above: 1
then:
- number.decrement:
id: bottom_counter
cycle: false
# Counters for stair entry at either top or bottom
#
# These counters will tuen the LED strip on/off depending on the counter value
# - >= 1turn on LED strip
# - =< 0 turn off LED strip
#
# Also implements a delay and counter reset. Useful if somebody enters the stairs at one point, then changes their mind
# and exits the stairs at the same point.
#
number:
- platform: template
name: "Bottom Stair Counter"
id: bottom_counter
optimistic: true
step: 1
min_value: 0
max_value: 10
on_value:
- if:
condition:
- number.in_range:
id: bottom_counter
above: 1
- light.is_off: led_master
then:
- light.turn_on:
id: led_master
effect: "Wipe In Upwards"
red: 100%
green: 71%
blue: 62%
brightness: 100%
- delay: 120s
- number.to_min: bottom_counter
else:
- if:
condition:
- number.in_range:
id: bottom_counter
below: 0
- light.is_on: led_master
then:
- light.turn_on:
id: led_master
effect: "Wipe Out Upwards"
- delay: 5s
- light.turn_off: led_master
- platform: template
name: "Top Stair Counter"
id: top_counter
optimistic: true
step: 1
min_value: 0
max_value: 10
on_value:
- if:
condition:
- number.in_range:
id: top_counter
above: 1
- light.is_off: led_master
then:
- light.turn_on:
id: led_master
effect: "Wipe In Downwards"
red: 100%
green: 71%
blue: 62%
brightness: 100%
- delay: 120s
- number.to_min: top_counter
else:
- if:
condition:
- number.in_range:
id: top_counter
below: 0
- light.is_on: led_master
then:
- light.turn_on:
id: led_master
effect: "Wipe Out Downwards"
- delay: 5s
- light.turn_off: led_master