I created a GUI of sorts for a similar problem. I simplified it by assuming that I can only set times in 15 minute increments, and I set the time as a number e.g. 0900 or 1245.
I used a setpoint to adjust them with a minvalue of 0 and a maxvalue of 2345, step 15, which forces the 15 minute increments.
I then wrote a rule that notices whether you’re going upwards or downwards when you adjust it, and moves 1245 up to 1300, and 1300 down to 1245.
The upshot of all this is that I get a setpoint that only accepts values from 00:00 to 23:45, only accepts values in 15 minute increments, and ticks up or down in 15 minute blocks including wrapping from 45->00 minutes on the way up, and 00->45 minutes on the way down.
The sitemap is something like:
Setpoint item=timeStart1Guest minValue=0 maxValue=2345 step=15
Then in the items we have something like:
Group:Number:SUM zoneSettingsTimes (All)
Number timeStart1Guest "Time Start [%04d]" <clock> (zoneSettingsTimes)
This means I can tell when any time has changed it’s setting, as the zoneSettingsTimes (which is a sum) will change. I run time normalisation rules any time any time field has changed:
import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import org.openhab.core.library.types.DecimalType
/*
This set of rules normalise the time fields in each zone, so that minutes are always
in 15 min blocks, and wrap around at 60, not at 99
*/
/*
Function defined as a lambda. Stupid function syntax if you ask me!!
This looks at the minutes, if it's 85 then we went down, and should be 45, if it's 60 then
we went up, and should be 00 plus add one to the hour
*/
val org.eclipse.xtext.xbase.lib.Functions$Function1 normaliseMinutes = [
org.openhab.core.library.items.NumberItem timeStart |
var int currentHours = (timeStart.state as DecimalType).intValue / 100
var int currentMinutes = (timeStart.state as DecimalType).intValue % 100
if( currentMinutes == 85 ) {
currentMinutes = 45
}
if( currentMinutes == 60 ) {
currentMinutes = 0
currentHours = currentHours + 1
}
if( (timeStart.state as DecimalType).intValue != currentHours * 100 + currentMinutes ) {
postUpdate( timeStart, currentHours * 100 + currentMinutes )
}
]
/*
Time normalisers - call the time normaliser whenever a Time field gets changed
*/
rule "Modify Time - adjust minutes"
when
Item zoneSettingsTimes changed
then
zoneSettingsTimes.members.forEach( time | {
normaliseMinutes.apply( time )
})
end
This all works well enough, although the UI is quite laggy on my raspberry pi.