Ok, I’m the worlds biggest Grinch in November, but I’m festive as heck in December, so I’d like to have this ready by then. I want to write a rule to operate the Christmas lights, but obviously only if it’s between 2 specific days (Dec 1 and Jan 7). I thought about a simple CRON rule to toggle a “Christmas” switch on those two dates, and let the other rules run only when “Christmas” is ON, but I’d like something that can be run on startup, and check if it’s between those days. Sounds pretty simple, buy I’m not overly familiar with DateTime. I’m wondering what kind of solutions everyone’s come up with.
Are your lights on all day during this period? I’m not knocking you for writing a rule, it’s a good concept for say season-based heating schedules, but seems a bit extreme for flipping a switch and leaving it for 2 months.
Heck no! I don’t have the money to burn that kind of electricity. The outside lights come on at sunset, and turn off at 11. The tree lights come on at sunset, but only when I’m at home, and turn off at bedtime.
To simplify my main code, I run the above at startup, and on dec 1 and Jan 8, and toggle a virtual switch. Then in the main code, I simply need to run if(Christmas.state == ON). Just for fun, I also change the label of the living room plug to “Christmas Tree”, if the virtual switch is on.
If you have other places where you may want to apply this sort of thing, you might be interested in the Time of Day Design Pattern:
The tl;dr is you have a String Item which represents state and a rule or rules to calculate the state. In your rules that care they just check the state to see what it should do. I’ve found a String is better primarily because once you have more than a couple of states maintaining Switches becomes challenging.
Oh, wow! That sounds like it could be VERY useful. I might have to play around with it during Christmas break. I’m guessing, requiring a string item to make the data available system-wide, that there’s no way to use some sort of array to record multiple states? Say if(ToD[1] == “Dusk”), if(ToD[2] == “Weekend”), if(ToD[3] == “Christmas”)…
Actually, I suppose you could split the string to create an array. I forget how to go about that in openHab, but something along the lines of ToD.split(“,”)
Bit late to the party on this one. Lets just say im already getting ready for this year’s festivities.
I’ve taken work by @rlkoshak and the idea from @Steve40 and integrated them.
val logName = "Events"
rule "Calculate time of day state"
when
System started or
Channel 'astro:sun:local:civilDawn#event' triggered START or
Channel 'astro:sun:local:daylight#event' triggered START or
Channel 'astro:sun:local:civilDusk#event' triggered START or
Channel 'astro:sun:local:civilDusk#event' triggered END or
Time cron "0 0 12,0 * * ? *" // there is currently a bug where only one cron is triggered per rule so I've combined all three into one
then
Thread::sleep(1000) // make sure we are a tad past midnight to give Astro a chance to recalculate DateTimes for today
// Time of Day Calculations
val long dawn_start = (vDawn_Time.state as DateTimeType).calendar.timeInMillis
val long morning_start = (vDaylight_Time.state as DateTimeType).calendar.timeInMillis
val long afternoon_start = now.withTimeAtStartOfDay.plusHours(12).millis
val long dusk_start = (vDusk_Time.state as DateTimeType).calendar.timeInMillis
val long night_start = (vNight_Time.state as DateTimeType).calendar.timeInMillis
val long bed_start = now.withTimeAtStartOfDay.millis
var curr = "UNKNOWN"
switch now {
case now.isAfter(dawn_start) && now.isBefore(morning_start): curr = "DAWN"
case now.isAfter(morning_start) && now.isBefore(afternoon_start): curr = "MORNING"
case now.isAfter(afternoon_start) && now.isBefore(dusk_start): curr = "AFTERNOON"
case now.isAfter(dusk_start) && now.isBefore(night_start): curr = "DUSK"
case now.isAfter(night_start): curr = "NIGHT"
case now.isAfter(bed_start) && now.isBefore(dawn_start): curr = "BED"
}
if(vTimeOfDay.state.toString != curr) {
logInfo(logName, "Current time of day is now " + curr)
vTimeOfDay.sendCommand(curr)
}
// Time of Year Calculations
val long xmas_dec_start = now.withDate(now.getYear(),12,1).withTime(0,0,0,0).millis // 01/12 00:00
val long xmas_dec_end = now.withDate(now.getYear(),12,31).withTime(23,59,59,999).millis // 31/12 23:59
val long xmas_jan_start = now.withDate(now.getYear(),1,1).withTime(0,0,0,0).millis // 01/01 00:00
val long xmas_jan_end = now.withDate(now.getYear(),1,6).withTime(0,0,0,0).millis // 06/01 00:00
curr = "UNKNOWN"
switch now {
case now.isAfter(xmas_jan_start) && now.isBefore(xmas_jan_end): curr = "CHRISTMAS"
case now.isAfter(xmas_dec_start) && now.isBefore(xmas_dec_end): curr = "CHRISTMAS"
}
if(vTimeOfYear.state.toString != curr) {
logInfo(logName, "Current time of year is now " + curr)
vTimeOfYear.sendCommand(curr)
}
end
This is currently showing as UNKNOWN for time of year. I’ve done it like this in case I want other times of year tracked. Although at the moment it’s only CHRISTMAS which I’m really interested in. It’s currently hiding the switches in my site map for the christmas lights. I will eventually write some rules which fire the light on automatically.
Idea being…
Outside lights ON if CHRISTMAS and DUSK and OFF at BED
Inside light ON if CHRISTMAS and someone is home (via presence detection) and only between certain hours and BED.
Thought I would share as i’ve take a lot from this community.