CalDav Binding to Read Holidays Calendar?

@vzorglub Vincent, et. al.

I saw that you use CalDav with Google Calendar. I was finally able to get mine configured to read a Calendar I created for openHAB.

One can subscribe to many different types of calendars in Google Calendar (Sports, Teams, astrological, etc.). There are also several holidays Calendars (e.g., US Holidays, US Federal Holidays, etc.). Do you know if it is possible to use the CalDav bindings to connect to a subscribed Holidays Calendar to check whether a particular day (e.g., today or tomorrow) is a holiday?

Thanks.

Mike

I know the answer, and it is not possible unfortunately as far as I know.
I have copied the holidays onto my calendar…

Thanks Vincent. I’d put a tentative task on my Calendar for today surmising that would be the answer: “Import Holidays” :frowning:

If I could impose further… Do you stilljust use CalDavCommand? Could you provide an example of one of your calendar holiday entries?

I can see how the Command can trigger to set that a holiday has begun. I suppose one could configure a holiday entry to “turn on early” to have openHAB “see” the upcoming holiday. But I’m going to play around with the Personal binding to try to “see ahead” for upcoming holidays because I need the day transitions for my HVAC schedule to take holidays vs. workdays into account.

Mike

You might find this useful. Not sure where I picked it up … . Cudos are with someone else …

item file

Switch Holiday					"Feiertag [MAP(holiday.map):%s]"
String SpecialDay				"Feiertag [MAP(holiday.map):%s]"
Switch SchoolVacation			"Schulferien [MAP(holiday.map):%s]"
String SchoolVacationName		"Schulferien [MAP(holiday.map):%s]"

rule file

var int year = now.getYear
var int dayOfYear = now.getDayOfYear

var int a = year % 19
var int b = year / 100
var int c = year % 100
var int d = b / 4;
var int e = b % 4;
var int f = (b + 8) / 25;
var int g = (b - f + 1) / 3;
var int h = (19 * a + b - d - g + 15) % 30;
var int i = c / 4;
var int k = c % 4;
var int L = (32 + 2 * e + 2 * i - h - k) % 7;
var int m = (a + 11 * h + 22 * L) / 451;

var int month = (h + L - 7 * m + 114) / 31;
var int day = ((h + L - 7 * m + 114) % 31) + 1;

var boolean holiday = false
var String holidayName = null

var org.joda.time.DateTime easterSunday = parse(year+"-"+month+"-"+day)
var org.joda.time.DateTime stAdvent = parse(year+"-12-25").minusDays(((parse(year+"-12-25").getDayOfWeek) + 21))

holidayName = null

// bundesweiter Feiertag
if (dayOfYear==parse(year+"-01-01").getDayOfYear) {
    holidayName = "new_years_day" // Neujahr
    holiday = true
}
// Baden-Württemberg, Bayern, Sachsen-Anhalt
else if (dayOfYear==parse(year+"-01-06").getDayOfYear) {
    holidayName = "holy_trinity"// Heilige 3 Könige
    holiday = false 
}
// Carnival ;-)
else if (dayOfYear==easterSunday.getDayOfYear-48) {
    holidayName = "carnival_monday" // Rosenmontag
    holiday = true
}
// bundesweiter Feiertag
else if (dayOfYear==easterSunday.getDayOfYear-2) {
    holidayName = "good_friday" // Karfreitag
    holiday = true
}
// Brandenburg
else if (dayOfYear==easterSunday.getDayOfYear) {
    holidayName = "easter_sunday" // Ostersonntag
    holiday = false
}
// bundesweiter Feiertag
else if (dayOfYear==easterSunday.getDayOfYear+1) {
    holidayName = "easter_monday" // Ostermontag
    holiday = true
}
// bundesweiter Feiertag
else if (dayOfYear==parse(year+"-05-01").getDayOfYear) {
    holidayName = "1st_may"// Tag der Arbeit
    holiday = true 
}
// bundesweiter Feiertag
else if (dayOfYear==easterSunday.getDayOfYear+39) {
    holidayName = "ascension_day" // Christi Himmelfahrt
    holiday = true
}
// Brandenburg
else if (dayOfYear==easterSunday.getDayOfYear+49) {
    holidayName = "whit_sunday" // Pfingstsonntag
    holiday = false
}
// bundesweiter Feiertag
else if (dayOfYear==easterSunday.getDayOfYear+50) {
    holidayName = "whit_monday" // Pfingstmontag
    holiday = true
}
// Baden-Württemberg, Bayern, Hessen, NRW, Rheinland-Pfalz, Saarland sowie regional in Sachsen, Thüringen
else if (dayOfYear==easterSunday.getDayOfYear+60) {
    holidayName = "corpus_christi" // Frohnleichnahm
    holiday = true
}
// Saarland sowie regional in Bayern
else if (dayOfYear==parse(year+"-08-15").getDayOfYear) {
    holidayName = "assumption_day" // Mariä Himmelfahrt
    holiday = false
}
// bundesweiter Feiertag
else if (dayOfYear==parse(year+"-10-03").getDayOfYear) {
    holidayName = "reunification" // Tag der deutschen Einheit
    holiday = true
}
// Brandenburg, Mecklenburg-Vorpommern, Sachsen, Sachsen-Anhalt, Thüringen
else if (dayOfYear==parse(year+"-10-31").getDayOfYear) {
    holidayName = "reformation_day" // Reformationstag
    holiday = false
}
// Baden-Württemberg, Bayern, NRW, Rheinland-Pfalz, Saarland
else if (dayOfYear==parse(year+"-11-01").getDayOfYear) {
    holidayName = "all_saints_day" // Allerheiligen
    holiday = true
}
// religiöser Tag
else if (dayOfYear==stAdvent.getDayOfYear-14) {
    holidayName = "remembrance_day" // Volkstrauertag
    holiday = false
}
// religiöser Tag
else if (dayOfYear==stAdvent.getDayOfYear-7) {
    holidayName = "sunday_in_commemoration_of_the_dead" // Totensonntag
    holiday = false
}
// Sachsen
else if (dayOfYear==stAdvent.getDayOfYear-11) {
    holidayName = "day_of_repentance" // Buß- und Bettag
    holiday = false
}
// kann auch der 4te Advent sein
else if (dayOfYear==parse(year+"-12-24").getDayOfYear) {
    holidayName = "christmas_eve" // Heiligabend
    holiday = true
}
// bundesweiter Feiertag
else if (dayOfYear==parse(year+"-12-25").getDayOfYear) {
    holidayName = "1st_christmas_day" // 1. Weihnachtstag
    holiday = true
}
// bundesweiter Feiertag
else if (dayOfYear==parse(year+"-12-26").getDayOfYear) {
    holidayName = "2nd_christmas_day" // 2. Weihnachtstag
    holiday = true
}
// Silvester
else if (dayOfYear==parse(year+"-12-31").getDayOfYear) {
    holidayName = "new_years_eve" // Silvester
    holiday = true
}

var boolean schoolvac = false
var String schoolvacName = null

// NRW Daten von http://www.schulferien.org/NRW/nrw.html
if (year == 2019) {
	if (dayOfYear >=        parse(year+"-01-01").getDayOfYear && 
		dayOfYear <=        parse(year+"-01-04").getDayOfYear	) {
		schoolvacName = "Weihnachtsferien"
		schoolvac = true
	} else if (dayOfYear >= parse(year+"-04-15").getDayOfYear && 
		dayOfYear <=        parse(year+"-04-27").getDayOfYear	) {
		schoolvacName = "Osternferien"
		schoolvac = true
	} else if (dayOfYear == parse(year+"-06-11").getDayOfYear ) {
		schoolvacName = "Pfingstferien"
		schoolvac = true
	} else if (dayOfYear >= parse(year+"-07-15").getDayOfYear && 
		dayOfYear <=        parse(year+"-08-27").getDayOfYear	) {
		schoolvacName = "Sommerferien"
		schoolvac = true
	} else if (dayOfYear >= parse(year+"-10-14").getDayOfYear && 
		dayOfYear <=        parse(year+"-10-26").getDayOfYear	) {
		schoolvacName = "Herbstferien"
		schoolvac = true
	} else if (dayOfYear >= parse(year+"-12-23").getDayOfYear&& 
		dayOfYear <=        parse(year+"-12-31").getDayOfYear) {
		schoolvacName = "Weihnachtsferien"
		schoolvac = true
	}
}
if (year == 2020) {
	if (dayOfYear >=        parse(year+"-01-01").getDayOfYear && 
		dayOfYear <=        parse(year+"-01-06").getDayOfYear	) {
		schoolvacName = "Weihnachtsferien"
		schoolvac = true
	} else if (dayOfYear >= parse(year+"-04-06").getDayOfYear && 
		dayOfYear <=        parse(year+"-04-18").getDayOfYear	) {
		schoolvacName = "Osternferien"
		schoolvac = true
	} else if (dayOfYear == parse(year+"-06-02").getDayOfYear ) {
		schoolvacName = "Pfingstferien"
		schoolvac = true
	} else if (dayOfYear >= parse(year+"-06-29").getDayOfYear && 
		dayOfYear <=        parse(year+"-08-11").getDayOfYear	) {
		schoolvacName = "Sommerferien"
		schoolvac = true
	} else if (dayOfYear >= parse(year+"-10-12").getDayOfYear && 
		dayOfYear <=        parse(year+"-10-24").getDayOfYear	) {
		schoolvacName = "Herbstferien"
		schoolvac = true
	} else if (dayOfYear >= parse(year+"-12-23").getDayOfYear&& 
		dayOfYear <=        parse(year+"-12-31").getDayOfYear) {
		schoolvacName = "Weihnachtsferien"
		schoolvac = true
	}
}

if (year == 2021) {
	if (dayOfYear >=        parse(year+"-01-01").getDayOfYear && 
		dayOfYear <=        parse(year+"-01-06").getDayOfYear	) {
		schoolvacName = "Weihnachtsferien"
		schoolvac = true
	} else if (dayOfYear >= parse(year+"-03-29").getDayOfYear && 
		dayOfYear <=        parse(year+"-04-10").getDayOfYear	) {
		schoolvacName = "Osternferien"
		schoolvac = true
	} else if (dayOfYear == parse(year+"-05-25").getDayOfYear ) {
		schoolvacName = "Pfingstferien"
		schoolvac = true
	} else if (dayOfYear >= parse(year+"-07-05").getDayOfYear && 
		dayOfYear <=        parse(year+"-08-17").getDayOfYear	) {
		schoolvacName = "Sommerferien"
		schoolvac = true
	} else if (dayOfYear >= parse(year+"-10-11").getDayOfYear && 
		dayOfYear <=        parse(year+"-10-23").getDayOfYear	) {
		schoolvacName = "Herbstferien"
		schoolvac = true
	} else if (dayOfYear >= parse(year+"-12-24").getDayOfYear&& 
		dayOfYear <=        parse(year+"-12-31").getDayOfYear) {
		schoolvacName = "Weihnachtsferien"
		schoolvac = true
	}
}

if (year == 2022) {
	if (dayOfYear >=        parse(year+"-01-01").getDayOfYear && 
		dayOfYear <=        parse(year+"-01-08").getDayOfYear	) {
		schoolvacName = "Weihnachtsferien"
		schoolvac = true
	} else if (dayOfYear >= parse(year+"-04-11").getDayOfYear && 
		dayOfYear <=        parse(year+"-04-23").getDayOfYear	) {
		schoolvacName = "Osternferien"
		schoolvac = true
	// } else if (dayOfYear == parse(year+"-05-25").getDayOfYear ) {
	// 	schoolvacName = "Pfingstferien"
	// 	schoolvac = true
	} else if (dayOfYear >= parse(year+"-06-27").getDayOfYear && 
		dayOfYear <=        parse(year+"-08-09").getDayOfYear	) {
		schoolvacName = "Sommerferien"
		schoolvac = true
	} else if (dayOfYear >= parse(year+"-10-04").getDayOfYear && 
		dayOfYear <=        parse(year+"-10-15").getDayOfYear	) {
		schoolvacName = "Herbstferien"
		schoolvac = true
	} else if (dayOfYear >= parse(year+"-12-23").getDayOfYear&& 
		dayOfYear <=        parse(year+"-12-31").getDayOfYear) {
		schoolvacName = "Weihnachtsferien"
		schoolvac = true
	}
}

if (holidayName !== null) {
    sendCommand(SpecialDay,holidayName)
} else {
    sendCommand(SpecialDay,"")	
}
if (holiday) {
    sendCommand(Holiday,ON)
} else {
    sendCommand(Holiday,OFF)
}

if (schoolvacName !== null) {
    sendCommand(SchoolVacationName,schoolvacName)
} else {
    sendCommand(SchoolVacationName,"")	
}
if (schoolvac) {
    postUpdate(SchoolVacation,ON)
} else {
    postUpdate(SchoolVacation,OFF)
}

rule file

rule "Feiertage berechnen"
when
//    Item Test changed from OFF to ON or
    System started or
    Time cron "0 0 1 * * ?"
then
	logDebug("Holiday", "Script Calculation started")
    callScript("holiday")
end
1 Like

Thanks Ralf.

Is the first rule file the “holiday” script invoked by rule "Feiertage berechnen"?

Fo you have the holiday.map file as well?

I had not considered it, but I can probably calculate most of the other US holidays that don’t have a “fixed” day of a particular month:

  • New Year’s Day
  • Easter per the formula
  • Independence Day - July 4
  • Christmas Day
  • New Year’s Eve

The rest all have a “formula”:

  • MLK Day - third Monday of January
  • Presidents Day - third Monday in February
  • Memorial Day - last Monday of May
  • Labor Day - first Monday of September
  • Columbus Day - second Monday of October
  • Election Day (school holiday) - first Tuesday after November 1
  • Thanksgiving - fourth Thursday in November

Problem is, I don’t know how to code that to efficiently. I bet the logic is out there already. Just a matter of searching. What scares me is date data types and operations in openHAB DSL!

Mike

All of these can be get with a cron statement:
https://www.freeformatter.com/cron-expression-generator-quartz.html

  • MLK Day - third Monday of January: 1 0 0 ? JAN 2#3 *
  • Presidents Day - third Monday in February: 1 0 0 ? FEB 2#3 *
  • Memorial Day - last Monday of May: 1 0 0 ? MAY 2L *
  • Labor Day - first Monday of September: 1 0 0 ? SEP 2#1 *
  • Columbus Day - second Monday of October: 1 0 0 ? OCT 2#2 *

This case is special and you will need 2 cron and check if the day of the month is NOT the first
1 0 0 ? OCT 3#1 * or 1 0 0 ? OCT 3#2 *

  • Election Day (school holiday) - first Tuesday after November 1: ``
  • Thanksgiving - fourth Thursday in November
    [/quote]

These too except easter of course

New Year’s Day: `1 0 0 1 JAN ? *`
Easter per the formula
Independence Day - July 4 `1 0 0 4 JUL ? *`
Christmas Day `1 0 0 25 DEC ? *`
New Year’s Eve `1 0 0 31 DEC ? *`

For example MLK day: 1 0 0 ? JAN 2#3 *

Going back to caldav, I send a “day type” to the system. I have an item Holiday_Type that can the values NONE, BANK, SCHOOL. In Britain we call the special holidays BANK holidays
According to the value of the item, I set different heating schedules

Vincent,

Which one are you referring to - Columbus Day or Election Day?

I did not realize that cron was so versatile! I know that cron be used as Time cron xxxx in a Rule’s trigger. But that would require separate rules that fire at midnight of the particular holiday. Is there a DSL method that can be invoked with cron strings so I can get back an actaul date in a variable? I’d like to use them in a case or if statement to check against ‘today’ or ‘tomorrow’? If it’s DSL, then that’s ideal and I don’t have to maintain events in a calendar.

Mike

Election day because if the 1st is a Tuesday then the election day is the second

All these can be achieved in the DSL without cron

Holiday map is only the German Translation to show the German names in Sitemap. Like this:

whit_monday=Pfingstmontag

The cron syntax is brilliant, didn’t know. Thanks for sharing.

The Formulars like 2nd Tuesday in Jan can be calculate with the following structure

  • Calc Weekday (0-6; 0 being Sunday) of 1st January; let’s call it WD
  • calc difference to 1st Tuesday at or after Jan 1st in days like this
  • plus ((7 - WD + 2) modulo 7) in days gives you 1st Tuesday
  • adding another 7 days gives you 2nd Tuesday

You get the gist …

Thanks Vincent & Ralf!

Mike

remainder()

	var eastFasadeIn   = (  90 - 90 + diffToFasade )  //For example: -26.09 or 333,91 - because 0 and 360 is north
    Sun_Fasade_Illum_East.postUpdate(             if (azimut > eastFasadeIn.remainder(360.0BD)  && azimut < eastFasadeOut.remainder(360.0BD)  && height >0) ON else OFF)

No wonder I didn’t find documentation on mod, modulo, modulus!

I just also noticed your b % 4 syntax in the easter formula

Thanks

P.S. Curious - what is this syntax 360.0BD? Big Decimal?

Especially for holidays, it might be worthwhile to watch the progress of the “Ephemeris” service which exposes the data from the jollyday library to openHAB:

Of course this had to be a global need and someone has already provided a programmatic solution. I will definitely track the Ephemeris service.

Hopefully this comes along soon. I’d rather leverage a facility like this that provides lots of options… without lots of code to write or maintain. My holidays need is not critical… so I’ll be patient and wait for the Ephemeris service (binding or action) to be released.

Thanks.