Alarm clock

Hey, because this was todays top result from searching “openhab alarm clock” I would like to post my improved version. It it’s a mix of this and code from the android alarm-clock - version

Add your things to do in line 71 of the rule

items:

Number ALARM1_PERSON1_H    "Wecker Stunde [%s]"
Number ALARM1_PERSON1_M    "Wecker Minute [%s]"  
String ALARM1_PERSON1_D    "Wecker Wochentage"  

Sitemap:

Frame label="Wecker" {        
     Selection item=ALARM1_PERSON1_D label="Tage" mappings=[0="  Aus  ", 1="  Mo - Fr  ", 2="  Sa - So  ", 3="  Alle Tage  "]`
     Setpoint item=ALARM1_PERSON1_H label="Stunde" minValue=0 maxValue=23 step=1
     Setpoint item=ALARM1_PERSON1_M label="Minuten" minValue=0 maxValue=55 step=5
}

Rule:

import java.time.ZonedDateTime
import java.time.DayOfWeek

val org.eclipse.xtext.xbase.lib.Functions$Function1<ZonedDateTime,ZonedDateTime> getNextAlarm= [ ZonedDateTime s |
    var newTime = s
    if(newTime < ZonedDateTime.now){
        newTime = newTime.plusDays(1)        
    } 
    val DayOfWeek[] theWorkDays = newArrayList(DayOfWeek.MONDAY,DayOfWeek.TUESDAY,DayOfWeek.WEDNESDAY,DayOfWeek.THURSDAY,DayOfWeek.FRIDAY)
    val DayOfWeek[] weekEndDays = newArrayList(DayOfWeek.SATURDAY,DayOfWeek.SUNDAY)

    var dayIsValid = false

    while (dayIsValid == false) {
        switch(ALARM1_PERSON1_D.state as Number) { 
            case 1: dayIsValid = theWorkDays.contains(newTime.getDayOfWeek())
            case 2: dayIsValid = weekEndDays.contains(newTime.getDayOfWeek())
            case 3: dayIsValid = theWorkDays.contains(newTime.getDayOfWeek()) || weekEndDays.contains(newTime.getDayOfWeek())
        } 

        if(dayIsValid == false){
            newTime = newTime.plusDays(1)
        }
    }
    newTime.withSecond(0)
]

var Timer timerAlarm = null

rule "Alarm Clock"
when
    Item ALARM1_PERSON1_D changed or Item ALARM1_PERSON1_H changed or Item ALARM1_PERSON1_M changed
then
    val settingsOffOrInvalid = (ALARM1_PERSON1_D.state === NULL || ALARM1_PERSON1_D.state == "0") || ALARM1_PERSON1_H.state === NULL || ALARM1_PERSON1_M === NULL || ALARM1_PERSON1_M.state === NULL

    if(settingsOffOrInvalid && timerAlarm !== null){
        logInfo("alarm", "Alarm canceled")
        timerAlarm.cancel
        timerAlarm = null
    }

    if(settingsOffOrInvalid){
        logInfo("alarm", "no alarm set")
        return
    }
    val newHour = (ALARM1_PERSON1_H.state as DecimalType).intValue
    val newMinute = (ALARM1_PERSON1_M.state as DecimalType).intValue

    var newZonedDateTime = ZonedDateTime.now
    newZonedDateTime  = newZonedDateTime.withHour(newHour)
    newZonedDateTime  = newZonedDateTime.withMinute(newMinute)
    val newTime = getNextAlarm.apply(newZonedDateTime)
    logInfo("alarm", newTime.toString) 
    
    val epoch = newTime.toInstant.toEpochMilli
    if (timerAlarm !== null) {
        logInfo("alarm", "Reschedule alarm")
        timerAlarm.reschedule(new DateTime(epoch))
    } else {
        logInfo("alarm_NEW_ALARM", newTime.toString)
        timerAlarm = createTimer(new DateTime(epoch), [ |                    

            // Add you stuff to do here

            val nextTime = ZonedDateTime.now.plusDays(1)        
            val newResheduleTime = getNextAlarm.apply(nextTime)
            val innerepoch = newResheduleTime.toInstant.toEpochMilli
            logInfo("alarm_FIRED_ALARM_RESCHEDULE", newResheduleTime.toString)
            timerAlarm.reschedule(new DateTime(innerepoch))
        ])
    }     
end