Adafruit_Learning_System_Gu.../ESP8266_MicroPython_Holiday_Lights/lights.py
2018-12-20 11:16:42 -06:00

106 lines
3.3 KiB
Python
Executable file

# ESP8266 MicroPython smart holiday lights project code.
# This will animate NeoPixels that can be controlled from the included
# lights.html web page.
# Author: Tony DiCola
# License: MIT License
import machine
import neopixel
import utime
import ujson
# Static configuration that never changes:
PIXEL_PIN = machine.Pin(15, machine.Pin.OUT) # Pin connected to the NeoPixels.
PIXEL_COUNT = 32 # Number of NeoPixels.
CONFIG_FILE = 'config.json' # Name of animation config file.
# Mirror the colors to make a ramp up and ramp down with no repeated colors.
def mirror(values):
# Add the input values in reverse order to the end of the array.
# However slice off the very first and very last items (the [1:-1] syntax)
# to prevent the first and last values from repeating.
# For example an input of:
# [1, 2, 3]
# Returns:
# [1, 2, 3, 2]
# Instead of returning:
# [1, 2, 3, 3, 2, 1]
# Which would duplicate 3 and 1 as you loop through the elements.
values.extend(list(reversed(values))[1:-1])
return values
# Linear interpolation helper:
def _lerp(x, x0, x1, y0, y1):
return y0 + (x - x0) * ((y1 - y0)/(x1 - x0))
# Animation functions:
def blank(config, np, pixel_count):
# Turn off all the pixels.
np.fill((0,0,0))
np.write()
def solid(config, np, pixel_count):
# Solid pulse of all pixels at the same color.
colors = config['colors']
elapsed = utime.ticks_ms() // config['period_ms']
current = elapsed % len(colors)
np.fill(colors[current])
np.write()
def chase(config, np, pixel_count):
# Chasing animation of pixels through different colors.
colors = config['colors']
elapsed = utime.ticks_ms() // config['period_ms']
for i in range(PIXEL_COUNT):
current = (elapsed+i) % len(colors)
np[i] = colors[current]
np.write()
def smooth(config, np, pixel_count):
# Smooth pulse of all pixels at the same color. Interpolates inbetween colors
# for smoother animation.
colors = config['colors']
period_ms = config['period_ms']
ticks = utime.ticks_ms()
step = ticks // period_ms
offset = ticks % period_ms
color0 = colors[step % len(colors)]
color1 = colors[(step+1) % len(colors)]
color = (int(_lerp(offset, 0, period_ms, color0[0], color1[0])),
int(_lerp(offset, 0, period_ms, color0[1], color1[1])),
int(_lerp(offset, 0, period_ms, color0[2], color1[2])))
np.fill(color)
np.write()
# Setup code:
# Initialize NeoPixels and turn them off.
np = neopixel.NeoPixel(PIXEL_PIN, PIXEL_COUNT)
np.fill((0,0,0))
np.write()
# Try loading the animation configuration, otherwise fall back to a blank default.
try:
with open(CONFIG_FILE, 'r') as infile:
config = ujson.loads(infile.read())
except OSError:
# Couldn't load the config file, so fall back to a default blank animation.
config = {
'colors': [[0,0,0]],
'mirror_colors': False,
'period_ms': 250,
'animation': 'blank'
}
# Mirror the color array if necessary.
if config['mirror_colors']:
config['colors'] = mirror(config['colors'])
# Determine which animation function should be called.
animation = globals().get(config['animation'], blank)
# Main loop code:
while True:
animation(config, np, PIXEL_COUNT)
utime.sleep(0.01)