Last active
August 29, 2015 14:04
-
-
Save kbeyer/faf5acdba8a54a21ea32 to your computer and use it in GitHub Desktop.
Driver for the RPi-LPD8806 library to enable use of WS2801 chipset
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
from color import Color, ColorHSV | |
from LPD8806 import LPD8806 | |
from WS2801 import WS2801 | |
#Not all LPD8806 strands are created equal. | |
#Some, like Adafruit's use GRB order and the other common order is GRB | |
#Library defaults to GRB but you can call strand.setChannelOrder(ChannelOrder) | |
#to set the order your strands use | |
class ChannelOrder: | |
RGB = [0,1,2] #Probably not used, here for clarity | |
GRB = [1,0,2] #Strands from Adafruit and some others (default) | |
BRG = [1,2,0] #Strands from many other manufacturers | |
class LEDStrip: | |
def __init__(self, leds, use_py_spi = True, dev="/dev/spidev0.0", driver="WS2801"): | |
#Variables: | |
# leds -- strand size | |
# dev -- spi device | |
if(driver == "WS2801"): | |
self.driver = WS2801(leds, use_py_spi, dev) | |
else: | |
#no alternate drivers for now. Here so they can be added later | |
self.driver = LPD8806(leds, use_py_spi, dev) | |
self.c_order = self.driver.channelOrder() | |
self.leds = leds | |
self.lastIndex = self.leds - 1 | |
self.gamma = bytearray(256) | |
self.buffer = [0 for x in range(self.leds + 1)] | |
self.masterBrightness = 1.0 | |
for led in range(self.leds): | |
self.buffer[led] = bytearray(3) | |
self.gamma = self.driver.gamma() | |
def update(self): | |
self.driver.update(self.buffer) | |
#Allows for easily using LED strands with different channel orders | |
def setChannelOrder(self, order): | |
self.c_order = order | |
#Set the master brightness for the LEDs 0.0 - 1.0 | |
def setMasterBrightness(self, bright): | |
if(bright > 1.0 or bright < 0.0): | |
raise ValueError('Brightness must be between 0.0 and 1.0') | |
self.masterBrightness = bright | |
#Fill the strand (or a subset) with a single color using a Color object | |
def fill(self, color, start=0, end=0): | |
if start < 0: | |
start = 0 | |
if end == 0 or end > self.lastIndex: | |
end = self.lastIndex | |
for led in range(start, end + 1): #since 0-index include end in range | |
self.__set_internal(led, color) | |
#Fill the strand (or a subset) with a single color using RGB values | |
def fillRGB(self, r, g, b, start=0, end=0): | |
self.fill(Color(r, g, b), start, end) | |
#Fill the strand (or a subset) with a single color using HSV values | |
def fillHSV(self, h, s, v, start=0, end=0): | |
self.fill(ColorHSV(h, s, v).get_color_rgb(), start, end) | |
#Fill the strand (or a subset) with a single color using a Hue value. | |
#Saturation and Value components of HSV are set to max. | |
def fillHue(self, hue, start=0, end=0): | |
self.fill(ColorHSV(hue).get_color_rgb(), start, end) | |
def fillOff(self, start=0, end=0): | |
self.fillRGB(0, 0, 0, start, end) | |
#internal use only. sets pixel color | |
def __set_internal(self, pixel, color): | |
if(pixel < 0 or pixel > self.lastIndex): | |
return; #don't go out of bounds | |
self.buffer[pixel][self.c_order[0]] = self.gamma[int(color.r * self.masterBrightness)] | |
self.buffer[pixel][self.c_order[1]] = self.gamma[int(color.g * self.masterBrightness)] | |
self.buffer[pixel][self.c_order[2]] = self.gamma[int(color.b * self.masterBrightness)] | |
#Set single pixel to Color value | |
def set(self, pixel, color): | |
self.__set_internal(pixel, color) | |
#Set single pixel to RGB value | |
def setRGB(self, pixel, r, g, b): | |
color = Color(r, g, b) | |
self.set(pixel, color) | |
#Set single pixel to HSV value | |
def setHSV(self, pixel, h, s, v): | |
self.set(pixel, ColorHSV(h, s, v).get_color_rgb()) | |
#Set single pixel to Hue value. | |
#Saturation and Value components of HSV are set to max. | |
def setHue(self, pixel, hue): | |
self.set(pixel, ColorHSV(hue).get_color_rgb()) | |
#turns off the desired pixel | |
def setOff(self, pixel): | |
self.setRGB(pixel, 0, 0, 0) | |
#Turn all LEDs off. | |
def all_off(self): | |
self.fillOff() | |
self.update() | |
self.fillOff() | |
self.update() | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class LPD8806(object): | |
"""Main driver for LPD8806 based LED strips""" | |
def __init__(self, leds, use_py_spi = False, dev="/dev/spidev0.0"): | |
self.leds = leds | |
self.dev = dev | |
self.use_py_spi = use_py_spi | |
if self.use_py_spi: | |
import spidev | |
self.spi = spidev.SpiDev() | |
self.spi.open(0,0) | |
self.spi.max_speed_hz = 16000000 | |
print 'py-spidev MHz: %d' % (self.spi.max_speed_hz / 1000000.0 ) | |
else: | |
self.spi = open(self.dev, "wb") | |
#define channel order for this chip | |
def channelOrder(*arg): | |
return [1,0,2] #GRB - Strands from Adafruit and some others (default) | |
#define gamma for this chip | |
def gamma(*arg): | |
gamma = bytearray(256) | |
for i in range(256): | |
# Color calculations from | |
# http://learn.adafruit.com/light-painting-with-raspberry-pi | |
gamma[i] = 0x80 | int( | |
pow(float(i) / 255.0, 2.5) * 127.0 + 0.5 | |
) | |
return gamma | |
#Push new data to strand | |
def update(self, buffer): | |
temp_buffer = [] | |
if self.use_py_spi: | |
for x in range(self.leds): | |
temp_buffer = temp_buffer + [i for i in buffer[x]] | |
self.spi.xfer2(temp_buffer) | |
self.spi.xfer2([0x00,0x00,0x00]) #zero fill the last to prevent stray colors at the end | |
self.spi.xfer2([0x00]) #once more with feeling - this helps :) | |
else: | |
for x in range(self.leds): | |
self.spi.write(buffer[x]) | |
self.spi.flush() | |
#seems that the more lights we have the more you have to push zeros | |
#not 100% sure why this is yet, but it seems to work | |
self.spi.write(bytearray(b'\x00\x00\x00')) #zero fill the last to prevent stray colors at the end | |
self.spi.flush() | |
self.spi.write(bytearray(b'\x00\x00\x00')) | |
self.spi.flush() | |
self.spi.write(bytearray(b'\x00\x00\x00')) | |
self.spi.flush() | |
self.spi.write(bytearray(b'\x00\x00\x00')) | |
self.spi.flush() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class WS2801(object): | |
"""Main driver for WS2801 based LED strips""" | |
def __init__(self, leds, use_py_spi = True, dev="/dev/spidev0.0"): | |
self.leds = leds | |
self.dev = dev | |
self.use_py_spi = use_py_spi | |
if self.use_py_spi: | |
import spidev | |
self.spi = spidev.SpiDev() | |
self.spi.open(0,1) | |
self.spi.max_speed_hz = 2000000 | |
print 'py-spidev MHz: %d' % (self.spi.max_speed_hz / 1000000.0 ) | |
else: | |
self.spi = open(self.dev, "wb") | |
#define channel order for this chip | |
def channelOrder(*arg): | |
return [1,2,0] # BRG - Strands from many other manufacturers | |
#define gamma for this chip | |
def gamma(*arg): | |
gamma = bytearray(256) | |
for i in range(256): | |
gamma[i] = int(pow(float(i) / 255.0, 2.5) * 255.0) | |
return gamma | |
#Push new data to strand | |
def update(self, buffer): | |
temp_buffer = [] | |
if self.use_py_spi: | |
for x in range(self.leds): | |
self.spi.writebytes([int(i) for i in buffer[x]]) | |
else: | |
for x in range(self.leds): | |
self.spi.write(buffer[x]) | |
self.spi.flush() | |
print 'TEMP: %r' % (buffer[x]) | |
print 'LENGTH: %d' % (len(temp_buffer)) | |
# WS2801 requires 500 micro-second delay between writebytes | |
# for low frequencies ... this will happen implicitly | |
# for high frequencies it must be explicit |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
These files should be placed in the /raspledstrip folder of https://github.com/adammhaile/RPi-LPD8806