This project's code uses the CircuitPython OAuth Library for authentication with Google services. Due to Google's update to the OAuth "authentication flow", the library became incompatible. As a result, this project does not currently work (but may in the future).
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 PyPortal. Passing a pretty_date argument formats the struct_time timestamp into a human-readable timestamp such as "January 6th, 2021"
# setup header label pyportal.set_text(format_datetime(now, pretty_date=True), label_header)
Within get_calendar_events, we perform a HTTP GET to Google Calendar API's event list endpoint
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 = PyPortal.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)
pyportal.set_text(format_datetime(event_start), event_labels[event_idx][0])
pyportal.set_text(event_name, event_labels[event_idx][1])
# Clear any unused labels
for event_idx in range(len(resp_events), MAX_EVENTS):
pyportal.set_text("", event_labels[event_idx][0])
pyportal.set_text("", event_labels[event_idx][1])
Finally, the display elements are displayed on the screen and the PyPortal sleeps for REFRESH_TIME minutes.
print("displaying events")
display_calendar_events(events)
print("Sleeping for %d minutes" % REFRESH_TIME)
time.sleep(REFRESH_TIME * 60)
Page last edited May 06, 2025
Text editor powered by tinymce.