Hio!
I’m trying to create stairway lighting using a WS2812b light strip. The idea being that when somebody enters the stairs a the bottom, the LEDs ‘wipe’ on from bottom to top. When they exit the stairs at the top, the LEDs ‘wipe’ off from bottom to top. And the same the other way round. Enter the stairs at the top, LEDs ‘wipe’ on from top to bottom, exit the stairs at the bottom, LEDs ‘wipe’ off from top to bottom.
I also want to count the number of people on the stairs so the LEDs don’t turn off until the last person exits the stairs. Typically this would only be one or two people, and nearly always a cat as well. What I don’t want is for me to start walking up the stairs, turn the lights on, then the cat passes me and turns them off before I’m at the top
I have various WLED(esp8266) devices around the house, but in this instance I want to keep everything within ESPHome as a stand alone device.
Building this on a NodeMCU ESP8266 and for testing purposes I’ve created a couple of switches for HA that turn the LEDs on and off. This works well with the ‘wipe’ effects so I know I’ve got that bit right
I’m using two VL53L0XV2 Time-of-Flight sensors for the triggers at the top and the bottom. These are both working well and returning on/off values.
I’m using Number templates as counters with on_value to trigger the wipes. I’ve not got as far as testing this so this may not be the best way of achieving this.
Where I’m struggling is getting the ToF sensors to count people passing them to trigger the wipes. Whenever I compile I get the following errors
INFO Reading configuration /config/esphome/esp-dev.yaml...
INFO Detected timezone 'Europe/London'
INFO Generating C++ source...
INFO Compiling app...
Processing esp8266-dev (board: esp01_1m; framework: arduino; platform: platformio/espressif8266 @ 3.2.0)
--------------------------------------------------------------------------------
HARDWARE: ESP8266 80MHz, 80KB RAM, 1MB Flash
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
Dependency Graph
|-- <ESPAsyncTCP-esphome> 1.2.3
|-- <ESPAsyncWebServer-esphome> 2.1.0
| |-- <ESPAsyncTCP-esphome> 1.2.3
| |-- <Hash> 1.0
| |-- <ESP8266WiFi> 1.0
|-- <DNSServer> 1.1.1
|-- <ESP8266WiFi> 1.0
|-- <ESP8266mDNS> 1.2
|-- <Wire> 1.0
|-- <NeoPixelBus> 2.6.9
| |-- <SPI> 1.0
Compiling /data/esp8266-dev/.pioenvs/esp8266-dev/src/main.cpp.o
/config/esphome/esp-dev.yaml: In lambda function:
/config/esphome/esp-dev.yaml:219:14: error: 'class esphome::number::NumberCall' has no member named 'increment'
219 | call.increment(true);
| ^~~~~~~~~
/config/esphome/esp-dev.yaml:223:14: error: 'class esphome::number::NumberCall' has no member named 'increment'
223 | call.increment(true);
| ^~~~~~~~~
/config/esphome/esp-dev.yaml:227:14: error: 'class esphome::number::NumberCall' has no member named 'decrement'
227 | call.decrement(true);
| ^~~~~~~~~
/config/esphome/esp-dev.yaml: In lambda function:
/config/esphome/esp-dev.yaml:245:14: error: 'class esphome::number::NumberCall' has no member named 'increment'
245 | call.increment(true);
| ^~~~~~~~~
*** [/data/esp8266-dev/.pioenvs/esp8266-dev/src/main.cpp.o] Error 1
========================= [FAILED] Took 12.63 seconds =========================
I’ve been reading the ESPHome docs for Number Component, Automations & Templates, Template Sensor, and Template Binary Sensor. I’ve also taken inspiration from this post
People counter passing through a door using VL53L0X or VL53L1X Big cheers to SebaVT for the inspiration!
Here’s my complete code so far
esphome:
name: esp8266-dev
esp8266:
board: esp01_1m
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
password: "dontbesilly"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
manual_ip:
static_ip: 192.168.1.150
gateway: 192.168.1.254
subnet: 255.255.255.0
dns1: 192.168.1.253
dns2: 8.8.8.8
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Esp8266-Dev Fallback Hotspot"
password: "notherebuddy"
captive_portal:
# Logical switches for testing in HA
switch:
- platform: template
id: bottom_switch
name: "Bottom Switch"
optimistic: true
turn_on_action:
- if:
condition:
light.is_off: led_master
then:
- light.turn_on:
id: led_master
effect: "Wipe In Upwards"
red: 100%
green: 71%
blue: 62%
brightness: 100%
turn_off_action:
- if:
condition:
light.is_on: led_master
then:
- light.turn_on:
id: led_master
effect: "Wipe Out Upwards"
- delay: 10s
- light.turn_off: led_master
- platform: template
id: top_switch
name: "Top Switch"
optimistic: true
turn_on_action:
- if:
condition:
light.is_off: led_master
then:
- light.turn_on:
id: led_master
effect: "Wipe In Downwards"
red: 0%
green: 100%
blue: 0%
brightness: 100%
turn_off_action:
- if:
condition:
light.is_on: led_master
then:
- light.turn_on:
id: led_master
effect: "Wipe Out Downwards"
- delay: 10s
- light.turn_off: led_master
# Get current time from HA
time:
- platform: homeassistant
id: esptime
# 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
# Logical binary sensors to convert distance to true/false
binary_sensor:
- platform: template
id: bottom_laser
name: "Bottom Laser"
filters:
- delayed_off: 100ms
lambda: !lambda |-
return id(sens_b).state < 0.5f;
- platform: template
id: top_laser
name: "Top Laser"
filters:
- delayed_off: 100ms
lambda: !lambda |-
return id(sens_t).state < 0.5f;
# 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
# Update a counter if a ToF is triggered
- platform: template
name: "Bottom Trigger"
lambda: !lambda |-
if(id(bottom_laser).state == true && id(led_master).current_values.is_on() == false && id(top_counter) == 0){
auto call = id(bottom_counter).make_call();
call.increment(true);
call.perform();
}else if(id(bottom_laser).state == true && id(led_master).current_values.is_on() == true && id(top_counter) == 0){
auto call = id(bottom_counter).make_call();
call.increment(true);
call.perform();
}else if(id(bottom_laser).state == true && id(led_master).current_values.is_on() == true && id(top_counter) != 0){
auto call = id(top_counter).make_call();
call.decrement(true);
call.perform();
}return 0;
- platform: template
name: "Top Trigger"
lambda: !lambda |-
if(id(top_laser).state == true && id(led_master).current_values.is_on() == false && id(bottom_counter) == 0){
auto call = id(top_counter).make_call();
call.increment(true);
call.perform();
}else if(id(top_laser).state == true && id(led_master).current_values.is_on() == true && id(bottom_counter) == 0){
auto call = id(top_counter).make_call();
call.increment(true);
call.perform();
}else if(id(top_laser).state == true && id(led_master).current_values.is_on() == true && id(bottom_counter) != 0){
auto call = id(bottom_counter).make_call();
call.decrement(true);
call.perform();
}return 0;
# Counters for stair entry at either top or bottom
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%
else:
- light.turn_on:
id: led_master
effect: "Wipe Out Downwards"
- delay: 6s
- 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%
else:
- light.turn_on:
id: led_master
effect: "Wipe Out Upwards"
- delay: 6s
- light.turn_off: led_master
I’m no coder so it’s entirely possible that my code might be complete rubbish
Can anyone provide any pointers as to where I’m going wrong with the lambda’s, or am I just approaching this from an angle that simply won’t work or doesn’t make any sense.