# moving rainbow
from machine import Pin
from neopixel import NeoPixel
from utime import sleep, ticks_ms
from urandom import randint
NEOPIXEL_PIN = 0
NUMBER_PIXELS = 30
RAINBOW_LENGTH = 7
PERCENT_SMALL_COLOR_WHEEL = round(255/RAINBOW_LENGTH)
PERCENT_COLOR_WHEEL = round(255/NUMBER_PIXELS)
strip = NeoPixel(Pin(NEOPIXEL_PIN), NUMBER_PIXELS)
BUTTON_PIN_1 = 15
BUTTON_PIN_2 = 14
button_presses = 0 # the count of times the button has been pressed
last_time = 0 # the last time we pressed the button
builtin_led = machine.Pin(25, Pin.OUT)
# The lower left corner of the Pico has a wire that goes through the buttons upper left and the lower right goes to the 3.3 rail
button1 = machine.Pin(BUTTON_PIN_1, machine.Pin.IN, machine.Pin.PULL_DOWN)
button2 = machine.Pin(BUTTON_PIN_2, machine.Pin.IN, machine.Pin.PULL_DOWN)
red = (255, 0, 0)
red_med = (32, 0, 0)
red_light = (8, 0, 0)
off = (0, 0, 0)
orange = (140, 60, 0)
yellow = (255, 255, 0)
green = (0, 255, 0)
blue = (0, 0, 255)
cyan = (0, 255, 255)
indigo = (75, 0, 130)
violet = (138, 43, 226)
white = (128, 128, 128)
colors = (red, orange, yellow, green, blue, cyan, indigo, violet)
color_count = len(colors)
levels = [255, 128, 64, 32, 16, 8, 4, 2, 1]
level_count = len(levels)
mode_list = ['moving rainbow', 'moving red dot', 'moving blue dot', 'moving green dot',
'red commet', 'blue commet', 'green commet', 'candle flicker', 'random dots', 'bounce',
'running lights', 'rainbow cycle', 'cylon scanner']
mode_count = 16 # len(mode_list)
# This function gets called every time the button is pressed. The parameter "pin" is used to tell
# which pin is used
def button_pressed_handler(pin):
global mode, last_time
new_time = ticks_ms()
# if it has been more that 1/5 of a second since the last event, we have a new event
if (new_time - last_time) > 200:
# print(pin)
# this is a hack but I can't get the pin ID parameter without vars() or attr()
pin_num = int(str(pin)[4:6])
# this works as long as one of the buttons is this one
if pin_num == BUTTON_PIN_1:
mode +=1
else:
mode -=1
# wrap around if we get too high
mode = mode % mode_count
last_time = new_time
# now we register the handler function when the button is pressed
button1.irq(trigger=machine.Pin.IRQ_FALLING, handler = button_pressed_handler)
button2.irq(trigger=machine.Pin.IRQ_FALLING, handler = button_pressed_handler)
def wheel(pos):
# Input a value 0 to 255 to get a color value.
# The colors are a transition r - g - b - back to r.
if pos < 0 or pos > 255:
return (0, 0, 0)
if pos < 85:
return (255 - pos * 3, pos * 3, 0)
if pos < 170:
pos -= 85
return (0, 255 - pos * 3, pos * 3)
pos -= 170
return (pos * 3, 0, 255 - pos * 3)
# erase the entire strip
def erase():
for i in range(0, NUMBER_PIXELS):
strip[i] = (0,0,0)
strip.write()
def move_dot(counter, color, delay):
strip[counter] = color
strip.write()
sleep(delay)
strip[counter] = (0,0,0)
def comet_tail(counter, color, delay):
for i in range(0, color_count):
# we start to draw at the head of the commet N levels away from the counter
target = ((level_count - i - 1) + counter) % NUMBER_PIXELS
# number to scale by
scale = (levels[i] / 255)
strip[target] = (int(color[0]*scale), int(color[1]*scale), int(color[2]*scale))
# erase the tail
if counter > 0:
strip[counter-1] = (0,0,0)
if counter == NUMBER_PIXELS-1:
strip[counter] = (0,0,0)
strip.write()
sleep(delay)
def moving_rainbow(counter, delay):
for i in range(0, RAINBOW_LENGTH-1):
color_index = round(i*PERCENT_SMALL_COLOR_WHEEL)
color = wheel(color_index)
# print(color_index, color)
# start at the end and subtract to go backwards and add the counter for offset
index = RAINBOW_LENGTH-1 - i + counter
# print(index)
if index < NUMBER_PIXELS:
strip[index] = color
strip.write()
# erase the tail if we are not at the start
if counter > 0:
strip[counter-1] = (0,0,0)
strip.write()
# turn off the last pixel at the top
if counter == NUMBER_PIXELS-1:
strip[counter] = (0,0,0)
sleep(delay)
def candle(delay):
green = 50 + randint(0,155)
red = green + randint(0,50)
strip[randint(0,NUMBER_PIXELS - 1)] = (red, green, 0)
strip.write()
sleep(delay)
def random_color(delay):
random_offset = randint(0, NUMBER_PIXELS-1)
random_color = randint(0, 255)
strip[random_offset] = wheel(random_color)
strip.write()
sleep(delay)
def random_red_white_blue(delay):
for i in range(0,10):
random_offset = randint(0, NUMBER_PIXELS-1)
random_color = randint(0, 3)
if random_color < 1:
strip[random_offset] = red
elif random_color < 2:
strip[random_offset] = white
elif random_color < 3:
strip[random_offset] = blue
strip.write()
sleep(delay)
HALF_LENGTH = round(NUMBER_PIXELS/2)
def bounce(counter, color, delay):
if counter < HALF_LENGTH:
strip[counter] = color
strip[NUMBER_PIXELS-1 - counter] = color
strip.write()
strip[counter] = (0,0,0)
strip[NUMBER_PIXELS-1 - counter] = (0,0,0)
sleep(delay)
else:
half_counter = counter - HALF_LENGTH
strip[HALF_LENGTH - half_counter] = color
strip[HALF_LENGTH + half_counter] = color
strip.write()
strip[HALF_LENGTH - half_counter] = (0,0,0)
strip[HALF_LENGTH + half_counter] = (0,0,0)
sleep(delay)
def running_lights(counter, color, spacing, delay):
for i in range(0, NUMBER_PIXELS):
if (counter+i) % spacing:
strip[i] = (0,0,0)
else:
strip[i] = color
strip.write()
sleep(delay)
def rainbow_cycle(counter, delay):
for i in range(0, NUMBER_PIXELS):
color_index = round(i*PERCENT_COLOR_WHEEL)
color = wheel(color_index)
# print(color_index, color)
strip[(i + counter) % NUMBER_PIXELS] = color
strip.write()
sleep(delay)
# 0=fwd, 1=rev
state = 0
def cylon_scanner(delay):
global counter, state
if state == 0:
#print('going forward', counter)
strip[counter] = red_light
strip[counter+1] = red_med
strip[counter+2] = red
strip[counter+3] = red_med
strip[counter+4] = red_light
# erase the tail
if counter > 0: strip[counter-1] = off
strip.write()
sleep(delay)
# reverse direction
if counter == NUMBER_PIXELS-5:
state = 1
counter = 0
#print('go to reverse', state)
return
else:
i = NUMBER_PIXELS-counter - 5
#print('in reverse c=', counter, 'i=', i)
strip[i] = red_light
strip[i+1] = red_med
strip[i+2] = red
strip[i+3] = red_med
strip[i+4] = red_light
strip.write()
sleep(delay)
# turn off as we move in reverse
if i < NUMBER_PIXELS-2:
strip[i+4] = off
if i == NUMBER_PIXELS - 6:
strip[NUMBER_PIXELS-1] = off
if i == 0:
state = 0
counter = 0
#print('switching to forward', counter)
# Global variables
mode = 0
counter = 0
last_mode = 1
delay = .05
while True:
# print only on change
if mode != last_mode:
# print('mode=', mode, 'running program', mode_list[mode])
last_mode = mode
if mode == 0:
moving_rainbow(counter, delay)
elif mode == 1:
move_dot(counter, red, delay)
elif mode == 2:
move_dot(counter, white, delay)
elif mode == 3:
move_dot(counter, blue, delay)
elif mode == 4:
comet_tail(counter, red, .005)
elif mode == 5:
comet_tail(counter, white, .005)
elif mode == 6:
comet_tail(counter, blue, .005)
elif mode == 8:
random_red_white_blue(.01)
elif mode == 9:
bounce(counter, red, .10)
elif mode == 10:
bounce(counter, white, .10)
elif mode == 11:
bounce(counter, blue, .10)
elif mode == 12:
running_lights(counter, red, 4, .2)
elif mode == 13:
running_lights(counter, white, 4, .2)
elif mode == 14:
running_lights(counter, blue, 4, .2)
elif mode == 15:
rainbow_cycle(counter, .05)
elif mode == 16:
cylon_scanner(.05)
else:
print('mode', mode, 'not configured')
counter += 1
# wrap the counter using modulo
if counter == NUMBER_PIXELS:
counter = counter % NUMBER_PIXELS
mode += 1
if mode == 16:
mode = 0