import time import board import neopixel #### # Neopixel setup # Set Constants pixel_pin = board.GP5 num_pixels = 144 brightness = 0.1 # Create neopixel object named pixels pixels = neopixel.NeoPixel( pixel_pin, num_pixels, brightness=brightness, auto_write=False, pixel_order="GRBW" ) # Colors used in this script # FORMAT: (R, G, B, W) RED = (255, 0, 0, 0) YELLOW = (255, 150, 0, 0) GREEN = (0, 255, 0, 0) BLANK = (0, 0, 0, 0) # Turn all pixels off pixels.fill(BLANK) pixels.show() # END Neopixel setup #### # Set the color on a single neopixel based on colormode and # whether yellowtime or redtime has been reached. Calling # logic should iterate over every neopixel ID that should # be updated during the current update interval, and then # call pixels.show() after all pixels have been set. It's # up to the calling logic to calculate whether the yellow # or red parameters should be set to True. Behavior when # red and yellow are both set to True depends on how the # colormode is configured. def colorizer(pxnum, colormode, yellow=False, red=False): # Every pixel from lowest to currently highest if colormode == "fill": if red: pixels[pxnum] = RED elif yellow: pixels[pxnum] = YELLOW else: pixels[pxnum] = GREEN elif colormode == "candybar": if pixels[pxnum] == BLANK: if red: pixels[pxnum] = RED elif yellow: pixels[pxnum] = YELLOW else: pixels[pxnum] = GREEN else: pass else: # Invalid colormodes end up here raise Exception("Invalid colormode: " + colormode) # Count down from the given total seconds, using the chosen # colormode (how the colors are filled into each pixel), # and the given yellowtime (seconds before timer has elapsed # that the bar should show yellow), and redtime (same as # yellowtime). The colormode determines what happens at # yellowtime and redtime. def countdown( seconds, colormode="fill", yellowtime=120, redtime=60, update_interval=1): # Turn all pixels off pixels.fill(BLANK) pixels.show() # Init the update interval tracking variable last_update_time = -1 # Init the elapsed time variable elapsed_time = 0 # This begins what I like to call the "Are We There Yet?" # loop. Instead of making the script wait for an interval # before continuing as a form of forced timed pacing, we # simply write an infinite loop that will iterate very # quickly between update intervals, essentially repeatedly # asking the CPU to calculate whether it's time to do an # update yet. The high frequency of the update interval # checks will make sure our update is fired on-time. # # ...unless we decide to configure a way to kill the loop entirely, I guess...? ;) while True: # Get the current time now = time.monotonic() # Is it time for an update yet? if now >= last_update_time + update_interval: # Update the last update time last_update_time = now # Do update stuff # Loop over every pixel ID that should be lit # based on the elapsed time for pixel in range(round(num_pixels * (elapsed_time / seconds))): # Set pixel color stuff if elapsed_time >= seconds - redtime: colorizer(pixel, colormode, red=True) elif elapsed_time >= seconds - yellowtime: colorizer(pixel, colormode, yellow=True) else: colorizer(pixel, colormode) # Display the result IRL pixels.show() # Increment the elapsed time variable elapsed_time += update_interval