Simple Python script that reads Google Calendar and updates OH items with event information

Hello!

Since I couldn’t make CalDAV Personal binding to work with Google Calendar, and, according to this post, there is a problem with CalDAV Personal binding in OH2, I’ve made a simple Python script that authenticates via OAuth2, and uses Google Calendar API to populate OH items with an event information.

First, you need to create OAuth2 credentials (https://console.developers.google.com), download credentials in JSON format and place it in CalSyncHAB folder (cloned or downloaded from a github). After installing Python (both 2.x and 3.x will work), you need to install following packages:

  1. python -m pip install --upgrade google-api-python-client
  2. python -m pip install configparser
  3. python -m pip install requests

In the CalSyncHAB.ini you need to set:

  1. Application name - name of the application that will ask for an authentication

  2. Scope - should not be changed

  3. CalendarId - ID of the calendar you want to retrieve information from (if you have only one calendar, “primary” keyword will suffice, if not, you have to use Calendar ID shown in the settings of that calendar)

  4. MaxEvents - maximal number of events retrieved (starting from current date and time)

  5. TimeZone - in format ±HH:mm

  6. ClientSecretFile - name of the OAuth2 credentials file in JSON format

  7. HostName - IP address or host name of the OH server

  8. Port - Port of the OH server (usually 8080)

  9. SSLConnection - Should be left as False (not used at the moment)

  10. Username - not used at the moment

  11. Password - not used at the moment

  12. ItemPrefix - prefix of the calendar items in OpenHAB - for example, if you use ItemPrefix Calendar_Google_Primary_ you should create following items:

    Calendar_Google_Primary_Event1_Summary (String)
    Calendar_Google_Primary_Event1_Location (String)
    Calendar_Google_Primary_Event1_Description (String)
    Calendar_Google_Primary_Event1_StartTime (DateTime)
    Calendar_Google_Primary_Event1_EndTime (DateTime)

If you’ve set MaxEvents to 5, you should have 5 sets of those items - for example Calendar_Google_Primary_Event1_Summary to Calendar_Google_Primary_Event5_Summary

After executing script for the first time (first time it should be done manually, not via OpenHAB), it will open Web Browser and ask you for a permission to access your calendar. You need to sign in to your Google account (if you aren’t signed in already) and press Allow button.

Then you can use rules to trigger this Python script via executeCommandLine on some specific time (cron expression) or via switch in UI. Finally, the script can be found here:

If this explanation sounds confusing, feel free to post your questions here, or open an issue on the github repository.

Best regards,
Davor

7 Likes

Great directions, thank you! Do you have any more directions on how to fire this or some examples of displaying the results?

1 Like

Hello!

I’m using Project Rotini as primary UI on my wall tablet, and it has calendar widget that uses standard OH items (description, location, start time and end time namely). I’ve also made standard OH sitemap frame, with all those items for the next 5 days, to use it in HABDroid and Basic UI. And I’m using executeCommandLine every hour to update those items.

Best regards,
Davor

Anybody else stop working recently?

2017-02-25 13:48:15.180 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event1_Summary' for the unknown item 'Calendar_Google_Home_Event1_Summary'.
2017-02-25 13:48:15.203 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event1_Summary' for the unknown item 'Calendar_Google_Home_Event1_Summary'.
2017-02-25 13:48:15.222 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event1_Location' for the unknown item 'Calendar_Google_Home_Event1_Location'.
2017-02-25 13:48:15.242 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event1_Location' for the unknown item 'Calendar_Google_Home_Event1_Location'.
2017-02-25 13:48:15.262 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event1_Description' for the unknown item 'Calendar_Google_Home_Event1_Description'.
2017-02-25 13:48:15.281 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event1_Description' for the unknown item 'Calendar_Google_Home_Event1_Description'.
2017-02-25 13:48:15.302 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event1_StartTime' for the unknown item 'Calendar_Google_Home_Event1_StartTime'.
2017-02-25 13:48:15.322 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event1_StartTime' for the unknown item 'Calendar_Google_Home_Event1_StartTime'.
2017-02-25 13:48:15.341 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event1_EndTime' for the unknown item 'Calendar_Google_Home_Event1_EndTime'.
2017-02-25 13:48:15.361 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event1_EndTime' for the unknown item 'Calendar_Google_Home_Event1_EndTime'.
2017-02-25 13:48:15.383 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event2_Summary' for the unknown item 'Calendar_Google_Home_Event2_Summary'.
2017-02-25 13:48:15.412 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event2_Summary' for the unknown item 'Calendar_Google_Home_Event2_Summary'.
2017-02-25 13:48:15.432 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event2_Location' for the unknown item 'Calendar_Google_Home_Event2_Location'.
2017-02-25 13:48:15.452 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event2_Location' for the unknown item 'Calendar_Google_Home_Event2_Location'.
2017-02-25 13:48:15.471 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event2_Description' for the unknown item 'Calendar_Google_Home_Event2_Description'.
2017-02-25 13:48:15.491 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event2_Description' for the unknown item 'Calendar_Google_Home_Event2_Description'.
2017-02-25 13:48:15.511 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event2_StartTime' for the unknown item 'Calendar_Google_Home_Event2_StartTime'.
2017-02-25 13:48:15.532 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event2_StartTime' for the unknown item 'Calendar_Google_Home_Event2_StartTime'.
2017-02-25 13:48:15.553 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event2_EndTime' for the unknown item 'Calendar_Google_Home_Event2_EndTime'.
2017-02-25 13:48:15.573 [INFO ] [thome.io.rest.core.item.ItemResource] - Received HTTP POST request at 'items/Calendar_Google_Home_Event2_EndTime' for the unknown item 'Calendar_Google_Home_Event2_EndTime'.

Hello!

I’ve just tried adding a new event, and it shows up correctly. Are you sure you haven’t changed anything?

Best regards,
Davor

I didn’t change the code, but I was trying to install a Kodi add-on and had
to install Python 2.7 which is likely my issue.

Hello!

This looks like a problem with OH rather than the problem with Python/Script. Script does trigger HTTP POST, but OpenHAB shows an error. Check OH calendar item names and item prefix in CalSyncHAB.ini.

Best regards,
Davor

Thanks, I’m pretty sure I did and they both look good, is there a log I can
check somewhere?

Hello!

Since it looks like the OH error, you can check openhab.log and events.log. It seems to me that it happens after Python script execution. Could you post part of your .items file that is used for the calendar, and CalSyncHAB.ini (without sensitive information, of course). Have you changed settings on Google Calendar (allowing of less secure applications, calendar name)?

Best regards,
Davor

No Permission changes with the calendar.

String     Calendar_Google_Home_Event1_Location 
String     Calendar_Google_Home_Event1_Description 
DateTime   Calendar_Google_Home_Event1_StartTime 
DateTime   Calendar_Google_Home_Event1_EndTime

[General]
ApplicationName: Chewy_Creds

[Calendar]
Scope: https://www.googleapis.com/auth/calendar.readonly
CalendarId: email@gmail.com
MaxEvents: 5
TimeZone: -05:00
ClientSecretFile: OH2Auth.json

[OpenHAB]
HostName: 192.168.1.50
Port: 8080
ItemPrefix: Calendar_Google_Home_

I fixed it by cutting the items and moving them to the top of the .items file. It must have just been corrupt.

Hello!

Glad you made it work. I’ve had a similar problem with my .rules file. Some hidden character found its way in, and made a mess of the rules.

Best regards,
Davor

1 Like

Thanks for the help.

1 Like

Hello!

I’ve updated CalSyncHAB script, and I would suggest anyone using it to get the newest version. There was a bug that would, occasionally, show some events as blank. This would happen in case of slow OH server response. POST request for removal of an old value would be sent to the OH server REST API first. After that, POST request with a new value would follow. In case that first POST request gets delay, update with a new value would happen first, and after that, delayed removal would occur. This is solved in the new version by separating removal of old values from update of a new ones and 2 seconds delay between those two.

Best regards,
Davor

Hi,
can you guide me how to

and also how to

What do I need to do within google console? Do I need to create a new project? If so, what kind of?
There was an “API Project api-project-xxxxxxxxxxxx” already and I created “Browser key 1” and Browser key 2" for this one, but now I am completely stuck. Thanks in advance.

Sorry for another question:

leads to: "/usr/bin/python: cannot import name IncompleteRead; ‘pip’ is a package and cannot be directly executed"
same result with sudo

My python version is 2.7.9

EDIT: I found: sudo pip install --upgrade google-api-python-client
but this leads to:

Traceback (most recent call last):
  File "/usr/bin/pip", line 9, in <module>
    load_entry_point('pip==1.5.6', 'console_scripts', 'pip')()
  File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 356, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 2476, in load_entry_point
    return ep.load()
  File "/usr/lib/python2.7/dist-packages/pkg_resources.py", line 2190, in load
    ['__name__'])
  File "/usr/lib/python2.7/dist-packages/pip/__init__.py", line 74, in <module>
    from pip.vcs import git, mercurial, subversion, bazaar  # noqa
  File "/usr/lib/python2.7/dist-packages/pip/vcs/mercurial.py", line 9, in <module>
    from pip.download import path_to_url
  File "/usr/lib/python2.7/dist-packages/pip/download.py", line 25, in <module>
    from requests.compat import IncompleteRead
ImportError: cannot import name IncompleteRead

Hello!

Firstly, go to https://console.developers.google.com/apis, and then choose Credentials on the menu (located on the left side of the screen). After that, press the blue button “Create credentials” located below the page title, and choose “OAuth client ID”. Select “Other” as application type, fill in “Name” field, and press “Create” button. It will show your “Client ID” and “Client secret” in a pop-up window. After closing this pop-up, you can download JSON credentials file by pressing Download JSON button located on the right side (it looks like download button on dropbox, google drive, etc).

Regarding your second post, I really can’t help you. I’m using Python on a Windows machine, and I don’t have access to any Linux at the moment.

Best regards,
Davor

@davorf: great job, thanks. I could just download the json file easily with your explanation.

I will work my way through python pip and post here how it has to be done.

In some python versions there seems to be a problem with pip which is descibed here.

I found out howto workaround these problems in my openhabianpi:

sudo easy_install --upgrade pip

Later all the command posted by @davorf worked with sudo:

sudo python -m pip install --upgrade google-api-python-client
sudo python -m pip install configparser
sudo python -m pip install requests

2 Likes

Now I am facing the next problem. While not having a webserver running on my rpi I executed

python CalSyncHAB.py --noauth_local_webserver

and entered my google account password when I was asked "Enter verification code:"
But all the time I only receive: “Authentication has failed: invalid_grant” though there was no typo in my password.
After the third attempt everything seems to be locked as I received: “Authentication has failed: invalid_grantCode was already redeemed.”

What have I done wrong?