Hello Rich, thanks for your questions :
Are docs being written?
No, I completely dropped this point as I had troubles with getting a functional IDE (seems solved now). And now, I’m a bit lazy to come back on this. So I think our exchanges will be a good base to start this long awaited documentation. And you’re more than welcome to help 
In PaperUI I can choose country and state but it’s not clear that it does anything
The country select the default official holiday list used by Ephemeris. In some countries there exists local state/region related holidays. Germany comes to my mind, maybe US also ?
I tried to use the offset to get to the next holiday but it returned None.
The offset meand today + or - offset days. So if you use +1 and tomorrow is not an holiday, you’ll get None. But it could be an added feature to get ‘NextHoliday’ what/when.
where does it get the list of holidays from?
Ephemeris is built on Jollyday package, list of holidays are contained in this library for many countries over the world.
Is the recommended place to put the xml files as you have it in your example, $OH_CONF/db? Are users expected to write these (as hinted at by the anniversary file in your example)?
From scratch, Ephemeris does not need any added XML file. I decided to use a $OH_CONF/db to centralize some of my personnal data used by OH2 (XMLTV, Ephemeris…) but user defined Holiday files can be placed anywhere.
Is there a way to define specific days like holidays in the cfg file or is that done limited to days of the week?
Depends.
In the cfg, minimum definition based on days of the week is weekend. This is handled by PaperUI configuration. You can define personal sets at any time like this :
dayset-trash=Monday,Friday
and query it this way (JSR223 exemple) :
trashTomorrow = Ephemeris.isInDayset("trash",1)
If one need more complex than day of the week definitions, you’ll have to go to an XML file using Jolliday XML syntax as presented here.
One important thing while defining XML files : they are cached in memory at first load, avoiding cost of loading, parsing the file. Counterpart is that changes in XML need a start/stop of the module (or OH itself) to become effective.
Is there a UI planned to define holidays? Is it planned for PaperUI it only for it’s replacement?
I have no UI planned on my side as I can cope with XML. I do not know what’s planned for PaperUI replacement. There exists an XSD definition of the XML syntax, so I suppose an UI could (should for sake of end users) be defined but this is not my specialty.
can I mix Fixed and FixedWeekday the same xml file?
From what I see in the XML description linked above, yes.
does this only support querying from Rules or does it now or is planned to in there future generate events that can trigger Rules?
Good point. Currently only queries from Rules, we could imagine having this triggering events but it was out of the scope of my PR.
Currently, I’m using it to populate an array of elements, initialized in the morning this way :
@rule("Cron : Petit resume du jour")
@when("Time cron 0 10 7 ? * * *")
def cron_resume_du_jour(event):
cron_resume_du_jour.log.debug(u"Lance le résumé du jour")
for key in dayEvents:
dayEvents[key] = None
for i in [0,1]:
ferie = Ephemeris.getBankHolidayName(i)
dayEvents[(dayEventKind.ferie,i)] = None if ferie is None else u"C'est férié : {}".format(ferie)
school = Ephemeris.isInDayset("school",i)
dayEvents[(dayEventKind.school,i)] = "Repos" if not school else "Ecole !!!"
event = Ephemeris.getBankHolidayName(0,"/etc/openhab2/db/events.xml")
dayEvents[(dayEventKind.event,i)] = None if event is None else u"C'est {}".format(event)
birthday = Ephemeris.getBankHolidayName(i,"/etc/openhab2/db/birthdays.xml")
dayEvents[(dayEventKind.birthday,i)] = None if birthday is None else u"C'est l'anniversaire de {}".format(birthday)
sotd = Ephemeris.getBankHolidayName(i,"/etc/openhab2/db/sotd.xml")
dayEvents[(dayEventKind.sotd,i)] = None if sotd is None else u"C'est la saint {}".format(sotd)
dayEvents[(dayEventKind.trash,i)] = Ephemeris.getBankHolidayName(i,"/etc/openhab2/db/poubelles.xml")
currentVacances = items["currentVacances"]
if not isinstance(currentVacances,UnDefType):
dayEvents[(dayEventKind.school,0)] = currentVacances.toString()
cron_resume_du_jour.log.debug(repr(dayEvents).decode("unicode-escape"))
with this placed in configuration.py :
from enum import Enum
class dayEventKind(Enum):
trash = 1
school = 2
worked = 4
ferie = 5
holiday = 6
event = 7
birthday = 8
sotd = 9
dayEvents = {
(dayEventKind.trash,0) : None,
(dayEventKind.trash,1) : None,
(dayEventKind.school,0) : None,
(dayEventKind.school,1) : None,
(dayEventKind.worked,0) : None,
(dayEventKind.worked,1) : None,
(dayEventKind.ferie,0) : None,
(dayEventKind.ferie,1) : None,
(dayEventKind.event,0) : None,
(dayEventKind.event,1) : None,
(dayEventKind.birthday,0) : None,
(dayEventKind.birthday,1) : None,
(dayEventKind.sotd,0) : None,
(dayEventKind.sotd,1) : None,
(dayEventKind.holiday,0) : None,
(dayEventKind.holiday,1) : None
}
This is a work in progress, maybe it can give you ideas for your DP.