Permalink
Browse files

Updated HSV handling

  • Loading branch information...
1 parent 4575816 commit 6b813feb5d4630cd4b6364aaae133ac16e88380c @adammhaile committed Oct 6, 2012
Showing with 181 additions and 241 deletions.
  1. +85 −103 LPD8806.py
  2. +95 −13 example.py
  3. +0 −62 fade.py
  4. +1 −2 off.py
  5. +0 −61 test.py
View
@@ -1,5 +1,6 @@
#!/usr/bin/env python
import colorsys
+import math
"""
LPD8806.py: Raspberry Pi library for LPD8806 based RGB light strips
@@ -20,7 +21,7 @@
Example:
>> import LPD8806
- >> led = LPD8806.strand()
+ >> led = LPD8806.LEDStrip()
>> led.fill(255, 0, 0)
"""
@@ -33,54 +34,57 @@ class ChannelOrder:
GRB = [1,0,2] #Strands from Adafruit and some others (default)
BRG = [1,2,0] #Strands from many other manufacturers
+#Main color object used by all methods
class Color:
- def __init__(self):
- self.R = 0.0
- self.G = 0.0
- self.B = 0.0
- self.H = 0.0
- self.S = 1.0
- self.V = 1.0
-
- def setRGB(self, r, g, b):
+ def __init__(self, r=0.0, g=0.0, b=0.0, bright=1.0):
if(r > 255.0 or r < 0.0 or g > 255.0 or g < 0.0 or b > 255.0 or b < 0.0):
raise ValueError('RGB values must be between 0 and 255')
- self.R = float(r)
- self.G = float(g)
- self.B = float(b)
- h, s, v = colorsys.rgb_to_hsv((float(r)/255.0), (float(g)/255.0), (float(b)/255.0))
- self.H = h
- self.S = s
- self.V = v
+ if(bright > 1.0 or bright < 0.0):
+ raise ValueError('Brightness must be between 0.0 and 1.0')
+ self.R = r * bright
+ self.G = g * bright
+ self.B = b * bright
+
+ #gets ColorHSV object
+ def getColorHSV(self):
+ h, s, v = colorsys.rgb_to_hsv(self.R / 255.0, self.G / 255.0, self.B / 255.0)
+ return ColorHSV(h, s, v)
+
+ def __str__( self ):
+ return "%d,%d,%d" % (self.R, self.G, self.B)
- def setHSV(self, h, s, v):
+#useful for natural color transitions. Increment huge to sweep through the colors
+#must call getColorRGB() before passing to any of the methods
+class ColorHSV:
+ def __init__(self, h=360.0, s=1.0, v=1.0):
if(h > 360.0 or h < 0.0):
raise ValueError('Hue value must be between 0.0 and 360.0')
if(s > 1.0 or s < 0.0):
raise ValueError('Saturation must be between 0.0 and 1.0')
if(v > 1.0 or v < 0.0):
raise ValueError('Value must be between 0.0 and 1.0')
- r, g, b = colorsys.hsv_to_rgb(h / 360.0, s, v)
- self.R = r * 255.0
- self.G = g * 255.0
- self.B = b * 255.0
+
self.H = h
self.S = s
self.V = v
+
+ #gets Color object (RGB)
+ def getColorRGB(self):
+ r, g, b = colorsys.hsv_to_rgb(self.H / 360.0, self.S, self.V)
+ return Color(r * 255.0, g * 255.0, b * 255.0)
- def setHue(self, hue):
- self.setHSV(hue, self.S, self.V)
+ def __str__( self ):
+ return "%0.2f,%0.2f,%0.2f" % (self.H, self.S, self.V)
-class strand:
+class LEDStrip:
def __init__(self, leds, dev="/dev/spidev0.0"):
#Variables:
# leds -- strand size
# dev -- spi device
- self.auto_update = False
self.c_order = ChannelOrder.GRB
self.dev = dev
self.spi = file(self.dev, "wb")
@@ -89,15 +93,18 @@ def __init__(self, leds, dev="/dev/spidev0.0"):
self.gamma = bytearray(256)
self.buffer = [0 for x in range(self.leds + 1)]
+ self.masterBrightness = 1.0
+
#anim step vars
self.wheelStep = 0
self.rainbowStep = 0
self.rainbowCycleStep = 0
self.wipeStep = 0
self.chaseStep = 0
self.larsonStep = 0
- self.larsonDir = 0
+ self.larsonDir = -1
self.larsonLast = 0
+ self.waveStep = 0
for led in range(self.leds):
self.buffer[led] = bytearray(3)
@@ -112,24 +119,20 @@ def __init__(self, leds, dev="/dev/spidev0.0"):
def setChannelOrder(self, order):
self.c_order = order
- #When true state change methods will not wait for update() to push the changes
- def setAutoUpdate(self, state=True):
- self.auto_update = state
+ #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
#Push new data to strand
- #Not needed if Auto Update is enaabled
def update(self):
for x in range(self.leds):
self.spi.write(self.buffer[x])
self.spi.flush()
self.spi.write(bytearray(b'\x00'))
self.spi.flush()
- #update if autoUpdate is True
- def __auto_update(self):
- if self.auto_update == True:
- self.update()
-
#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:
@@ -139,72 +142,59 @@ def fill(self, color, start=0, end=0):
for led in range(start, end + 1): #since 0-index include end in range
self.__set_internal(led, color)
- self.__auto_update()
-
#Fill the strand (or a subset) with a single color using RGB values
def fillRGB(self, r, g, b, start=0, end=0):
- color = Color()
- color.setRGB(r, g, b)
- self.fill(color, start, end)
+ 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):
- color = Color()
- color.setHSV(h, s, v)
- self.fill(color, start, end)
+ self.fill(ColorHSV(h, s, v).getColorRGB(), 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):
- color = Color()
- color.setHSV(hue, 1.0, 1.0)
- self.fill(color, start, end)
+ self.fill(ColorHSV(hue).getColorRGB(), 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):
- self.buffer[pixel][self.c_order[0]] = self.gamma[int(color.R)]
- self.buffer[pixel][self.c_order[1]] = self.gamma[int(color.G)]
- self.buffer[pixel][self.c_order[2]] = self.gamma[int(color.B)]
+ 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)
- self.__auto_update()
-
#Set single pixel to RGB value
def setRGB(self, pixel, r, g, b):
- color = Color()
- color.setRGB(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):
- color = Color()
- color.setHSV(h, s, v)
- self.set(pixel, color)
+ self.set(pixel, ColorHSV(h, s, v).getColorRGB())
#Set single pixel to Hue value.
#Saturation and Value components of HSV are set to max.
def setHue(self, pixel, hue):
- color = Color()
- color.setHSV(hue, 1.0, 1.0)
- self.set(pixel, color)
+ self.set(pixel, ColorHSV(hue).getColorRGB())
#turns off the desired pixel
def setOff(self, pixel):
self.setRGB(pixel, 0, 0, 0)
#Turn all LEDs off.
def all_off(self):
- auto = self.auto_update
- self.setAutoUpdate(True)
- self.fillRGB(0,0,0)
- self.fillRGB(0,0,0)
- self.setAutoUpdate(auto)
+ self.fillOff()
+ self.update()
+ self.fillOff()
+ self.update()
#Get color from wheel value (0 - 384)
def wheel_color(self, wheelpos):
@@ -226,8 +216,7 @@ def wheel_color(self, wheelpos):
r = wheelpos % 128
g = 0
- color = Color()
- color.setRGB(r, g, b)
+ color = Color(r, g, b)
return color
#generate rainbow
@@ -236,15 +225,11 @@ def anim_rainbow(self, start=0, end=0):
end = self.lastIndex
size = end - start + 1
- auto = self.auto_update
- self.setAutoUpdate(False)
for i in range(size):
color = (i + self.rainbowStep) % 384
c = self.wheel_color(color)
self.set(start + i, c)
- self.setAutoUpdate(auto)
- self.__auto_update()
self.rainbowStep += 1
if self.rainbowStep > 384:
self.rainbowStep = 0
@@ -255,15 +240,11 @@ def anim_rainbow_cycle(self, start=0, end=0):
end = self.lastIndex
size = end - start + 1
- auto = self.auto_update
- self.setAutoUpdate(False)
for i in range(size):
color = (i * (384 / size) + self.rainbowCycleStep) % 384
c = self.wheel_color(color)
self.set(start + i, c)
- self.setAutoUpdate(auto)
-
- self.__auto_update()
+
self.rainbowCycleStep += 1
if self.rainbowCycleStep > 384:
self.rainbowCycleStep = 0
@@ -273,15 +254,11 @@ def anim_color_wipe(self, color, start=0, end=0):
if end == 0 or end > self.lastIndex:
end = self.lastIndex
- auto = self.auto_update
- self.setAutoUpdate(False)
if(self.wipeStep == 0):
self.fillOff()
self.set(start + self.wipeStep, color)
- self.setAutoUpdate(auto)
- self.__auto_update()
self.wipeStep += 1
if start + self.wipeStep > end:
self.wipeStep = 0
@@ -291,18 +268,13 @@ def anim_color_chase(self, color, start=0, end=0):
if end == 0 or end > self.lastIndex:
end = self.lastIndex
- auto = self.auto_update
- self.setAutoUpdate(False)
- #self.fillOff()
if(self.chaseStep == 0):
self.setOff(end)
else:
self.setOff(start + self.chaseStep - 1)
self.set(start + self.chaseStep, color)
- self.setAutoUpdate(auto)
-
- self.__auto_update()
+
self.chaseStep += 1
if start + self.chaseStep > end:
self.chaseStep = 0
@@ -311,15 +283,12 @@ def anim_color_chase(self, color, start=0, end=0):
def anim_larson_scanner(self, color, tail=2, fade=0.75, start=0, end=0):
if end == 0 or end > self.lastIndex:
end = self.lastIndex
- size = end - start
+ size = end - start + 1
tail += 1 #makes tail math later easier
if tail >= size / 2:
tail = (size / 2) - 1
- auto = self.auto_update
- self.setAutoUpdate(False)
-
self.larsonLast = start + self.larsonStep;
self.set(self.larsonLast, color)
@@ -345,29 +314,42 @@ def anim_larson_scanner(self, color, tail=2, fade=0.75, start=0, end=0):
if(self.larsonLast - tr - 1 >= start):
self.setOff(self.larsonLast - tr - 1)
- self.setAutoUpdate(auto)
- self.__auto_update()
-
if start + self.larsonStep == end:
- self.larsonDir = 1
+ self.larsonDir = -self.larsonDir
elif self.larsonStep == 0:
- self.larsonDir = 0
+ self.larsonDir = -self.larsonDir
- if self.larsonDir == 0:
- self.larsonStep += 1
- else:
- self.larsonStep -= 1
+ self.larsonStep += self.larsonDir
#larson scanner (i.e. Cylon Eye or K.I.T.T.) but Rainbow
def anim_larson_rainbow(self, tail=2, fade=0.75, start=0, end=0):
if end == 0 or end > self.lastIndex:
end = self.lastIndex
- size = end - start
+ size = end - start + 1
hue = (self.larsonStep * (360 / size))
- color = Color()
- color.setHue(hue)
- self.anim_larson_scanner(color, tail, fade, start, end)
+ self.anim_larson_scanner(ColorHSV(hue).getColorRGB(), tail, fade, start, end)
+
+ #Sine wave animation
+ PI = 3.14159265
+ def anim_wave(self, color, cycles, start=0, end=0):
+ if end == 0 or end > self.lastIndex:
+ end = self.lastIndex
+ size = end - start + 1
+ c2 = Color()
+ for i in range(size):
+ y = math.sin(self.PI * float(cycles) * float(self.waveStep * i) / float(size))
+ if(y >= 0.0):
+ #Peaks of sine wave are white
+ y = 1.0 - y #Translate Y to 0.0 (top) to 1.0 (center)
+ c2 = Color(255 - float(255 - color.R) * y, 255 - float(255 - color.G) * y, 255 - float(255 - color.B) * y)
+ else:
+ #Troughs of sine wave are black
+ y += 1.0 #Translate Y to 0.0 (bottom) to 1.0 (center)
+ c2 = Color(float(color.R) * y, float(color.G) * y, float(color.B) * y)
+ self.set(start + i, c2)
+
+ self.waveStep += 1
Oops, something went wrong.

0 comments on commit 6b813fe

Please sign in to comment.