Skip to content

Instantly share code, notes, and snippets.

@billchurch
Last active June 2, 2024 12:08
Show Gist options
  • Save billchurch/787fd7b0032889c7bad0871981c5c5bd to your computer and use it in GitHub Desktop.
Save billchurch/787fd7b0032889c7bad0871981c5c5bd to your computer and use it in GitHub Desktop.
An example of an ESPHome based light (martin jerry MJ-S01) with an on-device timer
substitutions:
device_name: garage-light
friendly_name: Garage Light
default_delay: '900' # default delay of 15 minutes (900 seconds)
pre_off_warning: '30' # pre-off warning period in seconds
location: Garage
ha_timer_number: input_number.garage_light_timer
switch_name: Garage Interior Light Switch
motion_sensor_name: binary_sensor.motion_garage_motion_2
esphome:
name: ${device_name}
comment: ${friendly_name}
platform: ESP8266
board: esp01_1m
esp8266_restore_from_flash: true
globals:
- id: delay_length_global
type: int
restore_value: yes
initial_value: ${default_delay}
- id: flash_count
type: int
restore_value: no
initial_value: '0'
wifi:
ssid: !secret wifissid
password: !secret wifipass
fast_connect: off
domain: !secret domain
power_save_mode: none
ap:
ssid: "${device_name} Fallback Hotspot"
password: !secret wifipass
logger:
baud_rate: 0
api:
encryption:
key: !secret esphome_key
reboot_timeout: 0s
services:
- service: start_${device_name}_timer
then:
- script.execute: start_timer
- service: update_delay_length
variables:
delay_length: int
then:
- lambda: |-
id(delay_length_global) = delay_length;
ESP_LOGD("main", "Delay length updated to %d seconds", delay_length);
id(start_timer).execute();
ota:
# Device Specific Config
output:
- platform: gpio
pin: GPIO12
id: relay1
- platform: gpio
pin: GPIO4
id: statuslight
light:
- platform: binary
name: ${friendly_name}
output: relay1
id: lightid
on_turn_on:
then:
- script.execute: start_timer
- script.execute: flash_status_light
on_turn_off:
then:
- output.turn_off: statuslight
binary_sensor:
- platform: gpio
pin:
number: GPIO13
mode: INPUT_PULLUP
inverted: True
name: "${switch_name}"
on_multi_click:
# single click
- timing:
- ON for at most 1s
- OFF for at least 0.5s
then:
- light.toggle: lightid
- script.execute: flash_status_light
- if:
condition:
light.is_on: lightid
then:
- script.execute: start_timer
# double click
- timing:
- ON for at most 1s
- OFF for at most 1s
- ON for at most 1s
- OFF for at least 0.2s
then:
- switch.toggle: timer_disable
# long click
- timing:
- ON for at least 1.5s
then:
- switch.turn_off: timer_disable
internal: true
id: switchid
- platform: status
name: "${friendly_name} Status"
- platform: homeassistant
name: "${motion_sensor_name}"
entity_id: ${motion_sensor_name}
id: motion_sensor
status_led:
pin: GPIO5
text_sensor:
- platform: version
name: ${friendly_name} ESPHome Version
sensor:
- platform: homeassistant
entity_id: ${ha_timer_number}
id: delay_length_sensor
internal: true
on_value:
then:
- lambda: |-
id(delay_length_global) = int(id(delay_length_sensor).state);
ESP_LOGD("main", "Delay length updated to %d seconds from Home Assistant", int(id(delay_length_sensor).state));
interval:
- interval: 2min
then:
- if:
condition:
wifi.connected:
then:
- homeassistant.service:
service: homeassistant.update_entity
data:
entity_id: ${ha_timer_number}
script:
- id: flash_status_light
then:
- output.turn_off: statuslight
- delay: 500ms
- output.turn_on: statuslight
- id: start_timer
mode: restart # Change mode to restart
then:
- if:
condition:
- switch.is_off: timer_disable
then:
- delay: !lambda "return (id(delay_length_global) - ${pre_off_warning}) * 1000;"
- logger.log:
format: "Script has hit pre_off_warning: ${pre_off_warning} seconds"
- repeat:
count: ${pre_off_warning}
then:
- output.turn_off: statuslight
- delay: 1s
- output.turn_on: statuslight
- delay: 1s
- if:
condition:
binary_sensor.is_on: motion_sensor
then:
- script.execute: start_timer
- light.turn_off: lightid
- output.turn_off: statuslight
switch:
- platform: template
name: "Timer Disable"
id: timer_disable
optimistic: true
on_turn_on:
then:
# this is kind of lame but i wanted a different
# flash and this was the easiest way for me
- script.execute: flash_status_light
- delay: 2.1s
- script.execute: flash_status_light
on_turn_off:
then:
- if:
condition:
light.is_on: lightid
then:
- script.execute: start_timer
time:
# when the clock strikes 12, re-enable the timer
- platform: homeassistant
id: homeassistant_time
on_time:
- seconds: 0
minutes: 0
hours: 0
then:
- switch.turn_off: timer_disable
@billchurch
Copy link
Author

Updated to add a motion sensor in Home Assistant referenced by the substitution motion_sensor_name.

This will check to see if a motion sensor is showing occupied or (on) right before timer turns off the switch, if it shows occupied it starts the script again for the defined time.

If you're not using a motion sensor or want this functionality, then you'll need to remove any references to that in the binary_sensor section:

  - platform: homeassistant
    name: "${motion_sensor_name}"
    entity_id: ${motion_sensor_name}
    id: motion_sensor

and the conditional in the script flash_status_light:

            - if:
                condition:
                  binary_sensor.is_on: motion_sensor
                then:
                  - script.execute: start_timer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment