audio-reactive-led-strip/python/led.py

120 lines
4.0 KiB
Python
Raw Normal View History

from __future__ import print_function
from __future__ import division
2017-01-05 11:41:04 +01:00
import platform
import numpy as np
import config
# ESP8266 uses WiFi communication
if config.DEVICE == 'esp8266':
import socket
_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Raspberry Pi controls the LED strip directly
elif config.DEVICE == 'pi':
import neopixel
strip = neopixel.Adafruit_NeoPixel(config.N_PIXELS, config.LED_PIN,
config.LED_FREQ_HZ, config.LED_DMA,
config.LED_INVERT, config.BRIGHTNESS)
strip.begin()
_gamma = np.load(config.GAMMA_TABLE_PATH)
"""Gamma lookup table used for nonlinear brightness correction"""
_prev_pixels = np.tile(253, (3, config.N_PIXELS))
"""Pixel values that were most recently displayed on the LED strip"""
pixels = np.tile(1, (3, config.N_PIXELS))
"""Pixel values for the LED strip"""
def _update_esp8266():
"""Sends UDP packets to ESP8266 to update LED strip values
The ESP8266 will receive and decode the packets to determine what values
to display on the LED strip. The communication protocol supports LED strips
with a maximum of 256 LEDs.
The packet encoding scheme is:
|i|r|g|b|
where
i (0 to 255): Index of LED to change (zero-based)
r (0 to 255): Red value of LED
g (0 to 255): Green value of LED
b (0 to 255): Blue value of LED
"""
global pixels, _prev_pixels
# Truncate values and cast to integer
pixels = np.clip(pixels, 0, 255).astype(int)
# Optionally apply gamma correctio
p = _gamma[pixels] if config.SOFTWARE_GAMMA_CORRECTION else np.copy(pixels)
# Send UDP packets when using ESP8266
2017-01-05 11:41:04 +01:00
is_python_2 = int(platform.python_version_tuple()[0]) == 2
m = '' if is_python_2 else []
for i in range(config.N_PIXELS):
# Ignore pixels if they haven't changed (saves bandwidth)
if np.array_equal(p[:, i], _prev_pixels[:, i]):
continue
2017-01-05 11:41:04 +01:00
if is_python_2:
m += chr(i) + chr(p[0][i]) + chr(p[1][i]) + chr(p[2][i])
else:
m.append(i) # Index of pixel to change
m.append(p[0][i]) # Pixel red value
m.append(p[1][i]) # Pixel green value
m.append(p[2][i]) # Pixel blue value
m = m if is_python_2 else bytes(m)
_sock.sendto(m, (config.UDP_IP, config.UDP_PORT))
_prev_pixels = np.copy(p)
def _update_pi():
"""Writes new LED values to the Raspberry Pi's LED strip
Raspberry Pi uses the rpi_ws281x to control the LED strip directly.
This function updates the LED strip with new values.
"""
global pixels, _prev_pixels
# Truncate values and cast to integer
pixels = np.clip(pixels, 0, 255).astype(long)
# Optional gamma correction
p = _gamma[pixels] if config.SOFTWARE_GAMMA_CORRECTION else np.copy(pixels)
# Encode 24-bit LED values in 32 bit integers
r = np.left_shift(p[0][:].astype(int), 8)
g = np.left_shift(p[1][:].astype(int), 16)
b = p[2][:].astype(int)
rgb = np.bitwise_or(np.bitwise_or(r, g), b)
# Update the pixels
for i in range(config.N_PIXELS):
# Ignore pixels if they haven't changed (saves bandwidth)
if np.array_equal(p[:, i], _prev_pixels[:, i]):
continue
strip._led_data[i] = rgb[i]
_prev_pixels = np.copy(p)
strip.show()
def update():
"""Updates the LED strip values"""
if config.DEVICE == 'esp8266':
_update_esp8266()
elif config.DEVICE == 'pi':
_update_pi()
else:
raise ValueError('Invalid device selected')
# Execute this file to run a LED strand test
# If everything is working, you should see a red, green, and blue pixel scroll
# across the LED strip continously
if __name__ == '__main__':
import time
# Turn all pixels off
pixels *= 0
pixels[0, 0] = 255 # Set 1st pixel red
pixels[1, 1] = 255 # Set 2nd pixel green
pixels[2, 2] = 255 # Set 3rd pixel blue
print('Starting LED strand test')
while True:
pixels = np.roll(pixels, 1, axis=1)
update()
2017-01-05 11:41:04 +01:00
time.sleep(1)