To avoid these ads, REGISTER NOW!

LED "Smart" Garage Lighting with Parking Assist!

Denwood

Well-known member
Joined
Sep 22, 2014
Messages
4,291
Location
Thunder Bay, Ontario, Canada
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.


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.

1784642961821.png

These are the bits for each distance sensor:

1784644023563.png

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.

1784642704164.png

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

1784643150466.png

View from the car if you get it right:

1784643195147.png



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

Code:
# 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:

Code:
# 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
 
Last edited:
To avoid these ads, REGISTER NOW!
OP
D

Denwood

Well-known member
Joined
Sep 22, 2014
Messages
4,291
Location
Thunder Bay, Ontario, Canada
Thanks @Stuart in MN :cool:

It was about 7-8 hours to put everything together, but it's maybe my favourite project in the shop ever. I am a bit of newbie to Home Assistant and ESPHome, but the cost of the software (free) and sensors (cheap) along with ability to use AI to help code made this all pretty easy to do.
 
To avoid these ads, REGISTER NOW!
OP
D

Denwood

Well-known member
Joined
Sep 22, 2014
Messages
4,291
Location
Thunder Bay, Ontario, Canada
Only the Bat Cave is a rival.
I'd take the Bat Cave any day over my 16x24 teeny shop :) But I'll take that compliment!
Very nice!

Now just send me one with a Venmo request.
There are parking aid products out there that are pretty inexpensive using the red/yellow/green thing, but the display is pretty small and they seem to just target setup for the back or rear. None I've seen integrate with LED strips, cover 3 sides, and none are wireless. Now if you were using Home Assistant already and have an afternoon to spare, you could build your own :) . With parts all in, including the LED strip and LED controller, you're likely at about $250 USD.
 

dave*99

Well-known member
Joined
May 5, 2009
Messages
4,325
Location
Coastal NJ
I could use that in the bay my wife parks in, but the price of divorce just ain't worth it.
Nice work though.

How do you handle vehicle size variations in the lift bay? I could imagine checking side distances for equality but the depth I spot my pickup at is quite different than when I lift a sports car.
 
OP
D

Denwood

Well-known member
Joined
Sep 22, 2014
Messages
4,291
Location
Thunder Bay, Ontario, Canada
The distances red circled below are displayed live. The data is updated a few times per second. So rather than program the red/yellow/green distances in that dashboard, I would just use a cheat sheet for each vehicle and pop my phone onto the dash while getting the car oriented for the lift. Our Highlander for example is relatively wide, so I park it closer to the passenger side post so I can get out!

Come to think of it, I'll just update the dasboard so I can directly enter target values for specific vehicles...good idea!! It seems that I often park, turn the car off then get back 1 or 2 times to get things right. This will just make that a bit quicker and more precise :)

1784831040423.png
 
To avoid these ads, REGISTER NOW!
Top Bottom