Skip to content

Instantly share code, notes, and snippets.

@kbeyer
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kbeyer/faf5acdba8a54a21ea32 to your computer and use it in GitHub Desktop.
Save kbeyer/faf5acdba8a54a21ea32 to your computer and use it in GitHub Desktop.
Driver for the RPi-LPD8806 library to enable use of WS2801 chipset
#!/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()
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()
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
@kbeyer
Copy link
Author

kbeyer commented Jul 23, 2014

These files should be placed in the /raspledstrip folder of https://github.com/adammhaile/RPi-LPD8806

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment