…and how to solve it.
Yes, this is another thread about the widespread topic on “how can i implement a simple UI configurable scheduler, e.g. for an alarm clock?”.
However my intent is a bit different, essentially all the discussions i saw on this topic tried to solve the problem more or less elegant, but none of those discussions focused on the root cause, or why it actually is so difficult to achieve something which should be very easy?
So let’s take a look at the underlying root cause and how to fix that:
User Requirement:
A simple functionality to Configure Alarms etc. on the UI Level, must work without dependecies to other services (offline) and if possible be solvable with core Openhab functionality.
Problem: The simplest approach as stated in plenty of other discussions would be to utilize Cron, but Cron doesnt work with variables (due to the nature of how it works) which is required if we want to be able to configure it on a UI level, there are solutions to this, but none of them are simple or straightforward. So what is missing here?
Root Cause: For this we need to take a look at the environment we are actually working in, for this scheduling task we want to use the Rule Engine within Openhab, on this “abstraction layer” of the application we are working purely event based, we listen for updates on Items and if one is triggered we run our logic. Cron however is purely timing based, this is a component of the OS layer which is exposed in Openhab, but it doesn’t really fit into this event based environment. So we need a way somehow to bridge these two worlds, the timing based “Time” capabilities of the OS and our event based rules in Openhab.
The 90% Solution (Working):
So to make this work we essentially need a Time Item that contains the current Timestamp and that triggers a event whenever this is updated. There is actually a binding that provides just what we are looking for. A real genius developed the NTP Binding , somehow however i only found two instances in Blogs were this slightly gets touched that it can be utilized for rules, it seems it is completely overlooked how genius this actually is.
Prerequisites:
- Openhab
- Item Persistence
- NTP-Binding
How to configure:
- Install the NTP Binding, leave the config at default values (triggers an update event once a minute)
- Create an Item Alarm_Hour with Type number (done in PaperUi), rest of the fields can be left empty
- Create an Item Alarm_Minutes with Type number (done in PaperUi), rest of the fields can be left empty
- Create a UI in Habpanel to fill the Items, what i used for testing:
- Widget:Knob Name:Hours, linked to Alarm_Hour, Min 0, Max 23
- Widget:Knob Name:Minutes, linked to Alarm_Minutes, Min 0, Max 59
Rule
rule "Alarm_Clock1"
when
Item LocalTime_Date received update //Rule triggers when the NTP Time is updated, based on the configured Refresh
then
var String vLocalTime = LocalTime_Date.state.format("%1$tH:%1$tM") //Format Date String from NTP Binding to HH:MM
var String vAlarm_Hour = Alarm_Hour.state.toString //Format Number Format from UI to String, relevant for Length check below
var String vAlarm_Minutes = Alarm_Minutes.state.toString
var String vAlarm_Time
if (vAlarm_Hour.length == 1) { // Ensure that Hours input from UI has two characters (05)
vAlarm_Time = "0" + vAlarm_Hour // Build UI Set Alarm Time String
}
else {
vAlarm_Time = vAlarm_Hour
}
if (vAlarm_Minutes.length == 1) { // Ensure that Minutes input from UI has two characters (05)
vAlarm_Time = vAlarm_Time + ":0" + vAlarm_Minutes // Build UI Set Alarm Time String
}
else {
vAlarm_Time = vAlarm_Time + ":" + vAlarm_Minutes
}
if (vAlarm_Time == vLocalTime) { // Actual Condition, if NTP Time equals Time Set on UI then execute
Plug_3.sendCommand(ON)
}
logInfo("AlarmClock", "vLocalTime= "+ vLocalTime) //only used for Debug Logging, can be removed
logInfo("AlarmClock", "vAlarm_Hour= "+ vAlarm_Hour)
logInfo("AlarmClock", "vAlarm_Minutes= "+ vAlarm_Minutes)
logInfo("AlarmClock", "vAlarm_Time= "+ vAlarm_Time)
end
Note: I am not a developer, so there might be more elegant ways to write the above code, this is intended to be easily understandable. Also the intend is to showcase the concept of event-based Time items and how they can make scheduling easier, obviously for a proper alarm clock there are things like days and a general on/off switch missing.
However, this works like a charm, can be up and running in 5minutes and is simple and straightforward.
HabPanel Ui (nothing fancy, but it works):
Log Output:
==> /var/log/openhab2/events.log <==
2020-01-11 10:14:55.214 [ome.event.ItemCommandEvent] - Item 'Alarm_Hour' received command 10
2020-01-11 10:14:55.225 [vent.ItemStateChangedEvent] - Alarm_Hour changed from 9 to 10
2020-01-11 10:14:56.981 [ome.event.ItemCommandEvent] - Item 'Alarm_Minutes' received command 15
2020-01-11 10:14:56.989 [vent.ItemStateChangedEvent] - Alarm_Minutes changed from 16 to 15
==> /var/log/openhab2/events.log <==
2020-01-11 10:15:38.075 [vent.ItemStateChangedEvent] - LocalTime_Date changed from 2020-01-11T10:14:38.055+0100 to 2020-01-11T10:15:38.064+0100
2020-01-11 10:15:38.113 [ome.event.ItemCommandEvent] - Item 'Plug_3' received command ON
==> /var/log/openhab2/openhab.log <==
2020-01-11 10:15:38.117 [INFO ] [se.smarthome.model.script.AlarmClock] - vLocalTime= 10:15
2020-01-11 10:15:38.125 [INFO ] [se.smarthome.model.script.AlarmClock] - vAlarm_Hour= 10
2020-01-11 10:15:38.131 [INFO ] [se.smarthome.model.script.AlarmClock] - vAlarm_Minutes= 15
2020-01-11 10:15:38.137 [INFO ] [se.smarthome.model.script.AlarmClock] - vAlarm_Time= 10:15
==> /var/log/openhab2/events.log <==
2020-01-11 10:15:38.142 [nt.ItemStatePredictedEvent] - Plug_3 predicted to become ON
2020-01-11 10:15:38.155 [vent.ItemStateChangedEvent] - Plug_3 changed from OFF to ON
100% Solution (Concept):
Ok, so the above solution is already great, but only because the NTP-Binding provides exactly that missing concept. From my perspective an event based time Component/Item should be a core Item of Openhab. The NTP-Binding again relies on some “outside service” so is not really usable offline (not an issue for most, but might be for some).
So having a OpenHab SystemDateTime Item that offers the same event based update would solve i think the biggest underlying problem for most scheduling attempts
A proper scheduler of course should work slightly different but this is an important concept to actually solve that.
Conclusion: I don’t know if i missed something fundamental, however i have not seen this approach described anywhere, and other automation solutions seem to fall short in this area as well, so it seems like a wider spread issue. I also saw all the counter arguments and options like using caldav etc. but they are either over the top, rely again on complex config, or outside services. and setting these values simply in the rules file in the cron section is just not user friendly, if you are the only person in your home using your automation that might be viable, if you have other people as well you need to be able to set stuff like this on the UI. The WAF is just higher if she can set her own alarm.
Also, i am new on here, have been working with OpenHab now for the last year or so, so if i missed something about creating posts etc. please let me know