-
-
Save joeycastillo/afc037cf75ec1d6a3580fe2d9dfed54d to your computer and use it in GitHub Desktop.
Neopixel Christmas Tree with CircuitPython Deep Sleep
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import board | |
from digitalio import DigitalInOut, Direction, Pull | |
from oso_lcd.lcdwing_lite import LCDWingLite, Indicator | |
import time | |
import alarm | |
import rtc | |
import lights | |
import network | |
import button | |
display = LCDWingLite(board.I2C()) | |
clock = rtc.RTC() | |
if clock.datetime.tm_year < 2020: | |
display.print("5tClk") | |
display.set_indicator(Indicator.WIFI) | |
network.set_time_if_needed() | |
display.clear_indicator(Indicator.WIFI) | |
alarm.sleep_memory[0] = 10 # The default hour for the lights to turn on, 10 AM | |
alarm.sleep_memory[1] = 0 # The default minute for the lights to turn on (10:00 AM) | |
alarm.sleep_memory[2] = 1 # The default duration for the lights to remain on (1 hour) | |
def display_time(hour, minute): | |
hour_12 = hour % 12 | |
display.print("{:2d}:{:02d}".format(hour_12 if hour_12 else 12, minute)) | |
if hour < 12: | |
display.clear_indicator(Indicator.PM) | |
display.set_indicator(Indicator.AM) | |
else: | |
display.clear_indicator(Indicator.AM) | |
display.set_indicator(Indicator.PM) | |
MODE_SHOW_TIME = 0 | |
MODE_SET_ON_TIME = 1 | |
MODE_SET_DURATION = 2 | |
NUM_MODES = 3 | |
mode = 0 | |
time_needs_display = True | |
deep_sleep_at = time.monotonic() + 120 | |
lights_on = False | |
while True: | |
dt = clock.datetime | |
(press, long_press) = button.update() | |
if press or long_press: | |
deep_sleep_at = max(deep_sleep_at, time.monotonic() + 120) | |
if long_press: | |
mode = (mode + 1) % NUM_MODES | |
display.clear_indicator(Indicator.ALL) | |
time_needs_display = True | |
if mode == MODE_SHOW_TIME: | |
if time_needs_display or dt.tm_sec == 0: | |
display_time(dt.tm_hour, dt.tm_min) | |
time_needs_display = False | |
elif mode == MODE_SET_ON_TIME: | |
display.set_indicator(Indicator.BELL) | |
if press: | |
alarm.sleep_memory[1] += 15 | |
if alarm.sleep_memory[1] == 60: | |
alarm.sleep_memory[1] = 0 | |
alarm.sleep_memory[0] = (alarm.sleep_memory[0] + 1) % 24 | |
alarm.sleep_memory[0] = alarm.sleep_memory[0] | |
alarm.sleep_memory[1] = alarm.sleep_memory[1] | |
display_time(alarm.sleep_memory[0], alarm.sleep_memory[1]) | |
elif mode == MODE_SET_DURATION: | |
if press: | |
if alarm.sleep_memory[2] == 12: | |
alarm.sleep_memory[2] = 1 | |
else: | |
alarm.sleep_memory[2] += 1 | |
alarm.sleep_memory[2] = alarm.sleep_memory[2] | |
display.print("{:2d} hr".format(alarm.sleep_memory[2])) | |
if lights_on: | |
display.set_indicator(Indicator.DATA) | |
lights.animate() | |
elif dt.tm_hour == alarm.sleep_memory[0] and dt.tm_min >= alarm.sleep_memory[1] and mode == 0: | |
lights.turn_on() | |
lights_on = True | |
deep_sleep_at = 1 + time.monotonic() + alarm.sleep_memory[2] * 60 * 60 | |
if isinstance(alarm.wake_alarm, alarm.time.TimeAlarm) and not lights_on: | |
deep_sleep_at = time.monotonic() | |
if time.monotonic() >= deep_sleep_at: | |
button.prepare_for_sleep() | |
lights.prepare_for_sleep() | |
display.clear_indicator(Indicator.DATA) | |
display.set_indicator(Indicator.MOON) | |
pin_alarm = alarm.pin.PinAlarm(pin=board.BOOT0, value=False, pull=True) | |
time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + 60) | |
alarm.exit_and_deep_sleep_until_alarms(pin_alarm, time_alarm) | |
time.sleep(0.01667) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import random | |
import board | |
import neopixel | |
import time | |
from digitalio import DigitalInOut, Direction, Pull | |
NUM_PIXELS = 30 # The number of Neopixels in our Neopixel strip | |
NUM_TWINKLES = 15 # The number of active twinkles | |
MAX_TWINKLE_FRAMES = 30 | |
MIN_TWINKLE_FRAMES = 15 | |
TWINKLE_COLORS = [[255, 0, 0], # Red | |
[255, 180, 100], # Warm White | |
] | |
strip = neopixel.NeoPixel(board.D5, NUM_PIXELS, brightness=1, auto_write=False) | |
enable_lights = DigitalInOut(board.D10) | |
enable_lights.direction = Direction.OUTPUT | |
enable_lights.value = False | |
twinkles = list() | |
class Twinkle: | |
def __init__(self, location, color, frames): | |
self.location = location # pixel number on strand | |
self.color = color # color of the twinkle | |
self.frames = frames # number of frames to animate | |
self.current_frame = 0 # current frame in animation | |
self.state = 1 # 1 for starting / running, -1 for ending | |
def advance(self): | |
if self.current_frame == self.frames: | |
self.state = -1 # mark twinkle as ending | |
if self.current_frame == 0 and self.state == -1: | |
# if twinkle has ended, pick a new color / location and start again | |
self.location = random.randint(0, NUM_PIXELS - 1) | |
self.color = TWINKLE_COLORS[random.randint(0, len(TWINKLE_COLORS) - 1)] | |
self.frames = random.randint(MIN_TWINKLE_FRAMES, MAX_TWINKLE_FRAMES) | |
self.current_frame = 0 | |
self.state = 1 | |
self.current_frame = self.current_frame + self.state # advance to next frame | |
for i in range(NUM_TWINKLES): | |
location = random.randint(0, NUM_PIXELS - 1) | |
color = random.randint(1, len(TWINKLE_COLORS) - 1) | |
flash_len = random.randint(MIN_TWINKLE_FRAMES, MAX_TWINKLE_FRAMES) | |
twinkles.append(Twinkle(location, TWINKLE_COLORS[color], flash_len)) | |
def turn_on(): | |
enable_lights.value = True | |
def prepare_for_sleep(): | |
strip.deinit() | |
enable_lights.value = False | |
enable_lights.deinit() | |
def animate(): | |
for i in range(NUM_TWINKLES): | |
location = twinkles[i].location | |
brightness = (twinkles[i].current_frame/twinkles[i].frames) | |
scaled_color = (int(twinkles[i].color[0]*brightness), | |
int(twinkles[i].color[1]*brightness), | |
int(twinkles[i].color[2]*brightness)) | |
strip[location] = scaled_color | |
twinkles[i].advance() | |
strip.show() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import rtc | |
import time | |
import ssl | |
import wifi | |
import socketpool | |
import adafruit_requests | |
try: | |
from secrets import secrets | |
except ImportError: | |
print("WiFi secrets are kept in secrets.py, please add them there!") | |
raise | |
def set_time_if_needed(): | |
aio_username = secrets["aio_username"] | |
aio_key = secrets["aio_key"] | |
location = secrets.get("timezone", None) | |
TIME_URL = f"https://io.adafruit.com/api/v2/{aio_username}/integrations/time/strftime?x-aio-key={aio_key}&tz={location}&fmt=%25Y-%25m-%25d+%25H%3A%25M%3A%25S" | |
wifi.radio.connect(secrets["ssid"], secrets["password"]) | |
pool = socketpool.SocketPool(wifi.radio) | |
requests = adafruit_requests.Session(pool, ssl.create_default_context()) | |
response = requests.get(TIME_URL) | |
components = response.text.split(' ') | |
(year, month, day) = components[0].split('-') | |
(hour, minute, second) = components[1].split(':') | |
rtc.RTC().datetime = time.struct_time((int(year), int(month), int(day), int(hour), int(minute), int(second), 0, -1, -1)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This file is where you keep secret settings, passwords, and tokens! | |
# If you put them in the code you risk committing that info or sharing it | |
secrets = { | |
"ssid" : "YOUR_WIFI_NETWORK", | |
"password" : "YOUR_WIFI_PASSWORD", | |
"aio_username" : "ADAFRUIT_IO_USERNAME", | |
"aio_key" : "ADAFRUIT_IO_KEY", | |
"timezone" : "America/Chicago", # http://worldtimeapi.org/timezones | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment