The Google Calendar Event Display code uses the Google Calendar API's Event list endpoint to return events from a specific calendar.

The results from a GET request to this endpoint will look something like the following:

{
 "kind": "calendar#events",
 "etag": "\"p32c9b6vtqmbes0g\"",
 "summary": "Meetings",
 "updated": "2021-01-12T15:06:56.911Z",
 "timeZone": "America/New_York",
 "accessRole": "owner",
 "defaultReminders": [],
 "nextPageToken": "CigKGjMyajF0bm0xcmwzbDBnbWhmNTNyaW9xb3B2GAEggIDA3tm_zrYXGg0IABIAGJiVm_3Vlu4CIgcIBBC35scP",
 "items": [
  {
   "kind": "calendar#event",
   "etag": "\"3219736474490000\"",
   "id": "32j1tnm1rl3l0gmhf53rioqopv",
   "status": "confirmed",
   "htmlLink": "https://www.google.com/calendar/event?eid=MzJqMXRubTFybDNsMGdtaGY1M3Jpb3FvcHYgYWpmb242cGhsN24xZG1wanNkbGV2dHFhMDRAZw",
   "created": "2021-01-05T17:35:02.000Z",
   "updated": "2021-01-05T17:37:17.245Z",
   "summary": "Adafruit Show and Tell",
   "creator": {
    "email": ""
   },
   "organizer": {
    "email": "@group.calendar.google.com",
    "displayName": "Meetings",
    "self": true
   },
   "start": {
    "dateTime": "2021-01-06T19:30:00-05:00"
   },
   "end": {
    "dateTime": "2021-01-06T20:00:00-05:00"
   },
   "iCalUID": "@google.com",
   "sequence": 0,
   "reminders": {
    "useDefault": true
   }
  }
 ]
}

All events are kept within an items array which contains detailed information about each event. The code parses this array for the event's summary and the event's start dateTime

Refreshing Google API Access Token

The Google Calendar API access token expires after a specific time interval. If the access token is expired, the refresh token in secrets.py is used to POST a request to Google's servers for a new access token.

if (int(time.monotonic()) - access_token_obtained>= google_auth.access_token_expiration):
  print("Access token expired, refreshing...")
  if not google_auth.refresh_access_token():
    raise RuntimeError(
      "Unable to refresh access token - has the token been revoked?"
    )
    access_token_obtained = int(time.monotonic())

Fetching Calendar Events

Prior to calling Google Calendar, a timestamp must be obtained to display the latest events in ascending order. The code calls the Adafruit IO time service to fetch and set the timestamp we'll use for requesting data from Google Calendar.

# fetch calendar events!
print("fetching local time...")
now = get_current_time()

We'll display the current date at the top of the MagTag. Passing a pretty_date argument formats the struct_time timestamp into a human-readable timestamp such as "January 6th, 2021"

# setup header label
magtag.set_text(
    format_datetime(now, pretty_date=True), label_header, auto_refresh=False
)

We use call get_calendar_events with the timestamp to request a list of calendar events in ascending order.

print("fetching calendar events...")
events = get_calendar_events(CALENDAR_ID, MAX_EVENTS, now)

Within get_calendar_events, we perform a HTTP GET to Google Calendar API's event list endpoint

time_max = get_current_time(time_max=True)
    print("Fetching calendar events from {0} to {1}".format(time_min, time_max))

    headers = {
        "Authorization": "Bearer " + google_auth.access_token,
        "Accept": "application/json",
        "Content-Length": "0",
    }
    url = (
        "https://www.googleapis.com/calendar/v3/calendars/{0}"
        "/events?maxResults={1}&timeMin={2}&timeMax={3}&orderBy=startTime"
        "&singleEvents=true".format(calendar_id, max_events, time_min, time_max)
    )
    resp = magtag.network.requests.get(url, headers=headers)

Then, the response is parsed. Each entry in the response's items array is parsed and appended to an items list. This list is returned as events.

resp_json = resp.json()
    if "error" in resp_json:
        raise RuntimeError("Error:", resp_json)
    resp.close()
    # parse the 'items' array so we can iterate over it easier
    items = []
    resp_items = resp_json["items"]
    if not resp_items:
        print("No events scheduled for today!")
    for event in range(0, len(resp_items)):
        items.append(resp_items[event])
    return items

Back in the while True loop, the code passes the event list to display_calendar_events.

print("displaying events")
display_calendar_events(events)

display_calendar_events iterates through the resp_events list. In each iteration, it parses an event's start time and description from the list and generates labels to display the data on the device's screen.

def display_calendar_events(resp_events):
    # Display all calendar events
    for event_idx in range(len(resp_events)):
        event = resp_events[event_idx]
        # wrap event name around second line if necessary
        event_name = magtag.wrap_nicely(event["summary"], 25)
        event_name = "\n".join(event_name[0:2])  # only wrap 2 lines, truncate third..
        event_start = event["start"]["dateTime"]
        print("-" * 40)
        print("Event Description: ", event_name)
        print("Event Time:", format_datetime(event_start))
        print("-" * 40)
        # Generate labels holding event info
        magtag.add_text(
            text_font=font_event,
            text_position=(7, 40 + (event_idx * 35)),
            text_color=0x000000,
            text=format_datetime(event_start),
        )
        magtag.add_text(
            text_font=font_event,
            text_position=(88, 40 + (event_idx * 35)),
            text_color=0x000000,
            text=event_name,
            line_spacing=0.65,
        )

Finally, the display elements are shown on the screen and the MagTag enters low power mode for REFRESH_TIME minutes.

magtag.graphics.display.refresh()

print("Sleeping for %d minutes" % REFRESH_TIME)
magtag.exit_and_deep_sleep(REFRESH_TIME * 60)

This guide was first published on Jan 13, 2021. It was last updated on Jan 13, 2021.

This page (Code Walkthrough) was last updated on Jan 12, 2021.

Text editor powered by tinymce.