Rule to switch on Christmas Lights between 1. Advent and "Heilig Dreikönig"

I tried to create a rule to switch on Christmas lights between 1. Advent and “Heilig Dreikönig” (6th of January). I am new to java and openhab so I thought I’d post the result just to be shure this will work.

rule "Weihnachtsbeleuchtung an"
when
    Item NightState changed to ON
then
    val year = now.getYear
    val month = now.getMonthOfYear
    val day = now.getDayOfMonth
    val sdatum = year+"-"+month+"-"+day
    val DateTime datum = parse(sdatum)
    val DateTime stAdvent = parse(year+"-12-25").minusDays(((parse(year+"-12-25").getDayOfWeek) + 21))
    val DateTime h3k = parse(year+"-1-6")
    if ( stAdvent <= datum && datum <= h3k ) {
        Weihnachtsbeleuchtung_Command.sendCommand(ON)
    }
end

If there are any errors or if there is a more elegant approach I’d really appreciate your help.

Volker

Hey Volker,

I didn’t check the rule in detail (time parsing can be a big pain), but it looks logical so far.

Anyways i wanted to share my “different approach”.
I am using a general “Christmas time Mode” Item, which then has affect on other devices.
So they are behaving like a normal outlet during the year but act like a christmas light in the specific timeframe.

(Rules are ported to Javascript, but i think you can get an impression of the logic.)

// Switch christmas mode depending on the day/month of the year
JSRule({
    name: "Weihnachtsmodus",
	triggers: [
        TimerTrigger("45 0 0 ? NOV 5#4 *"), // START: 4er Donnerstag im November
        TimerTrigger("45 0 0 31 DEC ? *") // STOP: Letzter Tag des Jahres
	],
	execute: function( module, input){
        var now = new Date();

        logInfo("Weihnachtszeit-Umschaltung gestartet")
        var wMod = getItem("vWeihnachtsmodus");
        // Attention -> getMonth() returns months from 0 = January to 11 = December
        // Month has to be checked for equality to 10 due to this return value
        sendCommand(wMod, (now.getMonth() == 10) ? ON : OFF);
        logInfo("Weihnachtsmodus jetzt auf: " + wMod.state);

	}
});

So what is different here, is that i am running this rule only two times, instead of every night.
(It will also get executed on startup, so i am taking care of this with comparing the actual month.)
Everything it does, is switching the virtual christmas mode item, which will then be used in other rules for decision.

Edit:
From looking at the code again after some time, i have recognised that i have to put in some more effort in the comparing.
I think my christmas lights may stop, when openHAB is restarted in December. :smile:
So don’t look to much at the sendCommand line.
The approach in general is working.

Hi Volker,

as far as I can see your rule is doing the trick and should work fine.

However I’m a fan of seperating behaviors and try to follow that.

Hence I’m using multiple rules to do nearly the same as you:

rule "Weihnachtszeit"
when
	System started or
	Time is midnight
then
	val int year = now.getYear
	val int dayOfYear = now.getDayOfYear
	val int xmas_start = parse(year+"-12-24").getDayOfYear - parse(now.getYear+"-12-24").getDayOfWeek - 21
	val int xmas_end = parse(year+"-01-06").getDayOfYear

	if ((dayOfYear > xmas_start) || (dayOfYear < xmas_end))
		Zeit_Weihnachtszeit.postUpdate(ON)
	else
		Zeit_Weihnachtszeit.postUpdate(OFF)
end

rule "Weihnachtsbeleuchtung ein/aus"
when
	Item Tagesabschnitt changed to "BED" or
	Item Sonne_Phase changed to "SUN_SET"
then
	if (Zeit_Weihnachtszeit.state == ON) {
		if (Tagesabschnitt.state == "BED")
			Weihnachtsbeleuchtung.sendCommand(OFF)
		else if (Sonne_Phase.state == "SUN_SET")
			Weihnachtsbeleuchtung.sendCommand(ON)
	}
end

At every restart and midnight I check if we are between 1st Advent and 6th of Jan. If yes an item is set. Unset otherwise.

Second rule switches on lights at sunset and off when we go to bed (which is actually set at 10pm).

Regards,
Christian

2 Likes

For control of light I have created a library that I plan to add to openhab-.helper-libraries. Right now it is just in the personal section, because I need to do some major cleanup tasks. Unfortunately there is absolute no documentation right now (besides from the code)
If you are familiar with the RuleEngine / jsr223 / Python, you might be able to get it up and running, if you dare the repo is found here:

1 Like

This configuration of the intelliswitch library should turn on your light between sunset and midnight, it does not take dates into account. For that purpose I added a switch switchAllowChristmasLight, set that to ON at dates where your light is allowed to run, and OFF when not allowed.

intelliswitch_configuration = {
    'LOGGING_LEVEL': 'DEBUG',
	'MANAGERS' : [
        {'name': 'LightManager',
		'description': 'Automatic light schedule for livingroom',
		'RULES': [
			{'name': 'AutoLightSchedule-1', 'description': '', 'type': 'schedule', 
			'SCHEDULES': [ 
				{'begin':'14:00', 'end':'0:00'} ],
			'CONDITIONS': [
                                {'type':'item', 'name':'switchAllowChristmasLight'},
				{'type':'check', 'name':'ActiveNight'}],
			'OUTPUTS': [
				{'type':'item', 'name':'NightState'}]
			}
		]}
	]
}

In version 0.4 I have actually added the option of defining a function that can be used for evaluation. A date range might also be a future option :slight_smile:

Thank you @Olti for posting your approach! It inspires me to refine my own light management. :smiley:

One comment:

I assume this will always be the same as

val int xmas_end = 6

Is this correct?

Thank you all for your answers. I found one little error that I have corrected here:

rule "Weihnachtsbeleuchtung an"
when
    Item NightState changed to ON
then
    val year = now.getYear
    val month = now.getMonthOfYear
    val day = now.getDayOfMonth
    val sdatum = year+"-"+month+"-"+day
    val DateTime datum = parse(sdatum)
    val DateTime stAdvent = parse(year + "-12-25").minusDays(((parse(year + "-12-25").getDayOfWeek) + 21))
    val DateTime h3k = parse(year + "-1-6")
    logInfo("RULE", "--> Weihnachtsbeleuchtung getriggert. Datum: " + datum.toString + ". 1. Advent: " + stAdvent.toString + ". Heilig Dreikönig: " + h3k.toString) 
    if ( stAdvent <= datum || datum <= h3k ) {
        Weihnachtsbeleuchtung_Command.sendCommand(ON)
        logInfo("RULE", "--> Weihnachtsbeleuchtung ON")
    }
end

rule "Weihnachtsbeleuchtung aus"
when
    Time cron "0 0 23 1/1 * ? *"
then
    if ( Weihnachtsbeleuchtung_Command.state == ON ) {
        Weihnachtsbeleuchtung_Command.sendCommand(OFF)
        logInfo("RULE", "--> Weihnachtsbeleuchtung OFF")
    }
end

When validating the if datum is between stAdvent and h3k it has to be OR not AND.
I leave it as it is for now. I will see tomorrow if it works.

Yes, I think so.

Mainly implemented it that way to be flexible and have it better to understand what was the intention

This part can now also be implemented using Ephemeris. See Actions | openHAB

For Openhab 3.x:

rule "Christmastime"
when
        System started or
        Time is midnight
then
        val int year = now.getYear
        val int dayOfYear = now.getDayOfYear

        val int xmas_start = LocalDateTime.parse(year + "-12-24T00:00:00").getDayOfYear - LocalDateTime.parse(year + "-12-24T00:00:00").getDayOfWeek.getValue - 21
        val int xmas_end = LocalDateTime.parse(year + "-01-06T00:00:00").getDayOfYear

        if ((dayOfYear >= xmas_start) || (dayOfYear <= xmas_end)) {
                logInfo("CHRISTMAS", "ChristmastimeSwitch ON")
                ChristmastimeSwitch.postUpdate(ON)
        } else {
                logInfo("CHRISTMAS", "ChristmastimeSwitch OFF")
                ChristmastimeSwitch.postUpdate(OFF)
        }
end