Islamic Prayers - Time calculations and rules with audio and video


(Ahmad Yazan Tibi) #21

What is the difference between Time cron “0 2 0 ? * * *” and “0 2 0 * * ?”


(Vincent Regaud) #22

None

You can check with:

https://www.freeformatter.com/cron-expression-generator-quartz.html


(Matthias) #23

Well, I was again tinkering with the rule and found, that all of the performance issues came from the auto(un)boxing of objects vs. primitive types. I got rid of almost all of the .doubleValue stuff and am back to a 10sec precompile time.


(Rich Koshak) #24

That is very interesting. So the problem was the use of primitives. I usually recommend against using primitives where possible but never imagined that it would have that big of a performance impact. Really good to know. Thanks for coming back to post this.


(Amin Afip) #25

Hi,
I have downloaded the script and testing it out. Been away for a while due to ramadhan and syawal. Great to know Vincent have shared the code to all. May I know the codes in https://github.com/vzorglub/Openhab2-Prayer-Times has been updated with the enhancement as per comments above? It looks like the code was last updated 2 months ago. I will try it out anyway

For my case in Malaysia have to use a custom method 18 degrees for Isyak, dan 20 degrees for subuh. I have check the actual timing on Prayertimes.org and there are a 1 or two minutes difference but good enough for me as I am using this for switching of fans and ptz cameras for recording of daily speech. Will let you know how t works out.


(Vincent Regaud) #26

The original code at the top of the thread still works. I have changed mine according to @rlkoshak at it works fine except when the system starts at 6pm say and 4 timers go off and it tries to play 4 prayers at the same time…

I have not tried the calculation OH code yet.

The original code worked fine for 6 months or so before I published.

You can tweak the times in the sccript config


(Rich Koshak) #27

That is odd and unexpected and clearly wrong. There is a fundamental bug here but I’m too far away from the code now to easily find why that would be the case. Let me know if you want some help finding where I went wrong.


(Vincent Regaud) #28

Yes please,
It happens every time system started occurs
So everytime I change item files of rules of it goes…


(Rich Koshak) #29

When System started does it immediately plays all four prayers, or is there a delay and then it plays all four? Does it play the four in sequence or in parallel? Does it work correctly all other times?

I know I had some typos in the code I posted above. Can you post the latest version you are working with just to ensure that we are looking at the same thing?


(Vincent Regaud) #30

It plays all in parallel depending on the time of day, if 2 of 3 prayers in the day have triggered already it will play 2 or three.
It works perfectly, it’s just on system started.
It does it after a small delay. I think it’s the first rule that gets the values from the python script and then populates the timers. The timers then trigger because the time has already elapsed…

The code:

import java.util.Map
import java.util.HashMap
import org.eclipse.xtext.xbase.lib.Functions

val Map<String, Timer> timers = new HashMap<String, Timer> //createHashMap

// Converts HH:MM to a DateTimeType for today
val Functions$Function1<String, DateTimeType> toDateTimeType = [ hhmm |
    val hours = Integer::parseInt(hhmm.split(":").get(0))
    val mins = Integer::parseInt(hhmm.split(":").get(1))

    // Jumps to tomorrow midnight and substract to avoid problems at daylight saving changes
    val timerTime = now.withTimeAtStartOfDay.plusDays(1).minusHours(24-hours).plusMinutes(mins)

    new DateTimeType(timerTime.toString)
]

// Create a Timer that sendCommand to trigger with cmd at the passed in time
val Procedures$Procedure5<Map<String, Timer>, String, DateTimeType, String, String> createPrayerTimer = [ timers, key, time, trigger, cmd |
    val timerTime = new DateTime(time.getZonedDateTime.toInstant.toEpochMilli)
    timers.get(key)?.cancel
    timers.put(key, createTimer(timerTime, [ |
        sendCommand(trigger, cmd)
        timers.put(key, null)
    ]))
]

val Procedures$Procedure2<Map<String, Timer>, String> prayerTrigger = [ timers, prayer |
     if (House_HomeAway.state.toString == "home") {
        var prayerDuration = if(prayer == "Fajr") 178 else 98
        var String soundFile = if(prayer == "Fajr") "adhanfajr.mp3" else "adhan.mp3"
        var String topic = if(prayer == "Fajr") "Misc/PrayerTriggerFajr" else "Misc/PrayerTrigger"
        if (LivingRoom_TVON.state == ON) {
            if ((LivingRoom_TVSource.state.toString == "HDMI1") || (LivingRoom_TVSource.state.toString == "HDMI-CEC")) {
                if (timers.get("prayerDuration") === null) {
                    // save the current states of hte TV and Lights Items
                    val tvStates = storeStates(LivingRoom_TVSource, LivingRoom_TVVolume)
                    publish("mybroker", topic, "ON")
                    Thread::sleep(2600)
                    SkyBox.sendCommand("pause")
                    LivingRoom_TVRemoteKey.sendCommand("KEY_PAUSE")
                    LivingRoom_TVSource.sendCommand("AV")
                    LivingRoom_TVVolume.sendCommand(65)
                    //LivingRoom_TVLightLeft_Colour.sendCommand(new HSBType(new DecimalType(25), new PercentType(100), new PercentType(80)))
                    //LivingRoom_TVLightLeft_Level.sendCommand(100)
                    timers.put("prayerDuration", createTimer(now.plusSeconds(prayerDuration), [ |
                        restoreStates(tvStates)
                        SkyBox.sendCommand("play")
                        LivingRoom_TVRemoteKey.sendCommand("KEY_PLAY")
                        timers.put("prayerDuration", null)                    
                    ]))

                }
            }
        } else {
            playSound(soundFile)
        }
    }   
]

// Update the prayer start times based on the result of the Python script
rule "prayer times"
when
    Time cron "0 2 0 * * ?" or
    System  started
then
    var String PT = executeCommandLine("python /etc/openhab2/scripts/prayertimes.py", 5000)
    PrayerTime_Fajr.postUpdate(toDateTimeType.apply(transform("JSONPATH", "$.fajr", PT)))
    PrayerTime_Zuhr.postUpdate(toDateTimeType.apply(transform("JSONPATH", "$.dhuhr", PT)))
    PrayerTime_Asr.postUpdate(toDateTimeType.apply(transform("JSONPATH", "$.asr", PT)))
    PrayerTime_Maghrib.postUpdate(toDateTimeType.apply(transform("JSONPATH", "$.maghrib", PT)))
    PrayerTime_Isha.postUpdate(toDateTimeType.apply(transform("JSONPATH", "$.isha", PT)))
end

// Reset the timers when a prayer time is updated
rule "Prayer time updated"
when
    Member of PrayerTimes received update
then
    val prayer = triggeringItem.name.split("_").get(1)
    createPrayerTimer.apply(timers, prayer, triggeringItem.state, "PrayerTime_PrayerTrigger", prayer)
    val prayerTime = new DateTime((triggeringItem.state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli)
    val beforePrayerMins = BeforePrayerMinutes.members.findFirst[ min | min.name == "PrayerTime_MinutesBefore" + prayer]
    val afterPrayerMins = AfterPrayerMinutes.members.findFirst[ min | min.name == "PrayerTime_MinutesAfter" + prayer]
    if (beforePrayerMins !== null) {
        val time = new DateTimeType(prayerTime.minusMinutes((beforePrayerMins.state as Number).intValue).toString)
        createPrayerTimer.apply(timers, "before" + prayer, time, "PrayerTime_BeforePrayerTrigger", prayer)
    }
    if (afterPrayerMins !== null) {
        val time = new DateTimeType(prayerTime.plusMinutes((afterPrayerMins.state as Number).intValue).toString)
        createPrayerTimer.apply(timers, "after" + prayer, time, "PrayerTime_AfterPrayerTrigger", prayer)
    }
end

// Fajr is handled differently
rule "Fajr"
when
    Item PrayerTime_PrayerTrigger received command "Fajr"
then
    if (PrayerTime_PlayEarlyAdhan.state == ON) {
        if (now.getHourOfDay() >= (PrayerTime_EarlyAdhanTime.state as Number)) {
            prayerTrigger.apply(timers, receivedCommand.toString)
        }
    }
end

rule "Prayer Trigger other times"
when
    Item PrayerTime_PrayerTrigger received command "Zuhr" or
    Item PrayerTime_PrayerTrigger received command "Asr" or
    Item PrayerTime_PrayerTrigger received command "Maghrib" or
    Item PrayerTime_PrayerTrigger received command "Isha"
then
    prayerTrigger.apply(timers, receivedCommand.toString)
end

rule "Before Maghrib"
when
    Item PrayerTime_BeforePrayerTrigger received command "Maghrib"
then
    PrayerTime_MaghribPeriod.postUpdate(ON)
    PrayerTime_MaghribLightsTrigger.sendCommand(ON)
end

rule "After Maghrib"
when
    Item PrayerTime_AfterPrayerTrigger received command "Maghrib"
then
    PrayerTime_MaghribPeriod.postUpdate(OFF)
    PrayerTime_MaghribLightsTrigger.sendCommand(OFF)
end

rule "Maghrib Lights"
when
    Item PrayerTime_MaghribLightsTrigger received command
then
    if (House_HomeAway.state.toString == "home") {
        MaghribLights.sendCommand(receivedCommand)
    }
end


(Rich Koshak) #31

Oh, so on system started is plays all the prayers that have occurred so far for that day in parallel. That narrows things down significantly.

I bet this is exactly the case. And the fix is really simple.

// Create a Timer that sendCommand to trigger with cmd at the passed in time
val Procedures$Procedure5<Map<String, Timer>, String, DateTimeType, String, String> createPrayerTimer = [ timers, key, time, trigger, cmd |
    val timerTime = new DateTime(time.getZonedDateTime.toInstant.toEpochMilli)
    timers.get(key)?.cancel

    // Only create a Timer if the time is in the future
    if(timerTime.isAfter(now)) {
        timers.put(key, createTimer(timerTime, [ |
            sendCommand(trigger, cmd)
            timers.put(key, null)
        ]))
    }
]

(Vincent Regaud) #32

Yep, that worked, thanks


(Amin Afip) #33

I am having a problem .The value that I set did not work. Using Egypt method with Angle fajr 20 degrees and isha 18 degrees

prayTimes = PrayTimes(‘Egypt’)
prayTimes.adjust( {‘highLats’:‘AngleBased’, ‘fajr’: 20, ‘isha’: 18 } );
times = prayTimes.getTimes(date.today(), (3.054543,101.765242,0), timeZoneOffset);
print times;

{‘isha’: ‘13:41’, ‘asr’: ‘09:44’, ‘sunset’: ‘12:27’, ‘dhuhr’: ‘06:19’, ‘maghrib’: ‘12:27’, ‘imsak’: ‘22:38’, ‘midnight’: ‘18:19’, ‘sunrise’: ‘00:11’, ‘fajr’: ‘22:48’

the time that I should get is
|Fajr|5:49 am|
|Sunrise|7:11 am|
|Dhuhr|1:20 pm|
|Asr|4:44 pm|
|Maghrib|7:28 pm|
|Isha|8:42 pm|


(Vincent Regaud) #34

There is a bug with the ime zone that I didn’t have a problem with because I am in time zone 0.

It looks like you are 5 hours off so change this:

times = prayTimes.getTimes(date.today(), (3.054543,101.765242,0), 5);

Change the last digit until you get the correct times for your time zone


(Amin Afip) #35

ok. Thanks, it worked… I am learning up python now and will probably add some additional code to support Malaysia calculation method. For now I am adding a new method but still testing it.

methods = {
‘MWL’: {
‘name’: ‘Muslim World League’,
‘params’: { ‘fajr’: 18, ‘isha’: 17 } },
‘ISNA’: {
‘name’: ‘Islamic Society of North America (ISNA)’,
‘params’: { ‘fajr’: 15, ‘isha’: 15 } },
‘Egypt’: {
‘name’: ‘Egyptian General Authority of Survey’,
‘params’: { ‘fajr’: 19.5, ‘isha’: 17.5 } },
‘Makkah’: {
‘name’: ‘Umm Al-Qura University, Makkah’,
‘params’: { ‘fajr’: 18.5, ‘isha’: ‘90 min’ } }, # fajr was 19 degrees before 1430 hijri
‘Karachi’: {
‘name’: ‘University of Islamic Sciences, Karachi’,
‘params’: { ‘fajr’: 18, ‘isha’: 18 } },
‘Tehran’: {
‘name’: ‘Institute of Geophysics, University of Tehran’,
‘params’: { ‘fajr’: 17.7, ‘isha’: 14, ‘maghrib’: 4.5, ‘midnight’: ‘Jafari’ } }, # isha is not explicitly specified in this method
‘Jafari’: {
‘name’: ‘Shia Ithna-Ashari, Leva Institute, Qum’,
‘params’: { ‘fajr’: 16, ‘isha’: 14, ‘maghrib’: 4, ‘midnight’: ‘Jafari’ } },
’Malaysia’: {
’name’: ‘Jakim Malaysia, Malaysia’,
’params’: { ‘fajr’: 20, ‘isha’: 18 } }
}


(Amin Afip) #36

Hi,
I am a bit confused, I new new to OH, creating rules and items. I tried to follow the tutorial and going thru all the comments and improvement suggestions and I am lost. Correct me if i am wrong please check whether all the files are correct , I am using raspberry pi.

Additional question How do I display the solat time in the UI?

File created as per the tutorial

For Directory
/etc/openhab2/items/
prayertimes.items

For Directory /etc/openhab2/rules
magriblight-timeChange.rules
prayertimes-check.rules
prayertimes.rules
pray.rules

for Directory /etc/openhab2/scripts
adhan.py
prayertimes.py

for Directory /etc/openhab2/transform
maghriblight.js

Am I good to go?