Individual Alarm clock for each Day of week, with adjustable duration

I think the only changes needed for OH 2 is removal of all the imports. Everything else looks OK from an OH 2 perspective.

Applying some of the concepts here and here I think the logic above can be made a little simpler.

First add all the current Items to a Group, I’ll call it gAlarm.

var Timer timerPERSON1Wecker = null

rule "Wecker PERSON1"
when
    Time cron "0 0/1 * * * ?" // note, one could use an external event to trigger the rule if the alarm is implemented elsewhere (e.g. Tasker)
then
    val person = "PERSON1_WECKER_"

    var dayName= "NA"
    switch now.getDayOfWeek{
        case 1: dayName = "MO"
        case 2: dayName = "DI"
        case 3: dayName= "MI"
        case 4: dayName= "DO"
        case 5: dayName= "FR"
        case 6: dayName= "SA"
        case 7: dayName= "SO"
    }

    val person1On = gAlarm.members.filter[s | s.name == person+dayName].head.state

    if(person1On == ON){
        var sollMinute = (gAlarm.members.filter[s | s.name == person+day+"_M"].head.state as Number).intValue
        var sollStunde = (gAlarm.members.filter[s | s.name == person+day+"_H"].head.state as Number).intValue
        var runTime = (gAlarm.members.filter[s | s.name == person+day+"_RUN"].head.state as Number).intValue

        if(sollMinute == now.getMinuteOfHour && sollStunde == now.getHourOfDay) {
            sendCommand(person+"_AKTIV", ON)

            // do stuff

            timerPERSON1Wecker = createTimer(now.plusMinutes(runTime), [|
                // do stuff
                sendCommand(person+"_AKTIV", OFF)
                timerPERSON1Wecker = null
            ])
        }
    }
end

I also beleive this is a perfect place to use lambdas so you don’t have to copy and paste the rule above over and over for each person. I would go about it as follows:

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

val Map<String, Timer> timers = newHashMap

val Functions$Function3 <String, Map<String, Timer>, Functions$Function0, Functions$Function0, Boolean> processAlarm = 
[person, timers, alarmStart, alarmStop |

    var dayName= "NA"
    switch now.getDayOfWeek{
        case 1: dayName = "MO"
        case 2: dayName = "DI"
        case 3: dayName= "MI"
        case 4: dayName= "DO"
        case 5: dayName= "FR"
        case 6: dayName= "SA"
        case 7: dayName= "SO"
    }

    val person1On = gAlarm.members.filter[s | s.name == person+dayName].head.state

    if(person1On == ON){
        var sollMinute = (gAlarm.members.filter[s | s.name == person+day+"_M"].head.state as Number).intValue
        var sollStunde = (gAlarm.members.filter[s | s.name == person+day+"_H"].head.state as Number).intValue
        var runTime = (gAlarm.members.filter[s | s.name == person+day+"_RUN"].head.state as Number).intValue

        if(sollMinute == now.getMinuteOfHour && sollStunde == now.getHourOfDay) {
            sendCommand(person+"_AKTIV", ON)

            // alarmStart is a passed in lambda that implements the stuff to do for that person's alarm
            alarmStart.apply()

            timers.put<person, createTimer(now.plusMinutes(runTime), [|
                // alarmStop is a passed in lambda that implements the stuff to do at the end of that person's alarm
                alarmStop.apply()
                sendCommand(person+"_AKTIV", OFF)
                timers.put(person, null)
            ])
        }
    }

    true
]

rule "Weckers"
when
    Time cron "0 0/1 * * * ?"
then

    val Functions$Function0 <Boolean> person1Start = [|
        // alarm start code
        true
    ]
    val Functions$Function0 <Boolean> person1Stop = [|
        // alarm stop code
        true
    ]

    // define functions for each person, if there is nothing to do for that person you can use [| true]
    // as illustrated with person2 below.

    processAlarm.apply("PERSON1", timers, person1Start, person1Stop)
    processAlarm.apply("PERSON2", timers, [| true], [| true]) // PERSON2 has nothing to do when the alarm starts and ends so we pass empty lambdas
    
end

Notes:

  • The above is OH 2 code. I think it will work for OH 1 as written but you may need one or more imports.
  • I just typed this in, on my phone. It likely contains some errors but it should be pretty close to right.
3 Likes