My original Athan automation was a REST sensor, a handful of template sensors, and one automation to play a sound file. It worked, but it was fragile and did exactly one thing.
The Home Assistant Athan automation I run now is a lot more capable: it lives in its own package, handles Ramadan differently to the rest of the year, dims the lights and speaker for Fajr specifically, speaks a reminder before each prayer, and reverts the room to how it was once the Athan finishes. Here’s how it’s put together.
TL;DR: prayer times and Hijri date come from the Al Adhan API, a set of “N minutes before” template sensors drive a spoken reminder, the Athan playback automation snapshots and restores a scene around itself, a quiet_mode toggle gates every announcement in the house (not just this one), and Ramadan gets its own extra automation.
The sensors, now in a package Link to heading
Everything below lives in a single package file (packages/prayertimes.yaml) rather than scattered across the main configuration. Home Assistant packages let you group a feature’s sensors, templates, scripts and automations together instead of splitting them across configuration.yaml, automations.yaml and templates.yaml by type, which is how the 2018 version was organised.
rest:
# <- latitude/longitude below are placeholders - use your own, e.g. from Google Maps ->
- resource: "https://api.aladhan.com/v1/timings?latitude=<YOUR_LATITUDE>&longitude=<YOUR_LONGITUDE>&method=3"
scan_interval: 86400
sensor:
- name: "Fajr"
value_template: "{{ today_at(value_json.data.timings.Fajr) }}"
device_class: timestamp
- name: "Dhuhr"
value_template: "{{ today_at(value_json.data.timings.Dhuhr) }}"
device_class: timestamp
- name: "Asr"
value_template: "{{ today_at(value_json.data.timings.Asr) }}"
device_class: timestamp
- name: "Maghrib"
value_template: "{{ today_at(value_json.data.timings.Maghrib) }}"
device_class: timestamp
- name: "Isha"
value_template: "{{ today_at(value_json.data.timings.Isha) }}"
device_class: timestamp
- resource_template: "https://api.aladhan.com/v1/gToH/{{ now().strftime('%d-%m-%Y') }}"
scan_interval: 86400
sensor:
- name: "Hijri Month"
unique_id: hijri_month
value_template: "{{ value_json.data.hijri.month.number | int }}"
Two changes from the 2018 version worth calling out:
- I’ve switched from
platform: restsensors under a top-levelsensor:list to the modernrest:integration, which lets you define several sensors off one resource in a single block. - Rather than parsing the raw
HH:MMstring withtimestamp_customon a second template sensor, I pass it straight into Home Assistant’stoday_at()template function. It returns a proper timezone-aware timestamp for today at that local time, whichdevice_class: timestampneeds, and Home Assistant’s own timezone handling takes care of GMT/BST for free. No manual UTC conversion required.
Pick whichever calculation method matches your local mosque or community’s convention; Al Adhan supports several.
“N minutes before” template sensors Link to heading
These feed the spoken reminder automation further down. One per prayer, all following the same pattern:
template:
- sensor:
- name: "Fajr 10 Min Before"
unique_id: fajr_10_min_before
device_class: timestamp
state: "{{ (as_datetime(states('sensor.fajr')) - timedelta(minutes=10)).isoformat() }}"
- name: "Dhuhr 10 Min Before"
unique_id: dhuhr_10_min_before
device_class: timestamp
state: "{{ (as_datetime(states('sensor.dhuhr')) - timedelta(minutes=10)).isoformat() }}"
- name: "Asr 10 Min Before"
unique_id: asr_10_min_before
device_class: timestamp
state: "{{ (as_datetime(states('sensor.asr')) - timedelta(minutes=10)).isoformat() }}"
- name: "Maghrib 10 Min Before"
unique_id: maghrib_10_min_before
device_class: timestamp
state: "{{ (as_datetime(states('sensor.maghrib')) - timedelta(minutes=10)).isoformat() }}"
- name: "Isha 10 Min Before"
unique_id: isha_10_min_before
device_class: timestamp
state: "{{ (as_datetime(states('sensor.isha')) - timedelta(minutes=10)).isoformat() }}"
Ramadan detection Link to heading
The Hijri month sensor from earlier drives a simple binary sensor:
template:
- binary_sensor:
- name: "Ramadan"
unique_id: is_ramadan
state: "{{ states('sensor.hijri_month') | int == 9 }}"
Ramadan is the ninth month of the Hijri calendar, so this flips on and off automatically without me touching a calendar or a date range every year. It gates the Maghrib livestream automation near the end of this post.
The Athan automation Link to heading
This is the core of it, and the part that’s changed the most since 2018.
automation:
- alias: "Prayer - Athan"
initial_state: true
trigger:
- platform: time
at:
- sensor.fajr
- sensor.dhuhr
- sensor.asr
- sensor.maghrib
- sensor.isha
condition:
- condition: state
entity_id: input_boolean.quiet_mode
state: "off"
action:
- service: scene.create
data:
scene_id: before
snapshot_entities:
- media_player.living_room_speaker
- light.upstairs_corridor_air_freshener_light
- light.living_room_air_freshener_light
- choose:
- conditions:
- condition: time
after: "00:00:00"
before: "09:00:00"
sequence:
- service: media_player.volume_set
target:
entity_id: media_player.living_room_speaker
data:
volume_level: 0.25
default:
- service: media_player.volume_set
target:
entity_id: media_player.living_room_speaker
data:
volume_level: 0.50
- service: light.turn_on
target:
entity_id:
- light.upstairs_corridor_air_freshener_light
- light.living_room_air_freshener_light
data:
rgb_color: [0, 255, 0]
brightness_pct: 100
- choose:
- conditions:
- condition: time
after: "00:00:00"
before: "09:00:00"
sequence:
- service: media_player.play_media
target:
entity_id: media_player.living_room_speaker
data:
media_content_id: https://s3.intahnet.co.uk/athan/fajr.mp3
media_content_type: audio/mp3
default:
- service: media_player.play_media
target:
entity_id: media_player.living_room_speaker
data:
media_content_id: https://s3.intahnet.co.uk/athan/normal.mp3
media_content_type: audio/mp3
- delay: 5
- wait_template: "{{ is_state('media_player.living_room_speaker', 'idle') }}"
- delay: 5
- service: scene.turn_on
data:
entity_id: scene.before
A few things worth explaining:
- Scene snapshot and restore. Before doing anything, it captures the speaker and air freshener lights into a
scene.before, then restores that scene once the Athan finishes playing. Whatever state the room was in beforehand, it goes back to it, rather than leaving the volume or lights wherever the automation last set them. - Different volume and audio for Fajr. Between midnight and 9am, the speaker plays quieter and the Fajr-specific audio file is used instead of the normal one. Traditionally the Fajr Athan includes an extra phrase not present in the others, so it genuinely needs a different recording, not just a lower volume.
- The air freshener is real now. In the 2018 post I mentioned, half as a joke, that I might switch on an Ambi Pur air freshener plugged into a smart socket during the Athan. It’s now a proper part of the automation, turned on green at full brightness alongside the speaker.
- Self-hosted audio. Both
.mp3files are served from my own S3-compatible storage rather than a public link, so they’re never at the mercy of a third-party host disappearing. - The
wait_template. Rather than guessing how long the recording takes, the automation waits for the speaker to reportidlebefore restoring the scene, so it works regardless of which prayer (and therefore which recording length) triggered it.
Quiet mode Link to heading
The condition on the automation above checks input_boolean.quiet_mode, a toggle that mutes every non-critical announcement in the house, not just the Athan. I built two reusable scripts around it so any future automation can respect the same toggle without duplicating the check:
script:
conditional_announcement:
alias: "Conditional Announcement"
mode: queued
max: 10
fields:
entity_id:
required: true
media_content_id:
required: true
media_content_type:
default: "audio/mp3"
volume_level:
default: 0.5
sequence:
- choose:
- conditions:
- condition: state
entity_id: input_boolean.quiet_mode
state: "off"
sequence:
- service: media_player.volume_set
target:
entity_id: "{{ entity_id }}"
data:
volume_level: "{{ volume_level }}"
- service: media_player.play_media
target:
entity_id: "{{ entity_id }}"
data:
media_content_id: "{{ media_content_id }}"
media_content_type: "{{ media_content_type }}"
conditional_tts:
alias: "Conditional TTS Announcement"
mode: queued
max: 10
fields:
entity_id:
required: true
message:
required: true
sequence:
- choose:
- conditions:
- condition: state
entity_id: input_boolean.quiet_mode
state: "off"
sequence:
- service: tts.speak
target:
entity_id: tts.home_assistant_cloud
data:
media_player_entity_id: "{{ entity_id }}"
message: "{{ message }}"
Deliberately, quiet mode never touches the alarm system. It’s for voice reminders and ambient sounds, not security.
A spoken reminder before each prayer Link to heading
Ten minutes before each prayer, an automation triggers off the “N minutes before” sensors from earlier and speaks a short reminder through the living room speaker:
automation:
- alias: "Prayer - Notify Before Prayer"
initial_state: true
trigger:
- platform: time
at: sensor.fajr_10_min_before
- platform: time
at: sensor.dhuhr_10_min_before
- platform: time
at: sensor.asr_10_min_before
- platform: time
at: sensor.maghrib_10_min_before
- platform: time
at: sensor.isha_10_min_before
action:
- variables:
prayer_name: >
{% set map = {
'sensor.fajr_10_min_before': 'Fajr',
'sensor.dhuhr_10_min_before': 'Dhuhr',
'sensor.asr_10_min_before': 'Asr',
'sensor.maghrib_10_min_before': 'Maghrib',
'sensor.isha_10_min_before': 'Isha'
} %}
{{ map[trigger.entity_id] }}
- service: conversation.process
data:
agent_id: conversation.notification_agent
text: >-
Prayer time reminder. Prayer name: {{ prayer_name }}.
Notify that there are 10 minutes until {{ prayer_name }} prayer. Keep it concise and friendly.
response_variable: agent
- service: script.conditional_tts
data:
entity_id: media_player.living_room_speaker
message: "{{ agent.response.speech.plain.speech }}"
The conversation.process call is optional and needs its own conversation agent configured (conversation.notification_agent here is whatever LLM-backed conversation agent you’ve set up in Home Assistant). If you’d rather skip that entirely, replace the conversation.process and response_variable steps with a plain string, for example message: "{{ prayer_name }} prayer is in 10 minutes.", and call script.conditional_tts directly. Either way, it still respects quiet mode through the script.
Ramadan: casting the Maghrib stream Link to heading
One automation only runs during Ramadan, using the binary sensor from earlier:
automation:
- alias: "Prayer - Cast Stream Before Maghrib"
initial_state: true
trigger:
- platform: time
at: sensor.maghrib_10_min_before
condition:
- condition: state
entity_id: binary_sensor.ramadan
state: "on"
action:
- service: media_player.play_media
target:
entity_id: media_player.living_room_chromecast
data:
# <- placeholder - use your own mosque or community's livestream URL ->
media_content_id: "<YOUR_MOSQUE_OR_COMMUNITY_LIVESTREAM_URL>"
media_content_type: "video"
Ten minutes before Maghrib during Ramadan, it casts a livestream to the living room Chromecast, so it’s already up before the Athan plays and the fast breaks. I usually point it at Islam Channel or Eman Channel; they’ll often have Dua and dhikr with speakers like Mufti Menk in the run-up to Maghrib, which sets a different atmosphere for the month, even if I could do without the food adverts squeezed in right before iftar. Outside Ramadan, the binary_sensor.ramadan condition keeps this automation from firing at all.
Refreshing the sensors daily Link to heading
One more small piece: the prayer time and Hijri sensors are pulled once a day by their scan_interval, but I also force a refresh at midnight so nothing’s left showing yesterday’s times if a fetch was ever missed:
automation:
- alias: "Prayer - Refresh Prayer Times"
initial_state: true
trigger:
- platform: time
at: "00:00:00"
action:
- service: homeassistant.update_entity
target:
entity_id:
- sensor.fajr
- sensor.dhuhr
- sensor.asr
- sensor.maghrib
- sensor.isha
- sensor.hijri_month
Where this leaves it Link to heading
None of this was built in one sitting. Each piece got added when the previous version annoyed me in some specific way: the scene restore because I kept finding the volume left low after Fajr, quiet mode because a work call interrupted by a full-volume Athan is not a good look, the Fajr-specific audio and dimmer volume because 5am at full volume through the living room speaker wakes up more of the house than intended.
If you’re starting from my 2018 post, the sensors and the core play_media call are still the same idea. Everything else here is what accumulated around it once the basic version was working reliably enough to stop thinking about.