Hi All,
I would like to share a RESTful Sensor project to import data from the MUIS (Majlis Ugama Islam Singapura) API for accurate Prayer Times for Singapore. The code below provides individual sensors for Subuh, Syuruk, Zohor, Asar, Maghrib & Isyak Prayer Times. These sensors can be used for Azan automations in Node Red (Time Node) as a trigger.
The sensors will update hourly and if the Prayer Time for Today has passed, it will show the following day’s Prayer Time instead.
e.g. If time now is 1650h and Asar Prayer Time for today was at 1620h, tomorrow’s Asar Prayer Time will be shown instead.
INSTALLATION:
Add the codes below to your configurations.yaml file.
A full restart is required if this is the first time you have added the “sensor” or “template” component to your Home Assistant setup.
UPDATE: Updated the code to be usable with both Node-RED and Home Assistant’s native GUI Automation with the Template Sensor below.
Code to retrieve MUIS prayer times:
Prayer times will be in ISO 8601 format (Only Node-RED Automations).
E.g. 2025-04-26T16:21:00
Sensor:
- platform: rest
name: "Subuh ISO"
resource: "https://data.gov.sg/api/action/datastore_search?resource_id=d_e81ea2337599b674c4f645c1af93e0dc&limit=365&fields=Date,Subuh"
value_template: >
{% set today = now().strftime('%Y-%m-%d') %}
{% set tomorrow = (now() + timedelta(days=1)).strftime('%Y-%m-%d') %}
{% set records = value_json.result.records %}
{% set today_row = records | selectattr("Date", "equalto", today) | list %}
{% set tomorrow_row = records | selectattr("Date", "equalto", tomorrow) | list %}
{% if today_row and tomorrow_row %}
{% set t_hour, t_minute = today_row[0].Subuh.split(':') %}
{% set now_total = now().hour * 60 + now().minute %}
{% set prayer_total = (t_hour | int) * 60 + (t_minute | int) %}
{% if now_total < prayer_total %}
{{ today }}T{{ '%02d' % (t_hour | int) }}:{{ '%02d' % (t_minute | int) }}:00
{% else %}
{% set th, tm = tomorrow_row[0].Subuh.split(':') %}
{{ tomorrow }}T{{ '%02d' % (th | int) }}:{{ '%02d' % (tm | int) }}:00
{% endif %}
{% else %}
unknown
{% endif %}
scan_interval: 3600
headers:
Accept: application/json
- platform: rest
name: "Zohor ISO"
resource: "https://data.gov.sg/api/action/datastore_search?resource_id=d_e81ea2337599b674c4f645c1af93e0dc&limit=365&fields=Date,Zohor"
value_template: >
{% set today = now().strftime('%Y-%m-%d') %}
{% set tomorrow = (now() + timedelta(days=1)).strftime('%Y-%m-%d') %}
{% set records = value_json.result.records %}
{% set today_row = records | selectattr("Date", "equalto", today) | list %}
{% set tomorrow_row = records | selectattr("Date", "equalto", tomorrow) | list %}
{% if today_row and tomorrow_row %}
{% set t_hour, t_minute = today_row[0].Zohor.split(':') %}
{% set t_hour = t_hour | int + 12 %}
{% set now_total = now().hour * 60 + now().minute %}
{% set prayer_total = t_hour * 60 + (t_minute | int) %}
{% if now_total < prayer_total %}
{{ today }}T{{ '%02d' % t_hour }}:{{ '%02d' % (t_minute | int) }}:00
{% else %}
{% set th, tm = tomorrow_row[0].Zohor.split(':') %}
{% set th = th | int + 12 %}
{{ tomorrow }}T{{ '%02d' % th }}:{{ '%02d' % (tm | int) }}:00
{% endif %}
{% else %}
unknown
{% endif %}
scan_interval: 3600
headers:
Accept: application/json
- platform: rest
name: "Asar ISO"
resource: "https://data.gov.sg/api/action/datastore_search?resource_id=d_e81ea2337599b674c4f645c1af93e0dc&limit=365&fields=Date,Asar"
value_template: >
{% set today = now().strftime('%Y-%m-%d') %}
{% set tomorrow = (now() + timedelta(days=1)).strftime('%Y-%m-%d') %}
{% set records = value_json.result.records %}
{% set today_row = records | selectattr("Date", "equalto", today) | list %}
{% set tomorrow_row = records | selectattr("Date", "equalto", tomorrow) | list %}
{% if today_row and tomorrow_row %}
{% set t_hour, t_minute = today_row[0].Asar.split(':') %}
{% set t_hour = t_hour | int + 12 %}
{% set now_total = now().hour * 60 + now().minute %}
{% set prayer_total = t_hour * 60 + (t_minute | int) %}
{% if now_total < prayer_total %}
{{ today }}T{{ '%02d' % t_hour }}:{{ '%02d' % (t_minute | int) }}:00
{% else %}
{% set th, tm = tomorrow_row[0].Asar.split(':') %}
{% set th = th | int + 12 %}
{{ tomorrow }}T{{ '%02d' % th }}:{{ '%02d' % (tm | int) }}:00
{% endif %}
{% else %}
unknown
{% endif %}
scan_interval: 3600
headers:
Accept: application/json
- platform: rest
name: "Maghrib ISO"
resource: "https://data.gov.sg/api/action/datastore_search?resource_id=d_e81ea2337599b674c4f645c1af93e0dc&limit=365&fields=Date,Maghrib"
value_template: >
{% set today = now().strftime('%Y-%m-%d') %}
{% set tomorrow = (now() + timedelta(days=1)).strftime('%Y-%m-%d') %}
{% set records = value_json.result.records %}
{% set today_row = records | selectattr("Date", "equalto", today) | list %}
{% set tomorrow_row = records | selectattr("Date", "equalto", tomorrow) | list %}
{% if today_row and tomorrow_row %}
{% set t_hour, t_minute = today_row[0].Maghrib.split(':') %}
{% set t_hour = t_hour | int + 12 %}
{% set now_total = now().hour * 60 + now().minute %}
{% set prayer_total = t_hour * 60 + (t_minute | int) %}
{% if now_total < prayer_total %}
{{ today }}T{{ '%02d' % t_hour }}:{{ '%02d' % (t_minute | int) }}:00
{% else %}
{% set th, tm = tomorrow_row[0].Maghrib.split(':') %}
{% set th = th | int + 12 %}
{{ tomorrow }}T{{ '%02d' % th }}:{{ '%02d' % (tm | int) }}:00
{% endif %}
{% else %}
unknown
{% endif %}
scan_interval: 3600
headers:
Accept: application/json
- platform: rest
name: "Isyak ISO"
resource: "https://data.gov.sg/api/action/datastore_search?resource_id=d_e81ea2337599b674c4f645c1af93e0dc&limit=365&fields=Date,Isyak"
value_template: >
{% set today = now().strftime('%Y-%m-%d') %}
{% set tomorrow = (now() + timedelta(days=1)).strftime('%Y-%m-%d') %}
{% set records = value_json.result.records %}
{% set today_row = records | selectattr("Date", "equalto", today) | list %}
{% set tomorrow_row = records | selectattr("Date", "equalto", tomorrow) | list %}
{% if today_row and tomorrow_row %}
{% set t_hour, t_minute = today_row[0].Isyak.split(':') %}
{% set t_hour = t_hour | int + 12 %}
{% set now_total = now().hour * 60 + now().minute %}
{% set prayer_total = t_hour * 60 + (t_minute | int) %}
{% if now_total < prayer_total %}
{{ today }}T{{ '%02d' % t_hour }}:{{ '%02d' % (t_minute | int) }}:00
{% else %}
{% set th, tm = tomorrow_row[0].Isyak.split(':') %}
{% set th = th | int + 12 %}
{{ tomorrow }}T{{ '%02d' % th }}:{{ '%02d' % (tm | int) }}:00
{% endif %}
{% else %}
unknown
{% endif %}
scan_interval: 3600
headers:
Accept: application/json
Template Sensors Code:
Device class set to timestamp to enable for use with HA GUI Automations and with Node-RED. It also displays state in a more visually pleasing format. E.g. 26 April 2025 at 16:21
template:
- sensor:
- name: "MUIS - Subuh"
device_class: timestamp
state: >
{% set iso = states('sensor.subuh_iso') %}
{% if iso not in ['unknown', 'unavailable', None] %}
{{ as_datetime(iso ~ '+08:00').isoformat() }}
{% else %}
unknown
{% endif %}
- sensor:
- name: "MUIS - Zohor"
device_class: timestamp
state: >
{% set iso = states('sensor.zohor_iso') %}
{% if iso not in ['unknown', 'unavailable', None] %}
{{ as_datetime(iso ~ '+08:00').isoformat() }}
{% else %}
unknown
{% endif %}
- sensor:
- name: "MUIS - Asar"
device_class: timestamp
state: >
{% set iso = states('sensor.asar_iso') %}
{% if iso not in ['unknown', 'unavailable', None] %}
{{ as_datetime(iso ~ '+08:00').isoformat() }}
{% else %}
unknown
{% endif %}
- sensor:
- name: "MUIS - Maghrib"
device_class: timestamp
state: >
{% set iso = states('sensor.maghrib_iso') %}
{% if iso not in ['unknown', 'unavailable', None] %}
{{ as_datetime(iso ~ '+08:00').isoformat() }}
{% else %}
unknown
{% endif %}
- sensor:
- name: "MUIS - Isyak"
device_class: timestamp
state: >
{% set iso = states('sensor.isyak_iso') %}
{% if iso not in ['unknown', 'unavailable', None] %}
{{ as_datetime(iso ~ '+08:00').isoformat() }}
{% else %}
unknown
{% endif %}
Please note that this will only be valid for Singapore Prayer Times (by MUIS) in 2025 and that the resource URL will need to be updated to for the sensors to be functional after 2025. Barring changes in the API structure, this should continue to be usable with a simple update to the relevant year’s Prayer Timetable API URL.