/ PyPortal_Wakeup_Light / code.py
code.py
1 # SPDX-FileCopyrightText: 2019 Isaac Wellish for Adafruit Industries 2 # 3 # SPDX-License-Identifier: MIT 4 5 """ 6 This example uses a PyPortal and rgbw leds for a simple "wake up" light. 7 The strip starts to brighten 30 minutes before set wake up time. 8 This program assumes a neopixel strip is attached to D3 on the Adafruit PyPortal. 9 """ 10 import time 11 import board 12 import neopixel 13 from adafruit_pyportal import PyPortal 14 from adafruit_bitmap_font import bitmap_font 15 from adafruit_display_text.Label import Label 16 17 # type in time to get up each day of the week 18 default_wake_up = "6:30A" 19 up_time_monday = default_wake_up 20 up_time_tuesday = default_wake_up 21 up_time_wednesday = default_wake_up 22 up_time_thursday = default_wake_up 23 up_time_friday = default_wake_up 24 up_time_saturday = "10:00A" 25 up_time_sunday = "10:00A" 26 wake_up_times = (up_time_monday, 27 up_time_tuesday, 28 up_time_wednesday, 29 up_time_thursday, 30 up_time_friday, 31 up_time_saturday, 32 up_time_sunday, 33 default_wake_up) 34 days_str = ("Mon.", "Tues.", "Wed.", "Thurs.", "Fri.", "Sat.", "Sun.") 35 36 # set neopixel min and max brightness 37 BRIGHTNESS = 0 38 MIN_BRIGHTNESS = 0 39 MAX_BRIGHTNESS = 0.85 40 # initialize neopixel strip 41 num_pixels = 30 42 ORDER = neopixel.RGBW 43 strip = neopixel.NeoPixel(board.D3, num_pixels, brightness=BRIGHTNESS, 44 pixel_order=ORDER) 45 strip.fill(0) # start it set to off 46 # color of strip 47 WHITE = (0, 0, 0, 255) 48 # number of minutes it takes for strip to fade from min to max 49 light_minutes = 30 50 51 # determine the current working directory 52 # needed so we know where to find files 53 cwd = ("/"+__file__).rsplit('/', 1)[0] 54 55 # initialize the pyportal object and let us know what data to fetch and where 56 # to display it 57 pyportal = PyPortal(status_neopixel=board.NEOPIXEL, 58 default_bg=0x000000) 59 60 # set backlight default to off 61 backlight_off = 0 62 backlight_on = 0.8 63 pyportal.set_backlight(backlight_off) 64 65 # assign fonts 66 big_font = bitmap_font.load_font(cwd+"/fonts/Nunito-Light-75.bdf") 67 big_font.load_glyphs(b'0123456789:AP') # pre-load glyphs for fast printing 68 print('loading fonts...') 69 info_font = bitmap_font.load_font(cwd+"/fonts/Nunito-Black-17.bdf") 70 info_font.load_glyphs(b'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-,.:/ ') 71 72 time_color = 0xFFFFFF 73 time_position = (75,130) 74 time_textarea = Label(big_font, color=time_color, 75 x=time_position[0], y=time_position[1]) 76 77 wakeup_time_color = 0xFFFFFF 78 wakeup_time_position = (15,200) 79 wakeup_time_textarea = Label(info_font, color=wakeup_time_color, 80 x=wakeup_time_position[0], y=wakeup_time_position[1]) 81 82 light_on_time_color = 0xFFFFFF 83 light_on_time_position = (15,220) 84 light_on_time_textarea = Label(info_font, color=light_on_time_color, 85 x=light_on_time_position[0], y=light_on_time_position[1]) 86 87 pyportal.splash.append(time_textarea) 88 pyportal.splash.append(wakeup_time_textarea) 89 pyportal.splash.append(light_on_time_textarea) 90 91 while True: 92 try: 93 print("Getting time from internet!") 94 pyportal.get_local_time() 95 except RuntimeError as e: 96 print("Some error occured, retrying! -", e) 97 continue 98 break 99 100 # parse given time string into hour minute and AM_PM elements 101 def parseTime(time_before): 102 hours_before, minutes_before = time_before.split(":") 103 AM_PM_str = minutes_before[-1:] 104 minutes_before = int(minutes_before[:-1]) 105 if (hours_before != '12') and AM_PM_str == 'P': 106 hours_before = int(hours_before) + 12 107 elif ((hours_before == '12') and (AM_PM_str == 'P')): 108 hours_before = int(hours_before) 109 elif ((hours_before == '12') and (AM_PM_str == 'A')): 110 hours_before = 0 111 else: 112 hours_before = int(hours_before) 113 parsed_time = [hours_before, minutes_before] 114 return parsed_time 115 116 # get time objects for wake up times 117 val_times = [] 118 parsed_times = [] 119 for i in range(len(wake_up_times)): 120 parsed_time_day = parseTime(wake_up_times[i]) 121 hours, minutes = parsed_time_day[0:2] 122 now_day = time.localtime() 123 time_obj_mk = time.mktime((now_day[0], now_day[1], now_day[2], hours, 124 minutes, now_day[5], i, now_day[7], now_day[8])) 125 time_obj = time.localtime(time_obj_mk) 126 val_times.append(time_obj_mk) 127 parsed_times.append(time_obj) 128 129 # determine which day it is and print which time waking up on screen 130 def whichDay(): 131 now = time.localtime() 132 current_day = now[6] 133 now_mk = time.mktime((now[0], now[1], now[2], now[3], now[4], now[5], now[6], now[7], now[8])) 134 # if it's after midnight and before todays wakeup time, display the wake up time of today 135 for day in range(len(wake_up_times)): 136 if now_mk < val_times[day]: 137 if current_day == day: 138 input_wake_up_time = wake_up_times[day] 139 use_day = day 140 # set wake up time to the next day's wake up time after current day's wake up time 141 else: 142 if current_day == 6: 143 input_wake_up_time = wake_up_times[0] 144 use_day = 0 145 else: 146 if current_day == day: 147 input_wake_up_time = wake_up_times[day+1] 148 use_day = day + 1 149 input_wake_up_time_text = "Wake up " + days_str[use_day] + " at " + input_wake_up_time 150 wakeup_time_textarea.text = input_wake_up_time_text 151 return use_day 152 153 def displayTime(): 154 now = time.localtime() 155 hour, minute = now[3:5] 156 print(now) 157 print("Current time: %02d:%02d" % (hour, minute)) 158 formatTime(hour, minute) 159 time_textarea.text = formatTime(hour, minute) 160 return formatTime(hour, minute) 161 162 def formatTime(raw_hours, raw_minutes): 163 # display the time in a nice big font 164 format_str = "%d:%02d" 165 if raw_hours >= 12: 166 raw_hours -= 12 167 format_str = format_str+"P" 168 else: 169 format_str = format_str+"A" 170 if raw_hours == 0: 171 raw_hours = 12 172 time_str = format_str % (raw_hours, raw_minutes) 173 return time_str 174 175 def backLight(): 176 now = time.localtime() 177 now_val = time.mktime((now[0], now[1], now[2], now[3], now[4], now[5], now[6], now[7], now[8])) 178 wake_up_day_val = val_times[now[6]] 179 # if time is more than 9 hours after current day's wake up time, 180 # or time is before light start time, backlight off, tap to turn on 181 if (now_val - wake_up_day_val) > 32400 or (now_val - wake_up_day_val) < -1800: 182 pyportal.set_backlight(backlight_off) 183 if pyportal.touchscreen.touch_point: 184 pyportal.set_backlight(backlight_on) 185 time.sleep(5) 186 pyportal.set_backlight(backlight_off) 187 else: 188 pyportal.set_backlight(backlight_on) 189 190 def subtract30min(day): # subtract 30 min 191 # get the time object from the corresponding day 192 raw_wake_up_time = parsed_times[day] 193 now = time.localtime() 194 # new time subtracting 30 min from wake up time 195 minus30 = time.mktime((now[0], now[1], now[2], raw_wake_up_time[3], 196 raw_wake_up_time[4] - 30, now[5], now[6], now[7], now[8])) 197 time_minus30 = time.localtime(minus30) 198 hour_minus30 = time_minus30[3] 199 minutes_minus30 = time_minus30[4] 200 light_on_time_textarea.text = "Light starting at: " + formatTime(hour_minus30, minutes_minus30) 201 return formatTime(hour_minus30, minutes_minus30) 202 203 refresh_time = None 204 205 while True: 206 time_now = time.localtime() 207 # only query the online time once per hour (and on first run) 208 if (not refresh_time) or (time.monotonic() - refresh_time) > 3600: 209 try: 210 print("Getting time from internet!") 211 pyportal.get_local_time() 212 refresh_time = time.monotonic() 213 except RuntimeError as e: 214 print("Some error occured, retrying! -", e) 215 continue 216 time_str_text = displayTime() 217 print(time_str_text) 218 # determine which wake up time to choose based on the day 219 wake_up_day = whichDay() 220 # if time is more than 9 hours after previous day's wake up time, 221 # backlight off and can tap to turn on 222 backLight() 223 # start the light 30 min before wake up time 224 start_light_time = subtract30min(wake_up_day) 225 # If current day is same as wake up day and 226 # wake up time - 30 minutes equals current time, start the light 227 if wake_up_day == time_now[6] and time_str_text == start_light_time: 228 print("Starting wake up light") 229 # turn on backlight 230 pyportal.set_backlight(backlight_on) 231 for i in range(light_minutes - 1): 232 BRIGHTNESS = BRIGHTNESS + (MAX_BRIGHTNESS/light_minutes) # max 0.25, min 0.0 233 strip.fill(WHITE) 234 strip.brightness = BRIGHTNESS 235 displayTime() 236 time.sleep(60) # 60 for once per min 237 while not pyportal.touchscreen.touch_point: # turn strip off 238 displayTime() 239 time.sleep(1) 240 continue 241 strip.brightness = MIN_BRIGHTNESS 242 # update every second so that screen can be tapped to view time 243 time.sleep(1)