DIY Home Assistant Alarm Clock

Code for an alarm clock with Home Assistant integration. Added bonus…Never have to worry about setting it in the event of a power outage or forgetting DST!

esphome:
name: alarm_clock
friendly_name: Alarm Clock

esp32: # or esp8266
board: nodemcu-32s # Change this to your specific board
framework:
type: arduino

# — Enable necessary components
wifi:
ssid: “YOUR_WIFI_SSID”
password: “YOUR_WIFI_PASSWORD”

# Enable Web Server for debugging if needed
# web_server:
# port: 80

# Enable Home Assistant API
api:

ota:

logger:

# — Time Synchronization with Home Assistant
time:
– platform: homeassistant
id: esptime

# — I2C for the display
i2c:
sda: 21 # Change to your SDA pin
scl: 22 # Change to your SCL pin
scan: true
id: bus_a

# — Global variables for alarm state
globals:
– id: is_alarming
type: bool
restore_value: no
initial_value: ‘false’
– id: is_snoozed
type: bool
restore_value: no
initial_value: ‘false’

# — Inputs for setting the alarm
input_number:
– id: alarm_hour
name: “Alarm Hour”
min_value: 0
max_value: 23
step: 1
initial_value: 7
mode: box
– id: alarm_minute
name: “Alarm Minute”
min_value: 0
max_value: 59
step: 1
initial_value: 30
mode: box

input_boolean:
– id: alarm_enabled
name: “Alarm Enabled”
initial_value: off

# — Outputs for LED and Speaker
output:
– platform: ledc # Use ledc for ESP32 for better performance
pin: GPIO27 # Pin for the speaker
id: speaker_pin

rtttl:
id: alarm_sound
output: speaker_pin

light:
– platform: binary
name: “Alarm LED”
id: alarm_led
pin: GPIO2 # Pin for the LED
effects:
– pulse:
name: “Alarm Pulse”
transition_length: 0.5s
update_interval: 1s
– strobe:
name: “Alarm Strobe”

# — Buttons for user interaction
binary_sensor:
– platform: gpio
pin:
number: GPIO12
mode: INPUT_PULLUP
inverted: true
name: “Set Hour Button”
on_press:
– input_number.increment: alarm_hour
– if:
condition:
– input_number.state:
id: alarm_hour
is: 24
then:
– input_number.set:
id: alarm_hour
value: 0
– platform: gpio
pin:
number: GPIO13
mode: INPUT_PULLUP
inverted: true
name: “Set Minute Button”
on_press:
– input_number.increment: alarm_minute
– if:
condition:
– input_number.state:
id: alarm_minute
is: 60
then:
– input_number.set:
id: alarm_minute
value: 0

– platform: gpio
pin:
number: GPIO14
mode: INPUT_PULLUP
inverted: true
name: “Toggle Alarm Button”
on_press:
– input_boolean.toggle: alarm_enabled

– platform: gpio
pin:
number: GPIO15
mode: INPUT_PULLUP
inverted: true
name: “Snooze Button”
on_press:
– if:
condition:
– lambda: ‘return id(is_alarming);’
then:
– script.execute: snooze_alarm

# — Display configuration
font:
– file: “gfonts://Roboto”
id: font1
size: 20
– file: “gfonts://Roboto”
id: font2
size: 14

display:
– platform: ssd1306_i2c
model: “SSD1306 128×64”
address: 0x3C
id: oled_display
lambda: |-
// Display current time
it.strftime(35, 15, id(font1), “%H:%M:%S”, id(esptime).now());

// Display alarm time
it.printf(5, 50, id(font2), “Alarm: %02d:%02d”, (int)id(alarm_hour).state, (int)id(alarm_minute).state);

// Display alarm status
if (id(alarm_enabled).state) {
if (id(is_snoozed)) {
it.print(100, 50, id(font2), “Snooze”);
} else {
it.print(100, 50, id(font2), “On”);
}
} else {
it.print(100, 50, id(font2), “Off”);
}

# — Scripts and Automations for Alarm Logic
script:
– id: start_alarming
mode: single
then:
– globals.set:
id: is_alarming
value: ‘true’
– light.turn_on:
id: alarm_led
effect: “Alarm Strobe”
– rtttl.play: “missionimp:d=16,o=6,b=95:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d,32d#,32e,32f,32f#,32g,32g,32g,32g,32f#,32f,32e,32d#,32d,32c#,32c,32b,32b,32c,32c#,32d,32d#,32e,32f,32f#,32g,32g,32a,32a#,32b,32c,32c#,32d,32d#,32d,32c#,32c,32b,32a#,32a,32g#,32g,32f#,32f,32e,32d#,32d”
– repeat:
count: 10 # Repeat sound for a duration
then:
– delay: 5s # Length of the RTTTL string
– rtttl.play: “missionimp:d=16,o=6,b=95:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d,32d#,32e,32f,32f#,32g,32g,32g,32g,32f#,32f,32e,32d#,32d,32c#,32c,32b,32b,32c,32c#,32d,32d#,32e,32f,32f#,32g,32g,32a,32a#,32b,32c,32c#,32d,32d#,32d,32c#,32c,32b,32a#,32a,32g#,32g,32f#,32f,32e,32d#,32d”

– id: stop_alarming
mode: single
then:
– script.stop: start_alarming
– globals.set:
id: is_alarming
value: ‘false’
– light.turn_off: alarm_led
– rtttl.stop:
– globals.set:
id: is_snoozed
value: ‘false’

– id: snooze_alarm
mode: single
then:
– script.execute: stop_alarming
– globals.set:
id: is_snoozed
value: ‘true’
– delay: 5min # Snooze duration
– globals.set:
id: is_snoozed
value: ‘false’
– script.execute: start_alarming # Re-start alarm after snooze

# — Main Alarm Trigger
time:
– platform: sntp # Redundant, but good for fallback
on_time:
– seconds: 0 # Check every minute on the minute
then:
– if:
condition:
and:
– lambda: ‘return id(alarm_enabled).state;’
– lambda: ‘return !id(is_snoozed);’
– lambda: ‘return id(esptime).now().hour == (int)id(alarm_hour).state;’
– lambda: ‘return id(esptime).now().minute == (int)id(alarm_minute).state;’
then:
– script.execute: start_alarming

# Stop alarm if it’s turned off while ringing
on_state:
– entity_id: input_boolean.alarm_enabled
to: “off”
then:
– if:
condition:
– lambda: ‘return id(is_alarming);’
then:
– script.execute: stop_alarming