#! /usr/bin/env python """ usage: google-muell [options] --esp=HOST esp8266 ip [Default: 192.168.1.23] --client-secrets=FILE Path to client secrets file (from application) [Default: licht-kalender-secrets.json] --credential-path=PATH Path to newly generated (or existing) credentials [Default: licht-creds.json] --sleepval=SEC seconds to sleep [Default: 900] --lol=LOL set log level [Default: debug] you can create the client-secrets by creating a new google application, create oauth2 token and download it ( url here) """ from docopt import docopt from ampel.fade import calc_chain import time from time import sleep import json import sys from datetime import datetime, timedelta import requests import httplib2 from dateutil.parser import parse from apiclient import discovery from oauth2client import client from oauth2client import tools from oauth2client.file import Storage import logging as log SCOPES = 'https://www.googleapis.com/auth/calendar.readonly' APPLICATION_NAME = 'licht-kalender-client' calendarId = 'o56ig681gla2a5vupm4vgiv7tc@group.calendar.google.com' # Mapping colorId from calendar to RGB colors colormap = { # "-1": [ 124, 179, 66 ], # default color (green) "-1": [ 54, 234, 255 ], # default color (green) "1": [ 121, 134, 203 ], # lavendel "2": [ 51, 182, 121 ], # salbei "3": [ 142, 36, 170 ], # grape "4": [ 230, 124, 115 ], # light red "5": [ 255, 183, 0 ], # banana, gelber sack "6": [ 244, 81, 30 ], # mandarin "7": [3, 155, 229], # pfau "8": [ 128,128,128 ], # grey "9": [ 63, 81, 181 ], # heidelbeere "10": [0x0B,0x80,0x43 ], # basilicum "11": [ 231,0,0 ], # true red } def set_lol(lol): numeric_level = getattr(log,lol.upper(),None) if not isinstance(numeric_level,int): raise AttributeError(f'No such log level {lol}') log.basicConfig(level=numeric_level) def get_creds(secrets_file,credential_path): ''' provide a cred_dir where the credentials would be stored to ''' import argparse flags = tools.argparser.parse_args(args=[]) store = Storage(credential_path) credentials = store.get() if not credentials or credentials.invalid: flow = client.flow_from_clientsecrets(secrets_file, SCOPES) flow.user_agent = APPLICATION_NAME credentials = tools.run_flow(flow, store, flags) log.info(f'Storing new credentials to {credential_path}') else: log.info(f'Using existing valid credentials {credential_path}') return credentials def next_date(credentials): http = credentials.authorize(httplib2.Http()) service = discovery.build('calendar', 'v3', http=http) now = datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time log.debug('Getting the upcoming 10 events') eventsResult = service.events().list( calendarId=calendarId, timeMin=now, maxResults=10, singleEvents=True, orderBy='startTime').execute() events = eventsResult.get('items', []) for event in events: rem = event['reminders'] # 'reminders': {'useDefault': False, 'overrides': [{'method': 'popup', 'minutes': 900}]} start = parse(event['start'].get('dateTime', event['start'].get('date'))) if rem.get('overrides',[]): reminder = timedelta(minutes=rem['overrides'][0]['minutes']) log.info(f"Got a reminder at {reminder}, subtracting time") start = start - reminder if 'dateTime' in event['end']: end = parse(event['end']['dateTime']) else: end = parse(event['end']['date']) - timedelta(seconds=1) # + timedelta(days=1) if start < datetime.now() < end: log.info(f"event {event['summary']} is active now ({start} - {end})") return event else: log.info(f"event between {start} and {end} is not active") pass def to_payload(arr): return {"r":arr[0],"g":arr[1],"b":arr[2]} def main(): args = docopt(__doc__) set_lol(args['--lol']) client_secrets = args['--client-secrets'] sleepval = float(args["--sleepval"]) esp = args["--esp"] cred_path = args["--credential-path"] creds = get_creds(client_secrets,cred_path) while True: try: log.info("Fetching next Date") t = next_date(creds) if t: color = colormap[str(t.get('colorId',-1))] log.info(f"setting color to {color} according to colormap") else: color = colormap["-1"] log.info(f"setting default color {color}") requests.get(f"http://{esp}/color",params=to_payload(color)) except Exception as e: log.error(f"Something went wrong while calculating the next date:{e}") log.info(f"sleeping for {sleepval} seconds") sleep(sleepval) if __name__ == "__main__": main()