I’d like to post my solution. I used code from several posts in this thread as well as others (Thank you!). I’ve tested this as much as I possibly could to ensure it works the way that I need it to.
My use cases:
- It takes me about 30 min to wake up (Very hard for me)
- I need a snooze function
- The alarm has to work based on “if” I have work or “if” it is a one off like on the weekend or some random time I need an alarm.
- I didn’t want multiple UI cards because I have enough on my front end already. This needed to be 1 single card with all the info in one spot.
The snooze function is where I started with everything. I had to have this function or the entire process would not work for me. I also wanted this to be hands off. Meaning literally no pressing a button, turning a phone over, or anything using my hands. So this means voice. I have a Google Home in my bedroom and this was going to be my interface. After some thinking it made sense that “if” you tell GH to “stop”, “shut up”, etc, the playback of any music, voice, etc would just stop playing. This seemed like a good approach for a snooze.
I had to then find a way to make sure that after x period of time, HA would start the stream back up so that it would work just like a snooze and restart the alarm. The way this would work is with booleans and a loop. The trick is to ensure you have the right amount of booleans in conditions to not have HA go into a continuous loop and never stop. I noticed most have used “time” as a condition with a value of /5 or whatever. While I did test this and it did work, sometimes it would not only work but run through a series of volume changes (if you’re doing the slow volume increase approach) in the automation/script without waiting for delays. I found that this happened due to a previous run at the automation getting stuck in memory. So this wasn’t going to work. The alarm clock would jump in volume right away and blast very high immediately and then cycle through all the different volumes it had stored in memory until it caught up. So that obviously wasn’t going to work. Honestly if no one else using the time condition has seen this or experienced it then IDK. I also only wanted the entire process to start “when” a boolean was turned on. Not have an automation waiting every x minutes for conditions to be met. So the way I did that was tie the main alarm clock boolean to the trigger of any of my alarm times. Alarm time trigger > if conditions met > turn on alarm clock boolean.
This lead me to create a loop script. One that would trigger and then after a script was finished would continue to loop until I turned a boolean off. This was my triggering point. The way it works is I have one main boolean that “if” on, sets the entire process in motion. This is “alarm clock”. But I also needed booleans to define if it is a work day or not. Because I will have to set alarms for different occasions on off days or holidays.
Then I needed to have booleans to “start” an alarm process for an off or work day. This is where it got tricky because again I didn’t want to have different UI cards running different scripts. In the end I came up with 2 automations based on some booleans that would define the type of day (Work or not), trigger the alarm clock automation, and then loop it “if” the main alarm clock boolean was still on.
Now if the alarm clock triggers and starts playing and I want to snooze… All I have to do is say “Hey Google, stop”. Then no matter where the script is in its process will finish in its entirety without playing any music/sound. The script already executed the stream playback so all that is left is the volume changes. And I did this over a 10 min period. Which is normally my snooze timer. Then as long as that main boolean is on, it will start the loop over again at the end of the script. I can snooze for infinity and the alarm will keep looping until I want to end it.
Now the part of ending the alarm… It’s as simple as having the main alarm clock boolean in HA sync’d to Google Assistant. If I say “Hey Google, turn off alarm clock”. Thats it. All the automations and loop script stops. (You must have GA integrated with HA for this) Thats fine and all I know there will be times when I forget to say that and the loop script will keep running. How I got around this is tie my phone to turning off the alarm. I already have an automation that runs that will trigger when I unplug my phone and provide me with my day agenda and weather. (I’m able to do this because I use an app on my phone that can send MQTT data for phone sensors, including charge type). I use whether or not my phone is on AC charge or not after a certain time period. So all I had to do was tie the alarm clock boolean to the same automation to turn the alarm clock process off. Boom.
Here is my code. Hopefully someone can use this or even improve it.
## Group
Alarm Clock:
- input_boolean.alarm_clock_work_day
- input_boolean.alarm_clock_off_day
- sensor.time
- sensor.alarm_time
- input_number.alarm_hour
- input_number.alarm_minutes
- input_boolean.alarm_clock
- input_boolean.start_alarm_clock_work_day
- input_boolean.start_alarm_clock_off_day
- input_boolean.alarm_clock_loop
- input_select.radio_station
- automation.wake_up_radio
- automation.start_alarm_clock_radio_work_day
- automation.start_alarm_clock_radio_off_day
- automation.wake_up_radio_from_loop
- script.alarm_clock_loop
## Sensors
- platform: template
sensors:
alarm_time_off_day:
friendly_name: Alarm Time Off Day
value_template: '{{ "%0.02d:%0.02d" | format(states("input_number.alarm_hour") | int, states("input_number.alarm_minutes") | int) }}'
- platform: template
sensors:
alarm_time_work_day:
friendly_name: Alarm Time Work Day
value_template: '{{ "%0.02d:%0.02d" | format(states("input_number.alarm_hour") | int, states("input_number.alarm_minutes") | int) }}'
## Input Boolean
alarm_clock:
name: Alarm On/Off
icon: mdi:alarm
alarm_clock_loop:
name: Alarm Clock Loop
icon: mdi:alarm
alarm_clock_work_day:
name: Work Alarm On/Off
icon: mdi:alarm
alarm_clock_off_day:
name: Off Day Alarm On/Off
icon: mdi:alarm
start_alarm_clock_work_day:
name: Start Alarm Clock Work Day
initial: off
icon: mdi:alarm
start_alarm_clock_off_day:
name: Start Alarm Clock Off Day
initial: off
icon: mdi:alarm
work_day:
name: Work Day
icon: mdi:briefcase
## Input Number
alarm_hour:
name: Hour
icon: mdi:timer
initial: 6
min: 0
max: 20
step: 1
alarm_minutes:
name: Minutes
icon: mdi:timer
initial: 25
min: 0
max: 55
step: 1
## Input Select
radio_station:
name: 'Select Radio Station:'
options:
- WKFU 1111
- WK Some Station
initial: WKFU 1111
icon: mdi:radio
## Google Assistant
project_id: !secret ga_project_id
client_id: !secret gassistant_client_id
access_token: !secret gassistant_access_token
api_key: !secret gassistant_homegraph_api_key
expose_by_default: false
exposed_domains:
- input_boolean
entity_config:
input_boolean.alarm_clock:
name: Alarm Clock
expose: yes
## Automations
#
- id: start_alarm_clock_radio_off_day
alias: Start Alarm Clock Radio Off Day
initial_state: 'on'
trigger:
platform: template
value_template: '{{ states.sensor.time.state == states.sensor.alarm_time_off_day.state }}'
condition:
- condition: state
entity_id: input_boolean.alarm_clock
state: 'off'
- condition: state
entity_id: input_boolean.start_alarm_clock_off_day
state: 'off'
- condition: state
entity_id: input_boolean.alarm_clock_work_day
state: 'off'
- condition: state
entity_id: input_boolean.alarm_clock_off_day
state: 'on'
action:
- service: input_boolean.turn_on
data:
entity_id: input_boolean.alarm_clock
- service: input_boolean.turn_on
data:
entity_id: input_boolean.start_alarm_clock_off_day
#
- id: start_alarm_clock_radio_work_day
alias: Start Alarm Clock Radio Work Day
initial_state: 'on'
trigger:
platform: template
value_template: '{{ states.sensor.time.state == states.sensor.alarm_time_work_day.state }}'
condition:
- condition: time
weekday:
- mon
- tue
- wed
- thu
- fri
- condition: state
entity_id: input_boolean.alarm_clock
state: 'off'
- condition: state
entity_id: input_boolean.work_day
state: 'on'
- condition: state
entity_id: input_boolean.start_alarm_clock_work_day
state: 'off'
- condition: state
entity_id: input_boolean.alarm_clock_work_day
state: 'on'
- condition: state
entity_id: input_boolean.alarm_clock_off_day
state: 'off'
action:
- service: input_boolean.turn_on
data:
entity_id: input_boolean.start_alarm_clock_work_day
- service: input_boolean.turn_on
data:
entity_id: input_boolean.alarm_clock
#
- id: wake_up_radio
alias: Wake Up Radio
initial_state: 'on'
trigger:
- platform: state
entity_id: input_boolean.start_alarm_clock_work_day
to: 'on'
- platform: state
entity_id: input_boolean.start_alarm_clock_off_day
to: 'on'
condition:
- condition: state
entity_id: input_boolean.alarm_clock
state: 'on'
- condition: or
conditions:
- condition: state
entity_id: input_boolean.alarm_clock_work_day
state: 'on'
- condition: state
entity_id: input_boolean.alarm_clock_off_day
state: 'on'
action:
- service: input_boolean.turn_off
data:
entity_id: input_boolean.start_alarm_clock_work_day
- service: input_boolean.turn_off
data:
entity_id: input_boolean.start_alarm_clock_off_day
- service: script.turn_on
data:
entity_id: script.alarm_clock_loop
#
- id: wake_up_radio_from_loop
alias: Wake Up Radio From Loop
initial_state: 'on'
trigger:
- platform: state
entity_id: input_boolean.alarm_clock_loop
to: 'on'
condition:
- condition: state
entity_id: input_boolean.alarm_clock
state: 'on'
action:
- delay: '00:00:03'
- service: input_boolean.turn_off
data:
entity_id: input_boolean.alarm_clock_loop
- service: script.turn_on
data:
entity_id: script.alarm_clock_loop
### Script
alarm_clock_loop:
alias: Alarm Clock Loop
sequence:
- service: media_player.turn_on
data:
entity_id: media_player.master_bedroom_home
- service: media_player.volume_set
data:
entity_id: media_player.master_bedroom_home
volume_level: '0.01'
- delay: '00:00:02'
- service: media_player.play_media
data_template:
entity_id: media_player.master_bedroom_home
media_content_id: >
{% if is_state("input_select.radio_station", "WKFU 1111") %} http://something_something_something
{% elif is_state("input_select.radio_station", "Some Station") %} http://something_here
{% endif %}
media_content_type: 'audio/mp4'
- delay: '00:01:00'
- service: media_player.volume_set
data:
entity_id: media_player.master_bedroom_home
volume_level: '0.05'
- delay: '00:01:00'
- service: media_player.volume_set
data:
entity_id: media_player.master_bedroom_home
volume_level: '0.10'
- delay: '00:01:00'
- service: media_player.volume_set
data:
entity_id: media_player.master_bedroom_home
volume_level: '0.15'
- delay: '00:01:00'
- service: media_player.volume_set
data:
entity_id: media_player.master_bedroom_home
volume_level: '0.20'
- delay: '00:01:00'
- service: media_player.volume_set
data:
entity_id: media_player.master_bedroom_home
volume_level: '0.25'
- delay: '00:01:00'
- service: media_player.volume_set
data:
entity_id: media_player.master_bedroom_home
volume_level: '0.30'
- delay: '00:01:00'
- service: media_player.volume_set
data:
entity_id: media_player.master_bedroom_home
volume_level: '0.35'
- delay: '00:01:00'
- service: media_player.volume_set
data:
entity_id: media_player.master_bedroom_home
volume_level: '0.40'
- delay: '00:01:00'
- service: media_player.volume_set
data:
entity_id: media_player.master_bedroom_home
volume_level: '0.45'
- delay: '00:01:00'
- service: media_player.volume_set
data:
entity_id: media_player.master_bedroom_home
volume_level: '0.50'
- service: input_boolean.turn_on
data:
entity_id: input_boolean.alarm_clock_loop