Trying to increment a number using lambdas

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! :joy:

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 :joy_cat:


# 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          
3 Likes