[Solved] Show Google Calendar Events in HabPanel/Sitemap - CalDav Personal - Openhab 2.4

Hey guys,

I have been trying to set up Caldav binding all morning. I have read 20 or so forum posts, followed what examples I can find but to no avail. Can anyone point me in the right direction on how to do the following:

Show upcoming events and times from a google calendar in Habpanel/Sitemap

Seems like it should be fairly simple, but I just can’t figure it out…

Thanks in advance for any help.



I have just finished my setup with a lot of great help from @Celaeno1.
It would be good if you post the configuration files, items and logfiles so people can actually see what you have configured.

You can check my latest posts and the replies from Alex…there is a huge amount of useful information in that conversation!


1 Like

So I figured it out after a long time of twiddling around. I will post results for anyone who is interested in setting this up too.

  1. Install the Caldav Personal binding & the Caldav Command Binding in Paper UI (You Need Both)

  2. Navigate to the services folder in Openhab/conf/services

  3. There should be 3 Caldav Files there: caldavCommand.cfg, caldavPersonal.cfg and caldavio.cfg

  4. Get your google calendar ready to give caldav access.
    Because caldav needs to access the calendar as a “Less Secure App”, and 2 factor auth seems to make this who project a headache, I opted to create a new gmail account that has shared access to the calendar I want to use. I made a new gmail account, and shared the calendar with that gmail with the setting “See All Events And Details”. You can find this in the sharing setting of the calendar page.

  5. Enable “Less Secure Apps” by logging into your new google account and visiting this URL: https://myaccount.google.com/u/2/lesssecureapps

  6. Now caldav should be able to access the calendar to download the entries.

  7. Get the name of the calendar you want to use from google from the calendar settings page:

  8. Go back to Openhab File System and add the following to the bottom of the caldavio.cfg file:

    caldavio:<Calendar Name In Google>:url=https://www.google.com/calendar/dav/<your username>@gmail.com/events
    caldavio:<Calendar Name In Google>:username=<gmail username without @gmail.com>
    caldavio:<Calendar Name In Google>:password=<password for gmail account>
    caldavio:<Calendar Name In Google>:reloadInterval=2
    caldavio:<Calendar Name In Google>:preloadTime=200000
    caldavio:<Calendar Name In Google>:disableCertificateVerification=true
  9. Add the following to the bottom of the caldavPersonal.cfg file

    caldavPersonal:usedCalendars=<Calendar Name In Google>
  10. leave the caldavCommand.cfg as is

  11. Set up your Items File. Mine is pulling the next 5 events with Name, Start Time, End Time, and Location. Note where it says caldavPersonal=“calendar:Matt” replace Matt with the name of your calendar as above:

        String CalendarName1   "Up Next [%s]"                                                   <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:1 value:NAME" } 
        DateTime CalendarTimeStart1 "Starts [%1$ta, %1$te %1$tb %1$tl:%1$tM%1$tp]"              <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:1 value:START" } 
        DateTime CalendarTimeEnd1 "Ends [%1$ta, %1$te %1$tb %1$tl:%1$tM%1$tp]"                  <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:1 value:END" }
        String CalendarAt1 "At [%s]"                                                            <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:1 value:PLACE" } 
        String CalendarName2   "Coming up [%s]"                                                 <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:2 value:NAME" } 
        DateTime CalendarTimeStart2 "Starts [%1$ta, %1$te %1$tb %1$tl:%1$tM%1$tp]"              <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:2 value:START" } 
        DateTime CalendarTimeEnd2 "Ends [%1$ta, %1$te %1$tb %1$tl:%1$tM%1$tp]"                  <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:2 value:END" }
        String CalendarAt2 "At [%s]"                                                            <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:2 value:PLACE" } 
        String CalendarName3   "Later  [%s]"                                                    <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:3 value:NAME" } 
        DateTime CalendarTimeStart3 "Starts [%1$ta, %1$te %1$tb %1$tl:%1$tM%1$tp]"              <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:3 value:START" } 
        DateTime CalendarTimeEnd3 "Ends [%1$ta, %1$te %1$tb %1$tl:%1$tM%1$tp]"                  <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:3 value:END" }
        String CalendarAt3 "At [%s]"                                                            <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:3 value:PLACE" } 
        String CalendarName4   "Later [%s]"                                                     <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:4 value:NAME" } 
        DateTime CalendarTimeStart4 "Starts [%1$ta, %1$te %1$tb %1$tl:%1$tM%1$tp]"              <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:4 value:START" } 
        DateTime CalendarTimeEnd4 "Ends [%1$ta, %1$te %1$tb %1$tl:%1$tM%1$tp]"                  <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:4 value:END" }
        String CalendarAt4 "At [%s]"                                                            <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:4 value:PLACE" } 
        String CalendarName5   "Later [%s]"                                                     <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:5 value:NAME" } 
        DateTime CalendarTimeStart5 "Starts [%1$ta, %1$te %1$tb %1$tl:%1$tM%1$tp]"              <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:5 value:START" } 
        DateTime CalendarTimeEnd5 "Ends [%1$ta, %1$te %1$tb %1$tl:%1$tM%1$tp]"                  <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:5 value:END" }
        String CalendarAt5 "At [%s]"                                                            <calendar>  { caldavPersonal="calendar:Matt type:EVENT eventNr:5 value:PLACE" } 
  12. Save all the changes to files and you should see the following message in the openhab.logs:
    CalDAV IO is properly configured.
    CalDav Loader has been started
    reload job scheduled for:

  13. Now caldav is successfully pulling your calendar entries.

  14. Depending on your application you can now implement into a sitemap or habpanel.
    For those who are interested this is the widget code I made to display mine as I didnt like the other widgets I found out there:

        tbody.calbody {
            height: 101%;
            display: block;
            position: absolute;
            width: 100%;
        table.caltable.ng-scope {
            width: 101%;
        td.calcal {
            background-color: #a9a9a9;
            padding: 17px;
            vertical-align: middle;
            width: 32%;
            text-align: center;
            height: 100%;
        td.calinfo {
            padding-top: 13px;
            width: 78%;
            vertical-align: top;
            padding-left: 16px;
        .calday.ng-binding {
            padding-bottom: 0px !important;
            color: #4c4c4c;
        .calmonth.ng-binding {
            padding-bottom: 0px;
            color: #212121;
        .caldaynumber.ng-binding {
            font-size: 30px;
            line-height: 30px;
            color: #212121;
        .calname.ng-binding {
            padding-bottom: 3px;
            font-size: 20px;
            font-weight: 400;
            line-height: 20px;
        .calduration.ng-binding {
            padding-bottom: 0px;
        .calloc.ng-binding {
            padding-bottom: 0px;
        tr.calentry {
            border-bottom: 5px solid #333333;
            height: 33.333%;
            width: 100%;
            max-width: 100%;
            display: flex;
            position: relative;
        <table class="caltable">
            <tbody class="calbody">
                        <tr class="calentry">
                            <td class="calcal">
                                <div class="calday">{{itemValue('CalendarTimeStart1')| date:"EEE"}}</div>
                                <div class="calmonth">{{itemValue('CalendarTimeStart1')| date:"MMM"}}</div>
                                <div class="caldaynumber">{{itemValue('CalendarTimeStart1')| date:"dd"}}</div>
                            <td class="calinfo"><div class="calname">{{itemValue('CalendarName1')}}</div>
                                <div ng-if="((itemValue('CalendarTimeStart1') | date:'dd.MM.yyyy') < (itemValue('CalendarTimeEnd1') | date:'dd.MM.yyyy'))" class="calduration">All Day</div>
                                <div ng-if="((itemValue('CalendarTimeStart1') | date:'dd.MM.yyyy') == (itemValue('CalendarTimeEnd1') | date:'dd.MM.yyyy'))" class="calduration">{{itemValue('CalendarTimeStart1')| date:"shortTime"}} - {{itemValue('CalendarTimeEnd1')| date:"shortTime"}}</div>
                                <div class="calloc">{{itemValue('CalendarAt1')}}</div>
                        <tr class="calentry">
                            <td class="calcal">
                                <div class="calday">{{itemValue('CalendarTimeStart2')| date:"EEE"}}</div>
                                <div class="calmonth">{{itemValue('CalendarTimeStart2')| date:"MMM"}}</div>
                                <div class="caldaynumber">{{itemValue('CalendarTimeStart2')| date:"dd"}}</div>
                            <td class="calinfo"><div class="calname">{{itemValue('CalendarName2')}}</div>
                                <div ng-if="((itemValue('CalendarTimeStart2') | date:'dd.MM.yyyy') < (itemValue('CalendarTimeEnd2') | date:'dd.MM.yyyy'))" class="calduration">All Day</div>
                                <div ng-if="((itemValue('CalendarTimeStart2') | date:'dd.MM.yyyy') == (itemValue('CalendarTimeEnd2') | date:'dd.MM.yyyy'))" class="calduration">{{itemValue('CalendarTimeStart2')| date:"shortTime"}} - {{itemValue('CalendarTimeEnd2')| date:"shortTime"}}</div>
                                <div class="calloc">{{itemValue('CalendarAt2')}}</div>
                        <tr class="calentry">
                            <td class="calcal">
                                <div class="calday">{{itemValue('CalendarTimeStart3')| date:"EEE"}}</div>
                                <div class="calmonth">{{itemValue('CalendarTimeStart3')| date:"MMM"}}</div>
                                <div class="caldaynumber">{{itemValue('CalendarTimeStart3')| date:"dd"}}</div>
                            <td class="calinfo"><div class="calname">{{itemValue('CalendarName3')}}</div>
                                <div ng-if="((itemValue('CalendarTimeStart3') | date:'dd.MM.yyyy') < (itemValue('CalendarTimeEnd3') | date:'dd.MM.yyyy'))" class="calduration">All Day</div>
                                <div ng-if="((itemValue('CalendarTimeStart3') | date:'dd.MM.yyyy') == (itemValue('CalendarTimeEnd3') | date:'dd.MM.yyyy'))" class="calduration">{{itemValue('CalendarTimeStart3')| date:"shortTime"}} - {{itemValue('CalendarTimeEnd3')| date:"shortTime"}}</div>
                                <div class="calloc">{{itemValue('CalendarAt3')}}</div>

Which renders out like this:

And that’s it.

It looks more complicated than it is, so I hope this guide helps anyone out there looking to do the same.


I’m a noob…have a ton figured out, but displaying it all is one of my last TODO items… I like your display. Is this a screenshot from Habpanel or Sitemap? (This may sound like a stupid question but once I think mine is cool…then I see people’s that are a million times better, and did things I didn’t know was possible :slight_smile:)

Mind posting your code/config file?! (I see you posted code, but where does that go, etc, or entire file?)

Thanks for the steps. I’ll give them a try!

I see these bindings caldav-cmd are version 1…Is there a version 2 equivalent for openhab 2.5+? (Or an alternative binding or method we should be using to get calendar events?)

I’m fairly certain I followed these steps verbatim, except the obvious changes like username, pw, calendar name. ‘’’‘Any chance any of these variables or configs changed, like the calendar event url?’’’’ I’m getting a successful connection in the logs, but I’m not getting any events or updates. Also, I do have openhab 2.5.1 Thanks!

You should start a new thread for discussing your problems.

I’ve been getting in so much trouble already for starting threads…I fear it’s just an ID10T error! You don’t think my post is relevant to this? (Yes I’m serious and really looking for input). Appreciate the comment and thank you!

This URL in /services/caldavio.cfg specifically:

I’m getting a 404 in the openhab logs. Perhaps this URL changed? (When I pull that URL up in a browser I get a login, but then it leads to: “Not found”)

I’m not sure if the method here is the equivalent, but it does indicate this URL is actually deprecated! (red font at bottom)

It’s for habpanel yeah. The code goes in habpanel inside the template widget.

I am not sure about using on openhab 2.5 I am still on 2.4.

To check if the URL is working paste it into a browser, and try logging in with your credentials. If it works it will download a file of calendar entries.

I had an issue with mine it would just keep asking for me to login, it was Google checking it was ok for this new device to log in. I tried just logging into Google, then verifying the device with the email that said something like “is this you logging in?”

Then I checked the url again inna private window, and it worked and downloaded the entries. Then restated openhab and voila.

Good.luck, this can be a pain for sure.

Thanks!! Worked for me even if you are not using “Gmail calendar name”.

I’ve followed the steps above to configure my google calendar and the Caldav files but it is not working for me. I keep getting the same error in the logs.

 2020-08-10 22:00:59.753 [WARN ] [caldav.internal.job.EventReloaderJob] - Sardine error while loading calendar entries: Unexpected response (401 - Unauthorized) com.github.sardine.impl.SardineException: Unexpected response

at com.github.sardine.impl.handler.ValidatingResponseHandler.validateResponse(ValidatingResponseHandler.java:48) ~[sardine-5.6.jar:5.6]

at com.github.sardine.impl.handler.MultiStatusResponseHandler.handleResponse(MultiStatusResponseHandler.java:40) ~[sardine-5.6.jar:5.6]

at com.github.sardine.impl.handler.MultiStatusResponseHandler.handleResponse(MultiStatusResponseHandler.java:35) ~[sardine-5.6.jar:5.6]

at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:222) ~[httpclient-4.4.1.jar:4.4.1]

at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:164) ~[httpclient-4.4.1.jar:4.4.1]

at com.github.sardine.impl.SardineImpl.execute(SardineImpl.java:962) ~[sardine-5.6.jar:5.6]

at com.github.sardine.impl.SardineImpl.list(SardineImpl.java:417) ~[sardine-5.6.jar:5.6]

at com.github.sardine.impl.SardineImpl.list(SardineImpl.java:409) ~[sardine-5.6.jar:5.6]

at com.github.sardine.impl.SardineImpl.list(SardineImpl.java:386) ~[sardine-5.6.jar:5.6]

at org.openhab.io.caldav.internal.job.EventReloaderJob.loadEvents(EventReloaderJob.java:250) ~[bundleFile:?]

at org.openhab.io.caldav.internal.job.EventReloaderJob.execute(EventReloaderJob.java:141) [bundleFile:?]

at org.quartz.core.JobRunShell.run(JobRunShell.java:202) [bundleFile:?]

at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [bundleFile:?]

First I thought it had something to do with my credentials but when i connect withthese credentials via a web browser it works fine.

I have no idea what the error means. I am still new to openhab and have a lot to learn.

did you resolve your access?
I have problem to access my account “new” way google specifies:
Log file is telling me:

2020-10-16 14:24:14.135 [WARN ] [.io.caldav.internal.CalDavLoaderImpl] - A URL must be configured for calendar 'caldavPersonal
2020-10-16 14:24:14.137 [ERROR] [org.apache.felix.configadmin        ] - [org.osgi.service.cm.ManagedService, org.openhab.io.caldav.CalDavLoader, id=129, bundle=251/mvn:org.openhab.io/org.openhab.io.caldav/[1.14.0,1.15)]: Updating property CalDAV IO of configuration org.openhab.caldavio caused a problem: A URL must be configured for calendar 'caldavPersonal'
org.osgi.service.cm.ConfigurationException: CalDAV IO : A URL must be configured for calendar 'caldavPersonal'`


caldavio:Garbage:username=<my google login without @gmail.com>


caldavCommand.cfg -> no entry

I am getting crazy with google account settings.
I have created new calendar in google. Named it Garbage and made it available to all

Tried several links to access the calendar.
The latest caldavio.cfg looks like that:


and placing the link in the browser, giving creditals seems to be worlking

My DEBUG and TRACE is telling me there is no calendas named “Garbage” but there is…

2020-10-16 16:37:57.136 [DEBUG] [.io.caldav.internal.CalDavLoaderImpl] - Update was called for CalDAV IO.
-> 2020-10-16 16:37:57.140 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - processing configuration parameter: <Garbage>:disableCertificateVerification
-> 2020-10-16 16:37:57.143 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - processing configuration parameter: <Garbage>:password
-> 2020-10-16 16:37:57.146 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - processing configuration parameter: <Garbage>:preloadTime
-> 2020-10-16 16:37:57.150 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - processing configuration parameter: <Garbage>:reloadInterval
-> 2020-10-16 16:37:57.153 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - processing configuration parameter: <Garbage>:url
-> 2020-10-16 16:37:57.157 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - processing configuration parameter: <Garbage>:username
2020-10-16 16:37:57.159 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - processing configuration parameter: caldavPersonal:usedCalendars
2020-10-16 16:37:57.163 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - processing configuration parameter: Garbage:charset
2020-10-16 16:37:57.166 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - processing configuration parameter: Garbage:disableCertificateVerification
2020-10-16 16:37:57.170 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - processing configuration parameter: Garbage:lastModifiedFileTimeStampValid
2020-10-16 16:37:57.172 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - processing configuration parameter: Garbage:password
2020-10-16 16:37:57.174 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - processing configuration parameter: Garbage:preloadTime
2020-10-16 16:37:57.176 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - processing configuration parameter: Garbage:reloadInterval
2020-10-16 16:37:57.178 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - processing configuration parameter: Garbage:timeZone
2020-10-16 16:37:57.179 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - processing configuration parameter: Garbage:url
2020-10-16 16:37:57.182 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - processing configuration parameter: Garbage:username
-> 2020-10-16 16:37:57.183 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - config for calendar '<Garbage>': CalDavConfig [key=<Garbage>, username=<my_preious_google_login>, url=https://www.google.com/calendar/dav/<my_previous_google_account>@gmail.com/events, reloadMinutes=2, preloadMinutes=200000, disableCertificateVerification=true, lastModifiedFileTimeStampValid=true]
2020-10-16 16:37:57.186 [TRACE] [.io.caldav.internal.CalDavLoaderImpl] - config for calendar 'Garbage': CalDavConfig [key=Garbage, username=<my_google_urename>, url=https://calendar.google.com/calendar/dav/<my_google_account>@gmail.com/events, reloadMinutes=2, preloadMinutes=18720, disableCertificateVerification=true, lastModifiedFileTimeStampValid=false]
2020-10-16 16:37:57.187 [WARN ] [.io.caldav.internal.CalDavLoaderImpl] - A URL must be configured for calendar 'caldavPersonal'
2020-10-16 16:37:57.190 [ERROR] [org.apache.felix.configadmin        ] - [org.osgi.service.cm.ManagedService, org.openhab.io.caldav.CalDavLoader, id=130, bundle=251/mvn:org.openhab.io/org.openhab.io.caldav/[1.14.0,1.15)]: Updating property CalDAV IO of configuration org.openhab.caldavio caused a problem: A URL must be configured for calendar 'caldavPersonal'

Have no idea why do I have in the log my previous configuration I played with (Marked with -> in the log file.
Maybe this is the reason for the problem?
Ps. Reboot done few times after configuration changes.

Hi @Matt_Foreman, I am currently adapting your calendar idea to iCal binding for me to work in OH3.
I wonder about our CSS config. Would you mind sharing it? I really like the grey and neat design from the screenshot.

Cheers and happy holidays :wink:

Hey, yeah I did share it. It’s all above.

Dis you enable less secure apps?

Yeah I pasted your css in a blank template but it’s not yet quite the same so wondered if you have other CSS settings?

Ahh, yeah I kinda did somewhat dirty css that was for my specific use case. You should be able to tweak it if you have a larger display. You can also add more entries and tweak the css if you need too.