LED "Smart" Garage Lighting with Parking Assist

This is easily one of my favourite garage hacks ever. I have three LED segments around the door, LEFT, REAR (top of door) and RIGHT which turn green, yellow, red, or flashing red to guide (my daughter mostly) to park in the correct spot so car doors don’t hit the lift posts, and the car is correctly distanced from the garage door. This YT short (about 2 minutes) pretty much illustrates how the system works. Links for all the bits you’d need to replicate this project are in the YT description.

Click the pic to play the 2 minute YT system overview:

IMU0OyhuIqj-k

The project uses Home Assistant and the ESPHome integration to program three ultrasonic (and quite accurate!) distance sensors. ESPHome makes this super easy and there are only three wires to connect up. This control panel in Home Assistant lets you enter the distances you want for the red, yellow, green parking/LED ranges. I will likely use this all the time (for live distances) to get cars correctly positioned for lifting on the hoist as I otherwise usually park, get out, reposition, then repeat one or two times.

These are the bits for each distance sensor:

This is the pinout for the $7 ESP32 board. You’re only connecting three wires to it: ESP32 VIN to Sensor RED, ESP 32 GND to sensor BLACK and ESP32 TXD2 (Pin27) to sensor WHITE.

Here’s one of three sensors. WIFI connected, powered by USB. Less than a watt each for power use.

View from the car if you get it right. This is a 300 LED strip (BTF 6812) that is segmented in the WLED controller so that left is LEDs 0-100, center is LEDs 100-200, and right is LEDs 200-300. I’ve cut the LED strip at these points and soldered on wiring extensions to each strip so that I could use just the one WLED controller and 12V power supply.

Code that you can use to program the $7 ESP32 board in ESPHome to work with the $30 ultrasonic distance sensor:

# Board: DOIT ESP32 DEVKIT V1



# Distance sensor: A02YYUW UART

#

# Wiring:

# Sensor red    -> ESP32 VIN / 5V

# Sensor black  -> ESP32 GND

# Sensor white  -> ESP32 RX2 / GPIO16

# Sensor yellow -> Not connected



esphome:

  name: garage-distance-sensor-left

  friendly_name: Garage Distance Sensor Left



esp32:

  board: esp32doit-devkit-v1

  framework:

    type: esp-idf



logger:

  level: INFO



api:

  encryption:

    key: "YOUR ESPHOME NATIVE API"



ota:

  - platform: esphome



wifi:

  ssid: !secret wifi_ssid

  password: !secret wifi_password

  power_save_mode: none



  ap:

    ssid: "Garage Distance Fallback Hotspot"

    password: "YOUR SECRET PASSWORD"



captive_portal:



uart:

  id: distance_sensor_uart

  rx_pin: GPIO16

  baud_rate: 9600

  data_bits: 8

  parity: NONE

  stop_bits: 1



sensor:

  - platform: a02yyuw

    id: garage_left_distance

    name: "Left Garage Distance"

    uart_id: distance_sensor_uart

    unit_of_measurement: "cm"

    accuracy_decimals: 1

    device_class: distance

    state_class: measurement



    filters:

      # Convert millimetres to centimetres.

      - multiply: 0.1



      # Reject isolated false readings caused by ultrasonic crosstalk.

      - median:

          window_size: 5

          send_every: 3

          send_first_at: 1



  - platform: wifi_signal

    name: "Wi-Fi Signal"

    update_interval: 60s



  - platform: uptime

    name: "Uptime"



button:

  - platform: restart

    name: "Restart"

These are the generic entities you would need to replace in the code below:

binary_sensor.garage_door_contact

binary_sensor.garage_motion

sensor.garage_distance_left

sensor.garage_distance_rear

sensor.garage_distance_right

light.garage_wled_master

light.garage_wled_left_segment

light.garage_wled_rear_segment

light.garage_wled_right_segment

switch.garage_side_lights

light.garage_auxiliary_strip

This is the automation code (santized) used in Home Assistant to control the lights for parking:

# Sanitized Home Assistant package: Garage LED Parking Guidance

#

# Place this file under /config/packages/ and enable packages in configuration.yaml:

#

# homeassistant:

#   packages: !include_dir_named packages

#

# Replace the generic entity IDs below with your own entities.

# No IP addresses, encryption keys, Wi-Fi credentials, device IDs, or personal names

# are included in this version.



input_number:

  garage_side_off_distance:

    name: Garage Side - Off Distance

    min: 0

    max: 400

    step: 1

    unit_of_measurement: cm

    mode: box

    initial: 60



  garage_side_green_distance:

    name: Garage Side - Green Distance

    min: 0

    max: 400

    step: 1

    unit_of_measurement: cm

    mode: box

    initial: 50



  garage_side_yellow_distance:

    name: Garage Side - Yellow Distance

    min: 0

    max: 400

    step: 1

    unit_of_measurement: cm

    mode: box

    initial: 45



  garage_side_red_distance:

    name: Garage Side - Red Distance

    min: 0

    max: 400

    step: 1

    unit_of_measurement: cm

    mode: box

    initial: 40



  garage_rear_off_distance:

    name: Garage Rear - Off Distance

    min: 0

    max: 400

    step: 1

    unit_of_measurement: cm

    mode: box

    initial: 205



  garage_rear_red_distance:

    name: Garage Rear - Red Distance

    min: 0

    max: 400

    step: 1

    unit_of_measurement: cm

    mode: box

    initial: 195



  garage_rear_yellow_distance:

    name: Garage Rear - Yellow Distance

    min: 0

    max: 400

    step: 1

    unit_of_measurement: cm

    mode: box

    initial: 181



  garage_rear_green_distance:

    name: Garage Rear - Green Distance

    min: 0

    max: 400

    step: 1

    unit_of_measurement: cm

    mode: box

    initial: 170



automation:

  - id: sanitized_garage_parking_guidance

    alias: Garage Parking Guidance

    description: >-

      Uses left, rear, and right distance sensors to control three WLED

      segments while a vehicle backs into the garage.

    mode: restart



    triggers:

      # This example assumes the door contact is ON when the door is open.

      # Reverse the states if your contact reports the opposite way.

      - trigger: state

        entity_id: binary_sensor.garage_door_contact

        from: "off"

        to: "on"

        id: door_open



      - trigger: state

        entity_id: binary_sensor.garage_door_contact

        from: "on"

        to: "off"

        id: door_closed



      # Allows a manual WLED master-off command to stop the session.

      - trigger: state

        entity_id: light.garage_wled_master

        from: "on"

        to: "off"

        id: master_off



    conditions: []



    actions:

      - choose:

          - conditions:

              - condition: trigger

                id: door_open

            sequence:

              - action: light.turn_on

                target:

                  entity_id: light.garage_wled_master

                data:

                  brightness_pct: 100



              - delay:

                  milliseconds: 750



              - variables:

                  session_started: "{{ as_timestamp(now()) }}"

                  last_movement: "{{ as_timestamp(now()) }}"

                  movement_seen: false



                  left_reference: >-

                    {{ states('sensor.garage_distance_left') | float(9999) }}

                  rear_reference: >-

                    {{ states('sensor.garage_distance_rear') | float(9999) }}

                  right_reference: >-

                    {{ states('sensor.garage_distance_right') | float(9999) }}



              - repeat:

                  while:

                    - condition: template

                      value_template: >-

                        {% set now_ts = as_timestamp(now()) %}

                        {% set elapsed = now_ts - (session_started | float) %}

                        {% set inactive = now_ts - (last_movement | float) %}

                        {{

                          is_state('light.garage_wled_master', 'on')

                          and elapsed < 180

                          and (

                            ((not (movement_seen | bool)) and elapsed < 120)

                            or

                            ((movement_seen | bool) and inactive < 20)

                          )

                        }}



                  sequence:

                    - variables:

                        current_left: >-

                          {{ states('sensor.garage_distance_left') | float(9999) }}

                        current_rear: >-

                          {{ states('sensor.garage_distance_rear') | float(9999) }}

                        current_right: >-

                          {{ states('sensor.garage_distance_right') | float(9999) }}



                    # Meaningful movement: 2 cm on either side or 3 cm at rear.

                    - if:

                        - condition: template

                          value_template: >-

                            {{

                              ((current_left | float) - (left_reference | float)) | abs >= 2

                              or

                              ((current_rear | float) - (rear_reference | float)) | abs >= 3

                              or

                              ((current_right | float) - (right_reference | float)) | abs >= 2

                            }}

                      then:

                        - variables:

                            movement_seen: true

                            last_movement: "{{ as_timestamp(now()) }}"

                            left_reference: "{{ current_left }}"

                            rear_reference: "{{ current_rear }}"

                            right_reference: "{{ current_right }}"



                    # LEFT SEGMENT

                    # >= off: off

                    # >= green: green

                    # >= yellow: yellow

                    # >= red: solid red

                    # below red: flashing red

                    - choose:

                        - conditions:

                            - condition: template

                              value_template: >-

                                {{

                                  (current_left | float) >=

                                  states('input_number.garage_side_off_distance') | float

                                }}

                          sequence:

                            - action: light.turn_off

                              target:

                                entity_id: light.garage_wled_left_segment



                        - conditions:

                            - condition: template

                              value_template: >-

                                {{

                                  (current_left | float) >=

                                  states('input_number.garage_side_green_distance') | float

                                }}

                          sequence:

                            - action: light.turn_on

                              target:

                                entity_id: light.garage_wled_left_segment

                              data:

                                brightness_pct: 100

                                effect: Solid

                                rgb_color: [0, 255, 0]



                        - conditions:

                            - condition: template

                              value_template: >-

                                {{

                                  (current_left | float) >=

                                  states('input_number.garage_side_yellow_distance') | float

                                }}

                          sequence:

                            - action: light.turn_on

                              target:

                                entity_id: light.garage_wled_left_segment

                              data:

                                brightness_pct: 100

                                effect: Solid

                                rgb_color: [255, 180, 0]



                        - conditions:

                            - condition: template

                              value_template: >-

                                {{

                                  (current_left | float) >=

                                  states('input_number.garage_side_red_distance') | float

                                }}

                          sequence:

                            - action: light.turn_on

                              target:

                                entity_id: light.garage_wled_left_segment

                              data:

                                brightness_pct: 100

                                effect: Solid

                                rgb_color: [255, 0, 0]



                      default:

                        - action: light.turn_on

                          target:

                            entity_id: light.garage_wled_left_segment

                          data:

                            brightness_pct: 100

                            effect: Blink

                            rgb_color: [255, 0, 0]



                    # REAR SEGMENT

                    # Too far: off, then red/yellow/green as the target is approached.

                    # Closer than the green zone: flashing red.

                    - choose:

                        - conditions:

                            - condition: template

                              value_template: >-

                                {{

                                  (current_rear | float) >

                                  states('input_number.garage_rear_off_distance') | float

                                }}

                          sequence:

                            - action: light.turn_off

                              target:

                                entity_id: light.garage_wled_rear_segment



                        - conditions:

                            - condition: template

                              value_template: >-

                                {{

                                  (current_rear | float) >=

                                  states('input_number.garage_rear_red_distance') | float

                                }}

                          sequence:

                            - action: light.turn_on

                              target:

                                entity_id: light.garage_wled_rear_segment

                              data:

                                brightness_pct: 100

                                effect: Solid

                                rgb_color: [255, 0, 0]



                        - conditions:

                            - condition: template

                              value_template: >-

                                {{

                                  (current_rear | float) >=

                                  states('input_number.garage_rear_yellow_distance') | float

                                }}

                          sequence:

                            - action: light.turn_on

                              target:

                                entity_id: light.garage_wled_rear_segment

                              data:

                                brightness_pct: 100

                                effect: Solid

                                rgb_color: [255, 180, 0]



                        - conditions:

                            - condition: template

                              value_template: >-

                                {{

                                  (current_rear | float) >=

                                  states('input_number.garage_rear_green_distance') | float

                                }}

                          sequence:

                            - action: light.turn_on

                              target:

                                entity_id: light.garage_wled_rear_segment

                              data:

                                brightness_pct: 100

                                effect: Solid

                                rgb_color: [0, 255, 0]



                      default:

                        - action: light.turn_on

                          target:

                            entity_id: light.garage_wled_rear_segment

                          data:

                            brightness_pct: 100

                            effect: Blink

                            rgb_color: [255, 0, 0]



                    # RIGHT SEGMENT: same thresholds as the left segment.

                    - choose:

                        - conditions:

                            - condition: template

                              value_template: >-

                                {{

                                  (current_right | float) >=

                                  states('input_number.garage_side_off_distance') | float

                                }}

                          sequence:

                            - action: light.turn_off

                              target:

                                entity_id: light.garage_wled_right_segment



                        - conditions:

                            - condition: template

                              value_template: >-

                                {{

                                  (current_right | float) >=

                                  states('input_number.garage_side_green_distance') | float

                                }}

                          sequence:

                            - action: light.turn_on

                              target:

                                entity_id: light.garage_wled_right_segment

                              data:

                                brightness_pct: 100

                                effect: Solid

                                rgb_color: [0, 255, 0]



                        - conditions:

                            - condition: template

                              value_template: >-

                                {{

                                  (current_right | float) >=

                                  states('input_number.garage_side_yellow_distance') | float

                                }}

                          sequence:

                            - action: light.turn_on

                              target:

                                entity_id: light.garage_wled_right_segment

                              data:

                                brightness_pct: 100

                                effect: Solid

                                rgb_color: [255, 180, 0]



                        - conditions:

                            - condition: template

                              value_template: >-

                                {{

                                  (current_right | float) >=

                                  states('input_number.garage_side_red_distance') | float

                                }}

                          sequence:

                            - action: light.turn_on

                              target:

                                entity_id: light.garage_wled_right_segment

                              data:

                                brightness_pct: 100

                                effect: Solid

                                rgb_color: [255, 0, 0]



                      default:

                        - action: light.turn_on

                          target:

                            entity_id: light.garage_wled_right_segment

                          data:

                            brightness_pct: 100

                            effect: Blink

                            rgb_color: [255, 0, 0]



                    - delay:

                        milliseconds: 250



              - action: light.turn_off

                target:

                  entity_id:

                    - light.garage_wled_left_segment

                    - light.garage_wled_rear_segment

                    - light.garage_wled_right_segment

                    - light.garage_wled_master



          - conditions:

              - condition: trigger

                id:

                  - door_closed

                  - master_off

            sequence:

              - action: light.turn_off

                target:

                  entity_id:

                    - light.garage_wled_left_segment

                    - light.garage_wled_rear_segment

                    - light.garage_wled_right_segment

                    - light.garage_wled_master



  - id: sanitized_garage_motion_white_lighting

    alias: Garage Motion White Lighting

    description: >-

      Turns the full WLED strip on in neutral white when garage motion is

      detected, except while parking guidance is active.

    mode: restart



    triggers:

      - trigger: state

        entity_id: binary_sensor.garage_motion

        from: "off"

        to: "on"

        id: motion_detected



      - trigger: state

        entity_id: binary_sensor.garage_motion

        from: "on"

        to: "off"

        for:

          minutes: 5

        id: motion_cleared



      - trigger: state

        entity_id: automation.garage_parking_guidance

        attribute: current

        from: 1

        to: 0

        id: parking_finished



    conditions: []



    actions:

      - choose:

          - conditions:

              - condition: trigger

                id:

                  - motion_detected

                  - parking_finished

              - condition: state

                entity_id: binary_sensor.garage_motion

                state: "on"

              - condition: template

                value_template: >-

                  {{

                    state_attr('automation.garage_parking_guidance', 'current')

                    | int(0) == 0

                  }}

            sequence:

              - action: light.turn_on

                target:

                  entity_id: light.garage_wled_master

                data:

                  brightness_pct: 100



              - delay:

                  milliseconds: 250



              # RGB approximation of roughly 5000 K. Adjust for your strip.

              - action: light.turn_on

                target:

                  entity_id:

                    - light.garage_wled_left_segment

                    - light.garage_wled_rear_segment

                    - light.garage_wled_right_segment

                data:

                  brightness_pct: 100

                  effect: Solid

                  rgb_color: [255, 228, 206]



          - conditions:

              - condition: trigger

                id: motion_cleared

              - condition: template

                value_template: >-

                  {{

                    state_attr('automation.garage_parking_guidance', 'current')

                    | int(0) == 0

                  }}

            sequence:

              - action: light.turn_off

                target:

                  entity_id:

                    - light.garage_wled_left_segment

                    - light.garage_wled_rear_segment

                    - light.garage_wled_right_segment

                    - light.garage_wled_master



  - id: sanitized_garage_auxiliary_lights_motion

    alias: Garage Auxiliary Lights - Motion

    description: >-

      Controls the non-WLED garage lights from motion. Parking guidance is

      allowed to keep them on after motion clears.

    mode: restart



    triggers:

      - trigger: state

        entity_id: binary_sensor.garage_motion

        from: "off"

        to: "on"

        id: motion_on



      - trigger: state

        entity_id: binary_sensor.garage_motion

        from: "on"

        to: "off"

        for:

          minutes: 5

        id: motion_off



    conditions: []



    actions:

      - choose:

          - conditions:

              - condition: trigger

                id: motion_on

            sequence:

              - action: homeassistant.turn_on

                target:

                  entity_id:

                    - switch.garage_side_lights

                    - light.garage_auxiliary_strip



          - conditions:

              - condition: trigger

                id: motion_off

              - condition: template

                value_template: >-

                  {{

                    state_attr('automation.garage_parking_guidance', 'current')

                    | int(0) == 0

                  }}

            sequence:

              - action: homeassistant.turn_off

                target:

                  entity_id:

                    - switch.garage_side_lights

                    - light.garage_auxiliary_strip



  - id: sanitized_garage_auxiliary_lights_parking

    alias: Garage Auxiliary Lights - Parking Guidance

    description: >-

      Turns auxiliary garage lights on during parking guidance, then turns

      them off afterward only when no motion remains.

    mode: restart



    triggers:

      - trigger: state

        entity_id: automation.garage_parking_guidance

        attribute: current

        from: 0

        to: 1

        id: parking_started



      - trigger: state

        entity_id: automation.garage_parking_guidance

        attribute: current

        from: 1

        to: 0

        id: parking_finished



    conditions: []



    actions:

      - choose:

          - conditions:

              - condition: trigger

                id: parking_started

            sequence:

              - action: homeassistant.turn_on

                target:

                  entity_id:

                    - switch.garage_side_lights

                    - light.garage_auxiliary_strip



          - conditions:

              - condition: trigger

                id: parking_finished

              - condition: state

                entity_id: binary_sensor.garage_motion

                state: "off"

            sequence:

              - action: homeassistant.turn_off

                target:

                  entity_id:

                    - switch.garage_side_lights

                    - light.garage_auxiliary_strip
3 Likes