from __future__ import print_function from __future__ import division from __future__ import unicode_literals 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 m = [] 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 # Byte 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 _prev_pixels = np.copy(p) _sock.sendto(bytes(m), (config.UDP_IP, config.UDP_PORT)) 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() time.sleep(0.01)