CircuitPython Code
In the embedded code element below, click on the Download Project Bundle button, and save the .zip archive file to your computer.
Then, uncompress the .zip file, it will unpack to a folder named PyPortal_Wakeup_Light.
Copy the contents of the PyPortal_Wakeup_Light directory to your PyPortal CIRCUITPY drive.
# SPDX-FileCopyrightText: 2019 Isaac Wellish for Adafruit Industries # # SPDX-License-Identifier: MIT """ This example uses a PyPortal and rgbw leds for a simple "wake up" light. The strip starts to brighten 30 minutes before set wake up time. This program assumes a neopixel strip is attached to D3 on the Adafruit PyPortal. """ import time import board import neopixel from adafruit_pyportal import PyPortal from adafruit_bitmap_font import bitmap_font from adafruit_display_text.Label import Label # type in time to get up each day of the week default_wake_up = "6:30A" up_time_monday = default_wake_up up_time_tuesday = default_wake_up up_time_wednesday = default_wake_up up_time_thursday = default_wake_up up_time_friday = default_wake_up up_time_saturday = "10:00A" up_time_sunday = "10:00A" wake_up_times = (up_time_monday, up_time_tuesday, up_time_wednesday, up_time_thursday, up_time_friday, up_time_saturday, up_time_sunday, default_wake_up) days_str = ("Mon.", "Tues.", "Wed.", "Thurs.", "Fri.", "Sat.", "Sun.") # set neopixel min and max brightness BRIGHTNESS = 0 MIN_BRIGHTNESS = 0 MAX_BRIGHTNESS = 0.85 # initialize neopixel strip num_pixels = 30 ORDER = neopixel.RGBW strip = neopixel.NeoPixel(board.D3, num_pixels, brightness=BRIGHTNESS, pixel_order=ORDER) strip.fill(0) # start it set to off # color of strip WHITE = (0, 0, 0, 255) # number of minutes it takes for strip to fade from min to max light_minutes = 30 # determine the current working directory # needed so we know where to find files cwd = ("/"+__file__).rsplit('/', 1)[0] # initialize the pyportal object and let us know what data to fetch and where # to display it pyportal = PyPortal(status_neopixel=board.NEOPIXEL, default_bg=0x000000) # set backlight default to off backlight_off = 0 backlight_on = 0.8 pyportal.set_backlight(backlight_off) # assign fonts big_font = bitmap_font.load_font(cwd+"/fonts/Nunito-Light-75.bdf") big_font.load_glyphs(b'0123456789:AP') # pre-load glyphs for fast printing print('loading fonts...') info_font = bitmap_font.load_font(cwd+"/fonts/Nunito-Black-17.bdf") info_font.load_glyphs(b'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-,.:/ ') time_color = 0xFFFFFF time_position = (75,130) time_textarea = Label(big_font, color=time_color, x=time_position[0], y=time_position[1]) wakeup_time_color = 0xFFFFFF wakeup_time_position = (15,200) wakeup_time_textarea = Label(info_font, color=wakeup_time_color, x=wakeup_time_position[0], y=wakeup_time_position[1]) light_on_time_color = 0xFFFFFF light_on_time_position = (15,220) light_on_time_textarea = Label(info_font, color=light_on_time_color, x=light_on_time_position[0], y=light_on_time_position[1]) pyportal.splash.append(time_textarea) pyportal.splash.append(wakeup_time_textarea) pyportal.splash.append(light_on_time_textarea) while True: try: print("Getting time from internet!") pyportal.get_local_time() except RuntimeError as e: print("Some error occured, retrying! -", e) continue break # parse given time string into hour minute and AM_PM elements def parseTime(time_before): hours_before, minutes_before = time_before.split(":") AM_PM_str = minutes_before[-1:] minutes_before = int(minutes_before[:-1]) if (hours_before != '12') and AM_PM_str == 'P': hours_before = int(hours_before) + 12 elif ((hours_before == '12') and (AM_PM_str == 'P')): hours_before = int(hours_before) elif ((hours_before == '12') and (AM_PM_str == 'A')): hours_before = 0 else: hours_before = int(hours_before) parsed_time = [hours_before, minutes_before] return parsed_time # get time objects for wake up times val_times = [] parsed_times = [] for i in range(len(wake_up_times)): parsed_time_day = parseTime(wake_up_times[i]) hours, minutes = parsed_time_day[0:2] now_day = time.localtime() time_obj_mk = time.mktime((now_day[0], now_day[1], now_day[2], hours, minutes, now_day[5], i, now_day[7], now_day[8])) time_obj = time.localtime(time_obj_mk) val_times.append(time_obj_mk) parsed_times.append(time_obj) # determine which day it is and print which time waking up on screen def whichDay(): now = time.localtime() current_day = now[6] now_mk = time.mktime((now[0], now[1], now[2], now[3], now[4], now[5], now[6], now[7], now[8])) # if it's after midnight and before todays wakeup time, display the wake up time of today for day in range(len(wake_up_times)): if now_mk < val_times[day]: if current_day == day: input_wake_up_time = wake_up_times[day] use_day = day # set wake up time to the next day's wake up time after current day's wake up time else: if current_day == 6: input_wake_up_time = wake_up_times[0] use_day = 0 else: if current_day == day: input_wake_up_time = wake_up_times[day+1] use_day = day + 1 input_wake_up_time_text = "Wake up " + days_str[use_day] + " at " + input_wake_up_time wakeup_time_textarea.text = input_wake_up_time_text return use_day def displayTime(): now = time.localtime() hour, minute = now[3:5] print(now) print("Current time: %02d:%02d" % (hour, minute)) formatTime(hour, minute) time_textarea.text = formatTime(hour, minute) return formatTime(hour, minute) def formatTime(raw_hours, raw_minutes): # display the time in a nice big font format_str = "%d:%02d" if raw_hours >= 12: raw_hours -= 12 format_str = format_str+"P" else: format_str = format_str+"A" if raw_hours == 0: raw_hours = 12 time_str = format_str % (raw_hours, raw_minutes) return time_str def backLight(): now = time.localtime() now_val = time.mktime((now[0], now[1], now[2], now[3], now[4], now[5], now[6], now[7], now[8])) wake_up_day_val = val_times[now[6]] # if time is more than 9 hours after current day's wake up time, # or time is before light start time, backlight off, tap to turn on if (now_val - wake_up_day_val) > 32400 or (now_val - wake_up_day_val) < -1800: pyportal.set_backlight(backlight_off) if pyportal.touchscreen.touch_point: pyportal.set_backlight(backlight_on) time.sleep(5) pyportal.set_backlight(backlight_off) else: pyportal.set_backlight(backlight_on) def subtract30min(day): # subtract 30 min # get the time object from the corresponding day raw_wake_up_time = parsed_times[day] now = time.localtime() # new time subtracting 30 min from wake up time minus30 = time.mktime((now[0], now[1], now[2], raw_wake_up_time[3], raw_wake_up_time[4] - 30, now[5], now[6], now[7], now[8])) time_minus30 = time.localtime(minus30) hour_minus30 = time_minus30[3] minutes_minus30 = time_minus30[4] light_on_time_textarea.text = "Light starting at: " + formatTime(hour_minus30, minutes_minus30) return formatTime(hour_minus30, minutes_minus30) refresh_time = None while True: time_now = time.localtime() # only query the online time once per hour (and on first run) if (not refresh_time) or (time.monotonic() - refresh_time) > 3600: try: print("Getting time from internet!") pyportal.get_local_time() refresh_time = time.monotonic() except RuntimeError as e: print("Some error occured, retrying! -", e) continue time_str_text = displayTime() print(time_str_text) # determine which wake up time to choose based on the day wake_up_day = whichDay() # if time is more than 9 hours after previous day's wake up time, # backlight off and can tap to turn on backLight() # start the light 30 min before wake up time start_light_time = subtract30min(wake_up_day) # If current day is same as wake up day and # wake up time - 30 minutes equals current time, start the light if wake_up_day == time_now[6] and time_str_text == start_light_time: print("Starting wake up light") # turn on backlight pyportal.set_backlight(backlight_on) for i in range(light_minutes - 1): BRIGHTNESS = BRIGHTNESS + (MAX_BRIGHTNESS/light_minutes) # max 0.25, min 0.0 strip.fill(WHITE) strip.brightness = BRIGHTNESS displayTime() time.sleep(60) # 60 for once per min while not pyportal.touchscreen.touch_point: # turn strip off displayTime() time.sleep(1) continue strip.brightness = MIN_BRIGHTNESS # update every second so that screen can be tapped to view time time.sleep(1)
Make sure to add the necessary libraries to the lib folder, info on how to do this can be found in the "PyPortal CircuitPython Setup" section
This project uses the following CircuitPython libraries - from the bundle zip copy them in the CIRCUITPY/lib directory.
- adafruit_bitmap_font (directory)
- adafruit_bus_device (directory)
- adafruit_display_shapes (directory)
- adafruit_display_text (directory)
- adafruit_esp32spi (directory)
- adafruit_imageload (directory)
- adafruit_io (directory)
- adafruit_pyportal.mpy (file)
- adafruit_requests (file)
- adafruit_touchscreen.mpy (file)
- neopixel.mpy (file)
This is what the final contents of the CIRCUITPY drive will look like:
Text editor powered by tinymce.