ESPHome door monitor for the garage

We recently built a new house and boy howdy does it have a lot more doors and locks than our old house. And now that my kids are getting older they tend to leave doors unlocked / ajar and we’ve left via the garage one too many times with something unlocked. Now, I have alerts in Home Assistant that tell me when this happens after I leave home, but sometimes that’s not good because I’ve had locks jam or doors not be closed all the way so they can’t be locked remotely. To solve this, I designed and built a lite-up box that mounts to our garage wall that shows the status of all the locks and doors before we leave.


Mounted to the wall


I neglected to take a photo on the wall when it was on, so here’s one from my bench.

The design is very simple, it’s eight WS2812B addressable LEDs in series hooked up to a WeMos D1 Mini with the WeMos powering the LEDs via its 5v pin. These are then hot glued into a 3d printed case.


(Not pictured, the 330 ohm resistor on the data line that I added afterwards)

This is the flashed with ESPHome to turn on the LEDs when the garage door is opened, check all locks and doors and change the color of the light from green to red if the sensor is in a “bad” state.

substitutions:
  device_name: garage-door-alert
  front_lock: "6"
  front_status: "7"
  back_lock: "1"
  back_status: "0"
  interior_lock: "4"
  interior_status: "5"
  exterior_lock: "3"
  exterior_status: "2"

esphome:
  name: ${device_name}
  platform: ESP8266
  board: d1_mini

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_pass
  ap:
    ssid: Fallback ${device_name}
    password: "hackme"

captive_portal:

# Enable Home Assistant API
api:

ota:

script:
  - id: turn_on_lights
    then:
      - logger.log: 'Turning on lights'
      - light.turn_on:
          id: door_alert
          brightness: 1
          red: 0
          green: 0
          blue: 1
  - id: turn_off_lights
    then:
      - logger.log: 'Turning off lights'
      - light.turn_off: door_alert
  - id: change_lights
    mode: queued
    then:
      - logger.log: 'Changing lights'
      - light.addressable_set:
          id: door_alert
          range_from: ${front_lock}
          range_to: ${front_lock}
          red: !lambda "return (id(sensor_front_lock).state == \"locked\") ? 0 : 255;"
          green: !lambda "return (id(sensor_front_lock).state == \"locked\") ? 255: 0;"
          blue: 0
      - light.addressable_set:
          id: door_alert
          range_from: ${back_lock}
          range_to: ${back_lock}
          red: !lambda "return (id(sensor_back_lock).state == \"locked\") ? 0 : 255;"
          green: !lambda "return (id(sensor_back_lock).state == \"locked\") ? 255: 0;"
          blue: 0
      - light.addressable_set:
          id: door_alert
          range_from: ${interior_lock}
          range_to: ${interior_lock}
          red: !lambda "return (id(sensor_interior_lock).state == \"locked\") ? 0 : 255;"
          green: !lambda "return (id(sensor_interior_lock).state == \"locked\") ? 255: 0;"
          blue: 0
      - light.addressable_set:
          id: door_alert
          range_from: ${exterior_lock}
          range_to: ${exterior_lock}
          red: !lambda "return (id(sensor_exterior_lock).state == \"locked\") ? 0 : 255;"
          green: !lambda "return (id(sensor_exterior_lock).state == \"locked\") ? 255: 0;"
          blue: 0
      - light.addressable_set:
          id: door_alert
          range_from: ${front_status}
          range_to: ${front_status}
          red: !lambda "return (id(sensor_front_status).state) ? 255 : 0;"
          green: !lambda "return (id(sensor_front_status).state) ? 0: 255;"
          blue: 0
      - light.addressable_set:
          id: door_alert
          range_from: ${back_status}
          range_to: ${back_status}
          red: !lambda "return (id(sensor_back_status).state) ? 255 : 0;"
          green: !lambda "return (id(sensor_back_status).state) ? 0: 255;"
          blue: 0
      - light.addressable_set:
          id: door_alert
          range_from: ${interior_status}
          range_to: ${interior_status}
          red: !lambda "return (id(sensor_interior_status).state) ? 255 : 0;"
          green: !lambda "return (id(sensor_interior_status).state) ? 0: 255;"
          blue: 0
      - light.addressable_set:
          id: door_alert
          range_from: ${exterior_status}
          range_to: ${exterior_status}
          red: !lambda "return (id(sensor_exterior_status).state) ? 255 : 0;"
          green: !lambda "return (id(sensor_exterior_status).state) ? 0: 255;"
          blue: 0

text_sensor:
  - platform: homeassistant
    id: sensor_door_garage_main
    entity_id: cover.door_garage_main
    on_value:
      then:
        - if:
            condition:
              text_sensor.state:
                id: sensor_door_garage_main
                state: 'open'
            then:
              - script.execute: turn_on_lights
            else:
              - script.execute: turn_off_lights
  - platform: homeassistant
    id: sensor_front_lock
    entity_id: lock.door_front
    on_value:
      then:
        - script.execute: change_lights
  - platform: homeassistant
    id: sensor_back_lock
    entity_id: lock.door_back
    on_value:
      then:
        - script.execute: change_lights
  - platform: homeassistant
    id: sensor_interior_lock
    entity_id: lock.door_garage_interior
    on_value:
      then:
        - script.execute: change_lights
  - platform: homeassistant
    id: sensor_exterior_lock
    entity_id: lock.door_garage_exterior
    on_value:
      then:
        - script.execute: change_lights
        
binary_sensor:
  - platform: homeassistant
    id: sensor_front_status
    entity_id: binary_sensor.door_front
    on_state:
      then:
        - script.execute: change_lights
  - platform: homeassistant
    id: sensor_back_status
    entity_id: binary_sensor.door_back
    on_state:
      then:
        - script.execute: change_lights
  - platform: homeassistant
    id: sensor_interior_status
    entity_id: binary_sensor.door_garage_interior
    on_state:
      then:
        - script.execute: change_lights
  - platform: homeassistant
    id: sensor_exterior_status
    entity_id: binary_sensor.door_garage_exterior
    on_state:
      then:
        - script.execute: change_lights

light:
  - platform: fastled_clockless
    chipset: WS2812B
    rgb_order: GRB
    pin: GPIO14
    num_leds: 8
    name: "Door Alert"
    id: door_alert
    internal: true
    on_turn_on:
      - delay: 2s
      - script.execute: change_lights

If anyone is interested, I can clean up the FreeCAD design and provide STLs for all the parts.

Big thanks to @oxan for helping me with my issue calling address_set from a lambda that took this code from hideous to only terrifying.

3 Likes