Alarm clock

Edit: I still use this example, but for new users I suggest having a look at https://www.openhab.org/docs/apps/android.html#alarm-clock.

Original Post:

What makes this solution different is that you have only a minimal set of items (3) per alarm, but still be able to restrict it to days. The Day item contains the a string which defines start and end day,e g. 15 is monday to friday.

Items

Number ALARM1_PERSON1_H    "Hour [%s]"
Number ALARM1_PERSON1_M    "Minute [%s]"  
String ALARM1_PERSON1_D    "Day"                  
Number ALARM2_PERSON1_H    "Hour [%s]"    
Number ALARM2_PERSON1_M    "Minute [%s]"    
String ALARM2_PERSON1_D    "Day"                  

Sitemap

Selection item=ALARM1_PERSON1_D mappings=[90="  Off  ", 15="  1 - 5  ", 67="  6 - 7  ", 17="  1 - 7  "]
Setpoint item=ALARM1_PERSON1_H minValue=0 maxValue=23 step=1
Setpoint item=ALARM1_PERSON1_M minValue=0 maxValue=55 step=5

Rule

rule "ALARM PERSON1"
when
    Time cron "0 * * * * ?"
then
    var day_number = now.getDayOfWeek.toString
    var minute_now = now.getMinuteOfHour
    var hour_now = now.getHourOfDay
    var ALARM1_PERSON1 = ((ALARM1_PERSON1_M.state as DecimalType).intValue == minute_now &&
                        (ALARM1_PERSON1_H.state as DecimalType).intValue == hour_now &&
                        day_number >= ALARM1_PERSON1_D.state.toString.substring(0,1) &&
                        day_number <= ALARM1_PERSON1_D.state.toString.substring(1,2))
    var ALARM2_PERSON1 = ((ALARM2_PERSON1_M.state as DecimalType).intValue == minute_now &&
                        (ALARM2_PERSON1_H.state as DecimalType).intValue == hour_now &&
                        day_number >= ALARM2_PERSON1_D.state.toString.substring(0,1) &&
                        day_number <= ALARM2_PERSON1_D.state.toString.substring(1,2))
    if(ALARM1_PERSON1 || ALARM2_PERSON1){
        // do stuff, e.g. turn radio or light on
        TIMER_PERSON1_ALARM=createTimer(now.plusMinutes(80)) [|
			// turn off stuff
        ]
    }
end
10 Likes

hi, can u help me? … i want to use ur alarm in my setup so i can on/off any item, i dont mind repeating the rule/sitemap for each item…how can i achieve this?

thanks

You could copy the items and rules for each item you want to switch, but there is probably a better solution.
Let’s say you have the items A and B, you could define A_ALARM and B_ALARM, put them in a group and check this group for all on items. Then remove “_ALARM” from their name and you have the item, that should turned on.

im sorry, but can u provide me example…

thanks… let me have a look on this… i just started in openhab

Salaam brother,
Once you come up with some code, if it doesn’t work, post it here and we’ll have a look at it to help, but we are not here to write code for you.
Take care

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

there seems to be a typo in sitemap last symbol here:
Alle Tage "]`

I quickly tried it and alarm doesn´t get triggerted, log shows:
Rule ‘Alarm Clock’: Could not cast 1 to java.lang.Number; line 17, column 16, length 32

Diddn´t got time to investigate, but doesen´t seem to run out of the box.

Made a few changes, this works for me in OH3. Thanks for posting this.

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.toString) { 
            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) 
    
    if (timerAlarm !== null) {
        logInfo("alarm", "Reschedule alarm "+newTime.toString)
        timerAlarm.reschedule(newTime)
    } else {
        logInfo("alarm_NEW_ALARM", newTime.toString)
        timerAlarm = createTimer(newTime, [ |                    

            // Add you stuff to do here
            logInfo("alarm", "Do stuff here")

            val nextTime = ZonedDateTime.now.plusDays(1)        
            val newResheduleTime = getNextAlarm.apply(nextTime)
            logInfo("alarm_FIRED_ALARM_RESCHEDULE", newResheduleTime.toString)
            timerAlarm.reschedule(newResheduleTime)
        ]) 
    }     
end
1 Like

PROBLEM SOLVED!
After waiting two days it works

Hey everybody,
i built items and rules like tutorial in OH 3.
OH3 shows the correct alarm time und the log alse shows the correct alarm changes.
Bute my choosen things didn’t start at alarm time.
Did anyone find the error at my rule?

var Timer timerAlarm = null

rule "Alarm Clock"
when
    Item S20AlarmClock changed
then

	if (newState instanceof DateTimeType) {
        val epoch = newState.toLocaleZone.zonedDateTime.toInstant.toEpochMilli
        logInfo("alarm", "Scheduling alarm for {} ({})", newState.toLocaleZone, epoch)
		
		 if( timerAlarm !== null ) {
            logInfo("alarm", "Reschedule alarm")
            timerAlarm.reschedule(newState.toLocaleZone.zonedDateTime)
        } else {
            logInfo("alarm", "New alarm")
            timerAlarm = createTimer(newState.toLocaleZone.zonedDateTime, [ |
		
                // Turn on stuff, e.g. radio or light
							
				Echo_Living_Room_Radio.sendCommand(ON)
				Echo_Living_Room_Player.sendCommand('PLAY')
				RadioPower.sendCommand(ON)
				
				logInfo("alarm", "Alarm expired")
				
                timerAlarm = null
            ])
        }
    } else {
        if (timerAlarm !== null) {
            timerAlarm.cancel
            timerAlarm = null
        }
        logInfo("alarm", "Alarm canceled")
    }
end

Hey,
my alarm clock is working witch a Samsung Galaxy S20.
But it allways triggered an alarm at 00:00?
Any idea how to fix this problem?

Problem solved.