My Christmas Rule

I just posted “My OpenHab Christmas Rule” over on my blog. However, I know what a pain it it to search all over the code you are looking for, so here is the Items and Rules. If you know a little about OpenHab, you can figure this out. If you want the why, visit my blog.

Items: (There are 3)

Group christmasLights
Switch sChristmasLights "Christmas Lights" <switch>  [ "Lighting" ]
Switch Plug_Christmas_Tree "Christmas Tree"   <switch> (christmasLights)
{
  channel="zwave:device:512:node29:switch_binary"
}

Rules: (There are 2)

import java.time.Year
import java.time.Month
import java.time.temporal.TemporalAdjusters
import java.time.temporal.ChronoUnit
import java.time.DayOfWeek
import java.time.LocalDate

rule "Christmas Lights ON"
when
  Channel "astro:sun:local:civilDusk#event" triggered START
then
  val String currentYear = String::format("%1$tY", new java.util.Date )

  val LocalDate thanksgiving = Year.of(Integer.parseInt(currentYear)).atMonth(Month.NOVEMBER).atDay(1)
    .with(TemporalAdjusters.firstInMonth(DayOfWeek.THURSDAY))
    .with(TemporalAdjusters.nextOrSame(DayOfWeek.THURSDAY))
    .with(TemporalAdjusters.next(DayOfWeek.THURSDAY))
    .with(TemporalAdjusters.next(DayOfWeek.THURSDAY))
    .with(TemporalAdjusters.next(DayOfWeek.THURSDAY))

  var LocalDate lastDayOfYear = Year.of(Integer.parseInt(currentYear)).atMonth(Month.DECEMBER).atDay(1)
    .with(TemporalAdjusters.lastDayOfYear)
  
  var LocalDate today = LocalDate.now()

  if (
    today.until(thanksgiving,ChronoUnit.DAYS)<=0 &&
    thanksgiving.until(lastDayOfYear, ChronoUnit.DAYS)>0
  ) {
    logInfo("LIGHTS","Light the Christmas tree")
    christmasLights.sendCommand(ON)
  } else {
    logInfo("LIGHTS",today.until(thanksgiving,ChronoUnit.DAYS).toString + " days until the Christmas tree is lit.")
  }

end

rule "Christmas Lights OFF"
when
  Time cron "0 0 23 1/1 NOV,DEC ? *"
then
  christmasLights.sendCommand(OFF)
  logInfo("LIGHTS","Christmas, Lights Off")
end

I run this on:

  • RasPi
  • openHAB 2.4.0~S1451-1 (Build #1451)
  • Z-Wave Binding
  • Astro Binding
  • GE Z-Wave external plug This plug is in the Z-Wave database

That’s it. I included the plug in my network, setup the Items and Groups - the last group is so that I can have Alexa turn the lights off when I ask - and I put the rules in my Dusk_till_Dawn.rules file.

I hope this helps you get your seasonal lighting automated.

OH! After I wrote this, I got " Design Pattern: Time Of Day by @rlkoshak working. Wonderful tutorial. I may update my rules for next year using some of his concepts. Thank you Rich. :slight_smile:

Cheers!
=C=

5 Likes

Thanks for posting! Great example.

1 Like

Great example.

I have set up mine with nodered and bigtimer for now. (Was a quick n dirty set up I did in one hour)

I thought about starting jsr223/experimental rule engine for this usecase.
It isn’t needed that urgent, but has some logic to play around with.

2 Likes

I’ve got the rules engine installed but honestly, as a programmer, I like writing them…even when they get ugly like this one. :slight_smile:

Cheers!
=C=

Do you need any import for the temporalAdjuster and ChronoUnit?

Gah!

I can’t believe I forgot the imports. Sorry. :slight_smile: . Yes, you do need the following import statements in your rules file.

import java.time.Year
import java.time.Month
import java.time.temporal.TemporalAdjusters
import java.time.temporal.ChronoUnit
import java.time.DayOfWeek
import java.time.LocalDate

Cheers! :slight_smile:
=C=

1 Like

Could you add them to your original post, please?
Thanks

I did. :slight_smile:

Cheers!
=C=

Thanks, These imports are going to come in useful.
Learned something new today!!

1 Like

If you do please post how you did it. We will need lots and lots of examples. :slight_smile:

So, if you want to make the code a little cleaner you can take advantage of cron triggers and perhaps Astro season events to populate a TimeOfYear state. Then you can use a few very simple Rules instead of the complicated date math.

Let’s make it even simpler and have a ChristmasTime Switch.

Switch ChristmasTime "Tis the season"
rule "Christmas Time"
when
    Time cron "45 0 0 ? NOV 5#4 *" or // 4th Thursday of November
    Time cron "45 0 0 31 DEC ? *" // Last day of the year
then
    ChristmasTime.sendCommand(if(now.getMonthOfYear == 11) ON else OFF)
end

rule "Christmas Lights ON"
when
  Channel "astro:sun:local:civilDusk#event" triggered START
then
    if(ChristmasTime.state == OFF) return;
    logInfo("LIGHTS", "Light the Christmas tree")
    christmasLights.sendCommand(ON)
end

rule "Christmas Lights OFF"
when
  Time cron "0 0 23 1/1 NOV,DEC ? *"
then
  christmasLights.sendCommand(OFF)
  logInfo("LIGHTS","Christmas, Lights Off")
end

Of course you lose the nice logInfo calculation of the number of days until the tree is lit. For that I don’t think there is any alternative that is any cleaner than what you have. Working with Dates is always ugly.

And I too learned something. I’m not familiar with those classes. I guess I’ve been away from Java too long.

2 Likes

WOW!

Compares to my code that is dang near elegant. Thanks again. :slight_smile:

Cheers!
=C=

Just one little bit:
I would change the cron triggers in the first rule so as not to conflict with other “midnight” jobs

rule "Christmas Time"
when
    Time cron "45 0 0 ? NOV 5#4 *" or // 4th Thursday of November
    Time cron "45 0 0 31 DEC ? *" // Last day of the year
then
    ChristmasTime.sendCommand(if(now.getMonthOfYear == 11) ON else OFF)
end

1 Like

I’ve been at this awhile and have taken it upon myself to figure out how to code in Rules DSL well. Now that I’m really good at it the NGRE is coming down the line.

image

Great point. I’ll update my code accordingly.

I fully agree and this is one reason i didn’t try to switch yet.
If i do so it will definetely be a combination of experimental engine combined with JSR223 (i think javascript will be my choice then), which uses the script area.

1 Like

I am waiting/hoping for your tutorial to get started. :smile:
Maybe i can use it as a starting point and help out improving the threads before we add them to the docs.

1 Like

What I have so far start’s here. There are five posts in the series (see the little navigation links at the bottom of each post).

I have a good start. I have the basics, installation, importing libraries, what implicit variables are available, and started on Actions. I still need to cover “but only if…” , templates, creating your own libraries, and lots of examples. I think there is enough there to get started. But the time based triggers are one thing that is somewhat lacking which would make my approach challenging.

1 Like

Sounds really promising already.
Maybe i can start with that soon.
Current priority topic is the vscode extension, which need a bit love after this long time without updates.

3 Likes

My xMas Tree Plug (WeMo & Hue Motion) Rules:


//
// xMas Tree Plug
//

rule "xMas Tree turn ON when a phone is ON and Dec and Weekend "
     when
		Item Kitchen_Motion_Sensor changed to ON
     then

		currMonth = now.getMonthOfYear
		currHour = now.getHourOfDay
		currDayofWeek = now.getDayOfWeek

		if (Wallplug_xMas_Tree.state == OFF && currMonth == 12 && currHour >= 7  && currHour <= 21 && Home_Away.state == ON && (JsAndriodUnifi.state == ON || TsiPhoneUnifi.state == ON)) { 

			if (currDayofWeek == 6 || currDayofWeek == 7) {

				// Turn ON xMas Tree
				Wallplug_xMas_Tree.sendCommand(ON)
					Thread::sleep(3000)  // 3 second wait
				Wallplug_xMas_Tree.sendCommand(ON)
					Thread::sleep(3000)  // 3 second wait

				logInfo("WeMo", "Turned ON xMas Tree Plug based on motion, phones, hour, day and month.")
			}
		}
end


rule "xMas Tree Plug turn OFF when both phones are off the network"
     when
    	Item JsAndriodUnifi changed to OFF or
		Item TsiPhoneUnifi changed to OFF
     then

		if (JsAndriodUnifi.state == OFF && TsiPhoneUnifi.state == OFF) {

			// Shut off xMas Tree
			Wallplug_xMas_Tree.sendCommand(OFF)
				Thread::sleep(3000)  // 3 second wait
			Wallplug_xMas_Tree.sendCommand(OFF)
				Thread::sleep(3000)  // 3 second wait

			logInfo("WeMo", "Turned OFF xMas Tree Plug because both Cell Phones are gone.")
		}
end

Best, Jay

1 Like

It is advisable not to use Thread::sleep for more than 500ms
You can use timers instead:
Why are you sending the command twice to turn ON and OFF the Xmas tree?

rule "xMas Tree turn ON when a phone is ON and Dec and Weekend "
when
    Item Kitchen_Motion_Sensor changed to ON
then
    currMonth = now.getMonthOfYear
    currHour = now.getHourOfDay
    currDayofWeek = now.getDayOfWeek

    if (Wallplug_xMas_Tree.state == OFF && currMonth == 12 && currHour >= 7  && currHour <= 21 && Home_Away.state == ON && (JsAndriodUnifi.state == ON || TsiPhoneUnifi.state == ON)) { 
        if (currDayofWeek == 6 || currDayofWeek == 7) {
            // Turn ON xMas Tree
            Wallplug_xMas_Tree.sendCommand(ON)
            createTimer(now.plusSeconds(3), [ | Wallplug_xMas_Tree.sendCommand(ON) ])
            createTimer(now.plusSeconds(6), [ | logInfo("WeMo", "Turned ON xMas Tree Plug based on motion, phones, hour, day and month.") ])
        }
    }
end


rule "xMas Tree Plug turn OFF when both phones are off the network"
when
    Item JsAndriodUnifi changed to OFF or
    Item TsiPhoneUnifi changed to OFF
then
    if (JsAndriodUnifi.state == OFF && TsiPhoneUnifi.state == OFF) {
        // Shut off xMas Tree
        Wallplug_xMas_Tree.sendCommand(OFF)
        createTimer(now.plusSeconds(3), [ | Wallplug_xMas_Tree.sendCommand(OFF) ])
        createTimer(now.plusSeconds(6), [ | logInfo("WeMo", "Turned OFF xMas Tree Plug because both Cell Phones are gone.") ])
        logInfo("WeMo", "Turned OFF xMas Tree Plug because both Cell Phones are gone.")
    }
end

My setup is a little different as we don’t always get to put up the tree and lights at the same time. I have my outside lights on this too. I have a switch that says it’s christmas time to cover this since we sometime are late getting the stuff setup.

My “Settings” sitemap

sitemap settings label="Settings"
{
                Setpoint item=BedtimeTimer minValue=1 maxValue=10 step=1
                Setpoint item=BarrelCount step=1
                Setpoint item=MasterBedroomLightSleepTime minValue=10 maxValue=250 step=5
                Setpoint item=MasterBedroomLightNumReadings minValue=10 maxValue=500 step=5
                Switch item=ChristmasTime
}

My living room menu only shows christmas lights option if “Christmas time” switch is on.

sitemap home label="Main Menu"
{
        Frame {
                Switch item=Bedtime_Scene
                        Text label="Living Room" icon="firstfloor" {
                        Switch item=LivingRoomLights mappings=[OFF="All Off", ON="All On"]
                        Switch item=ChristmasLights visibility=[ChristmasTime==ON] mappings=[OFF="All Off", ON="All On"]

My items have the virtual switch for all my xmas lights. the group and my one living room light is also where the christmas tree goes. so it’s part of that group too.

Group gchristmaslights
Switch ChristmasLights "Christmas Lights"

Switch Switch_LivingRoom_Light "Living Room Light"     <light> (gchristmaslights,gLivingRoomLights,gDashboard)
rule "Christmas Lights"

when
        Item ChristmasLights changed
then
   if(ChristmasLights.state==ON)
        {
        gchristmaslights.send(ON)
        logInfo("All xmas Lights","ON")
        sendCommand(gchristmaslights,ON)

        }
   else
        {
        logInfo("All xmas Lights","OFF")
        gchristmaslights.send(OFF)
        }


end


rule "xmas morning lights"
    when
            Time cron "0 30 6 * * ?"
    then
        if (ChristmasTime.state == ON)
        {
                gchristmaslights.send(ON)
                logInfo("All xmas Lights","ON")
        }
    end


Each morning, if it’s christmas time the lights turn on. This way the tree is lit each morning when the kids get up. The christmas inflatables are up and saying hi to everyone as they are off to work/school.

1 Like