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

So since i was running into serval problems to get this working… and to help others to not get lost in this thread i will add all the steps needed here… most of them is copy&paste from this thread… Thanks to all who helped here :slight_smile: @davorf @FrankR @Mike_Bagdanoff @ei_Gelb_Geek @binderth

I also added some small adjustments and code lines for my Telegram Bot, which notifies our house group… so more than one human keep an eye on the trash cans :wink:

GCal_tut_1GCal_tut_3GCal_tut_2

  1. Make sure you have already python installed…

  2. Upgrade pip:

sudo easy_install --upgrade pip
  • after that is finished, run:
sudo python -m pip install --upgrade google-api-python-client
sudo python -m pip install configparser
sudo python -m pip install requests
  1. Create OAuth2 credentials
  • go to https://console.developers.google.com/ and create a project named “OpenHAB” and create a new OAuth Client ID, Type: “others”
  • download this OAuth 2.0-Client-ID as JSON (and save it for later)
  • activate the Google Calandar API
  1. create a folder “CalSyncHAB” within /etc/openhab2/scripts
  • create folder
sudo mkdir /etc/openhab2/scripts/CalSyncHAB
sudo git clone http://github.com/davorf/CalSyncHAB.git .
  • rename your OAuth 2.0-Client-ID to “CalSyncHABSecret.json” and put it in under /etc/openhab2/scripts/CalSyncHAB
sudo chown openhab:openhabian /etc/openhab2/scripts/CalSyncHAB
  • cd into CalSyncHAB folder and
sudo chown openhab:openhabian *
  • open .ini file and for setting “ClientSecretFile” enter the complete path, e.g.
ClientSecretFile: /etc/openhab2/scripts/CalSyncHAB/CalSyncHABSecret.json
  • create a script “/etc/openhab2/scripts/CalSyncHAB.sh” with: (in my case i need to remove the first line to get the .sh running)
#!/bin/sh
/usr/bin/python /etc/openhab2/scripts/CalSyncHAB/CalSyncHAB.py --noauth_local_webserver
sudo chown openhab:openhabian /etc/openhab2/scripts/CalSyncHAB.sh
  • after that run the .sh copy the url shown by the script into your browser, click “Allow” and paste the given code back into the script prompt.
sudo -u openhab /etc/openhab2/scripts/CalSyncHAB.sh
  • if this was successfull, we can delete that .sh file (we can use the .py file in our rules)

OpenHAB File Examples:

  • /etc/openhab2/scripts/CalSyncHAB/CalSyncHAB.ini
[General]
ApplicationName: OpenHAB

[Calendar]
Scope: https://www.googleapis.com/auth/calendar.readonly
CalendarId: <YOUR_CALENDAR_ID>@group.calendar.google.com
MaxEvents: 5
TimeZone: +02:00
ClientSecretFile: /etc/openhab2/scripts/CalSyncHAB/CalSyncHABSecret.json

[OpenHAB]
HostName: <IP_OF_YOUR_OH>
Port: 8080
ItemPrefix: gCal_Abfall_
  • GoogleCal.items
//GoogleCalender
Group gCal_Abfall
Group gCal_Abfall_Event
Group:Switch:OR(ON, OFF) gCal_Abfall_Item "Müll-Abfuhr Termine morgen [(%d)]" <softener>
Group:Switch:OR(ON, OFF) gCal_Geburtstag_Item "Geburtstage morgen [(%d)]" <smiley>
String gCal_Abfall_Event1 (gCal_Abfall)
String gCal_Abfall_Event2 (gCal_Abfall)
String gCal_Abfall_Event3 (gCal_Abfall)

// your Google Cal Items need to match the item names!  
Switch GelberSack "GelberSack" (gCal_Abfall_Item)
Switch Biotonne "Biotonne" (gCal_Abfall_Item)
Switch Restmuell "Restmuell" (gCal_Abfall_Item)
Switch Papiertonne "Papiertonne" (gCal_Abfall_Item)

String gCal_Abfall_Event1_Summary "Mülltonne: [%s]" <calendar> (gCal_Abfall_Event)
String gCal_Abfall_Event1_Location "Event1 Loc.: [%s]" <calendar> (gCal_Abfall_Event)
String gCal_Abfall_Event1_Description "Event1 Desc. [%s]" <calendar> (gCal_Abfall_Event)
DateTime gCal_Abfall_Event1_StartTime  "Abholung: [%1$td.%1$tm.%1$tY]" <calendar> (gCal_Abfall_Event)
DateTime gCal_Abfall_Event1_EndTime "Event1 End [%1$td.%1$tm.%1$tY %1$tH:%1$tM]" <calendar> (gCal_Abfall_Event)
Switch gCal_Abfall_Event1_Approved "Mülltonne rausgestellt: [%s]" <calendar> (gCal_Abfall_Event)

String gCal_Abfall_Event2_Summary "Mülltonne: [%s]" <calendar> (gCal_Abfall_Event)
String gCal_Abfall_Event2_Location "Event2 Loc.: [%s]" <calendar> (gCal_Abfall_Event)
String gCal_Abfall_Event2_Description "Event2 Desc. [%s]" <calendar> (gCal_Abfall_Event)
DateTime gCal_Abfall_Event2_StartTime  "Abholung: [%1$td.%1$tm.%1$tY]" <calendar> (gCal_Abfall_Event)
DateTime gCal_Abfall_Event2_EndTime "Event2 End [%1$td.%1$tm.%1$tY %1$tH:%1$tM]" <calendar> (gCal_Abfall_Event)
Switch gCal_Abfall_Event2_Approved "Mülltonne rausgestellt: [%s]" <calendar> (gCal_Abfall_Event)

String gCal_Abfall_Event3_Summary "Mülltonne: [%s]" <calendar> (gCal_Abfall_Event)
String gCal_Abfall_Event3_Location "Event3 Loc.: [%s]" <calendar> (gCal_Abfall_Event)
String gCal_Abfall_Event3_Description "Event3 Desc. [%s]" <calendar> (gCal_Abfall_Event)
DateTime gCal_Abfall_Event3_StartTime  "Abholung: [%1$td.%1$tm.%1$tY]" <calendar> (gCal_Abfall_Event)
DateTime gCal_Abfall_Event3_EndTime "Event3 End [%1$td.%1$tm.%1$tY %1$tH:%1$tM]" <calendar> (gCal_Abfall_Event)
Switch gCal_Abfall_Event3_Approved "Mülltonne rausgestellt: [%s]" <calendar> (gCal_Abfall_Event)

String gCal_Abfall_Event4_Summary "Mülltonne: [%s]" <calendar> (gCal_Abfall_Event)
String gCal_Abfall_Event4_Location "Event4 Loc.: [%s]" <calendar> (gCal_Abfall_Event)
String gCal_Abfall_Event4_Description "Event4 Desc. [%s]" <calendar> (gCal_Abfall_Event)
DateTime gCal_Abfall_Event4_StartTime  "Abholung: [%1$td.%1$tm.%1$tY]" <calendar> (gCal_Abfall_Event)
DateTime gCal_Abfall_Event4_EndTime "Event4 End [%1$td.%1$tm.%1$tY %1$tH:%1$tM]" <calendar> (gCal_Abfall_Event)
Switch gCal_Abfall_Event4_Approved "Mülltonne rausgestellt: [%s]" <calendar> (gCal_Abfall_Event)
  • GoogleCal.rules
// grab the calendar events from google via API
rule "GetCalEvents"
when
	//at second :00 Every 30 Minutes, everyday from 5PM to 9PM
	Time cron "0 0/30 17-21 ? * *"
then
	var String results = executeCommandLine("python /etc/openhab2/scripts/CalSyncHAB/CalSyncHAB.py", 120*1000)
	logInfo("GetCalEvents", results)
end

// Check garbage calendar events
rule "Check garbage calendar events"
when
	// 30 seconds delay to get "GetCalEvents" rule time to parse Google Cal API
	// at second :30 Every 30 Minutes, everyday from 5PM to 9PM
	Time cron "30 0/30 17-21 ? * *"
then
	logInfo("Garbage calendar", "Execution started")
	gCal_Abfall.members.forEach[ gc |
		val eventStart = gCal_Abfall_Event.members.filter[ act | act.name == gc.name+"_StartTime"].head
		val eventDesc = gCal_Abfall_Event.members.filter[ act | act.name == gc.name+"_Description"].head
		val eventSum = gCal_Abfall_Event.members.filter[ act | act.name == gc.name+"_Summary"].head
		val eventApproved = gCal_Abfall_Event.members.filter[ act | act.name == gc.name+"_Approved"].head
		// Execution every (Time cron) until EventStartTime or Tasks is approved by Item
		if (eventApproved.state == OFF) {
			// in this case i used 8 hours before EventStartTime (my events starting at 00:00, so I have enough time in the evening to get the trash cans out)
			if (now.isAfter(new DateTime((eventStart.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli).minusHours(8)) &&
				now.isBefore(new DateTime((eventStart.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli))) {
				val buffer = eventDesc.state.toString.split(";")
				val calItem = gCal_Abfall_Item.members.filter[ ci | ci.name == eventSum.state.toString].head
				if (calItem !== null) {
					logInfo("Garbage calendar", gc.name + " starting now with '" + calItem.name + "' -> " + buffer.get(0))
					// you need to have images with the event names in your openhab "html" folder, otherwise comment the line out
					sendTelegramPhoto( "bot1", "http://openhabianpi:8080/static/" + calItem.name + ".png", "")
					sendTelegram( "bot1", "🗑" + gc.name + " ausgelöst...\n\n" + calItem.name + " wird morgen früh abgeholt...\n -> " + buffer.get(0) + "\n\n(Wiedervorlage dieser Nachricht jede Stunde bis der Schalter auf erledigt gesetzt wurde.. ;-) )")
					sendCommand(calItem, ON)
				}
				else {
					logInfo("Garbage calendar", "WARNING: cannot find item named '" + eventSum.state + "'")
				}
			}
		}
		//Execution at EventStartTime if Task is not approved by Item
		if (now.isAfter(new DateTime((eventStart.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)) &&
		//Change plusMinutes(60) to your Time Cron Interval
		now.isBefore(new DateTime((eventStart.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli).plusMinutes(60))) {
			//Reset eventApproved status!
			eventApproved.sendCommand(OFF)
			//Reset calItem!
			val buffer = eventDesc.state.toString.split(";")
			val calItem = gCal_Abfall_Item.members.filter[ ci | ci.name == eventSum.state.toString].head
			if (calItem !== OFF) {
				sendCommand(calItem, OFF)
				logInfo("Garbage calendar", gc.name + " ended now with'" + calItem.name + "' -> " + buffer.get(1))
			}
			else {
				logInfo("Garbage calendar", "WARNING: cannot find item named '" + eventSum.state + "'")
			}
		}
	]
	logInfo("Garbage calendar", "Execution finished")
end
  • YOURSITEMAP.sitemap
	Frame label="Anstehende Termine für Morgen" {
		Text item=gCal_Abfall_Item {
			Frame label="Anstehende Müll-Abfuhr Termine" {
				//Group item=gCal_Abfall_Item label="Anstehende Müll-Abfuhr Termine"
				Text item=gCal_Abfall_Event1_Summary
				//Text item=gCal_Abfall_Event1_Location
				Text item=gCal_Abfall_Event1_Description
				Text item=gCal_Abfall_Event1_StartTime
				//Text item=gCal_Abfall_Event1_EndTime
				Switch item=gCal_Abfall_Event1_Approved
				Text item=gCal_Abfall_Event2_Summary
				//Text item=gCal_Abfall_Event2_Location
				Text item=gCal_Abfall_Event2_Description
				Text item=gCal_Abfall_Event2_StartTime
				//Text item=gCal_Abfall_Event2_EndTime
				Switch item=gCal_Abfall_Event2_Approved
				Text item=gCal_Abfall_Event3_Summary
				//Text item=gCal_Abfall_Event3_Location
				Text item=gCal_Abfall_Event3_Description
				Text item=gCal_Abfall_Event3_StartTime
				//Text item=gCal_Abfall_Event3_EndTime
				Switch item=gCal_Abfall_Event3_Approved
				Text item=gCal_Abfall_Event4_Summary
				//Text item=gCal_Abfall_Event4_Location
				Text item=gCal_Abfall_Event4_Description
				Text item=gCal_Abfall_Event4_StartTime
				//Text item=gCal_Abfall_Event4_EndTime
				Switch item=gCal_Abfall_Event4_Approved
			}
		}
		Text item=gCal_Geburtstag_Item
	}

Hope this helps some newbies… Thank you and have fun :slight_smile:

/Holger

.

8 Likes