Scripts to control a strip of LPD8806 LEDs from a raspberry pi's GPIO

glow.py 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #!/usr/bin/python
  2. # Testing the LED lights
  3. import random
  4. import time
  5. import argparse
  6. import struct
  7. # Set up command-line operations
  8. parser = argparse.ArgumentParser(description="Make the LPD8806 LEDs glow random colors")
  9. parser.add_argument('-s', '--step', type=int, default=1,
  10. help='Amount in RGB to increase/decrease at every interval. Lower value '
  11. 'will be slower and smoother, higher will be faster but jumpier.')
  12. parser.add_argument('-i', '--interval', type=float, default=0.1,
  13. help='Time in seconds to wait between every interval (step). Lower value '
  14. 'will be slower and more jagged and jumpy, higher will be faster and smoother.')
  15. parser.add_argument('-g', '--glow_pause', type=float, default=2,
  16. help='Time in seconds to wait at maximum glow')
  17. parser.add_argument('-d', '--dim_pause', type=float, default=1,
  18. help='Time in seconds to wait while LEDs are off')
  19. parser.add_argument('-m', '--minimum', type=int, default=0,
  20. help='The minimum value to fade out to, the "dim" setting. (0 - 255)')
  21. parser.add_argument('-n', '--no_dim', action='store_true', default=False,
  22. help='Instead of fading out to a dim minimum, only pause at max glow'
  23. 'and then fade to the next random color.')
  24. parser.add_argument('-v', '--verbose', action='store_true', default=False,
  25. help='Display debug printouts of the current and target colors at every '
  26. 'sub-interval')
  27. # Set the spi file
  28. dev = "/dev/spidev0.0"
  29. # Open SPI device
  30. spidev = file(dev, "wb")
  31. # Number of LEDs in my strip
  32. height = 32
  33. # Calculate gamma correction table. This includes
  34. # LPD8806-specific conversion (7-bit color w/high bit set).
  35. gamma = bytearray(256)
  36. for i in range(256):
  37. gamma[i] = 0x80 | int(pow(float(i) / 255.0, 2.5) * 127.0 + 0.5)
  38. # Create a bytearray to display
  39. # R, G, B byte per pixel, plus extra '0' byte at end for latch.
  40. step = parser.parse_args().step
  41. interval = parser.parse_args().interval
  42. glow_pause = parser.parse_args().glow_pause
  43. dim_pause = parser.parse_args().dim_pause
  44. minimum = parser.parse_args().minimum
  45. no_dim = parser.parse_args().no_dim
  46. verbose = parser.parse_args().verbose
  47. if verbose: print "Allocating..."
  48. array = bytearray(height * 3 + 1)
  49. def test_gamma(strip, gamma):
  50. # First a test:
  51. for i, color in enumerate(gamma):
  52. print str(i) + ": " + str(color) + " (" + repr(struct.pack('>B', color)) + ")"
  53. for y in range(height):
  54. value = [0]*3
  55. y3 = y * 3
  56. strip[y3] = color
  57. strip[y3 + 1] = color
  58. strip[y3 + 2] = color
  59. spidev.write(strip)
  60. spidev.flush()
  61. time.sleep(0.5)
  62. def rgb_to_gamma(color, gamma):
  63. """Translate normal RGB colors to the first occurrence in the gamma array
  64. The LPD8806 skips over a lot of RGB colors by using the same color at many
  65. different indices. This method just takes a gamma index: color, finds what
  66. color byte the gamma array contains at that index, and then searches the
  67. array from the beginning to find the first occurrence of that color byte
  68. and returns that gamma index instead. That way, all representable colors can
  69. be reduced to the indexes in gamma that start new colors, thereby making
  70. equivalencies between colors that are actually equal a lot easier.
  71. Arguments:
  72. color -- triple tuple representing RGB respectively for the desired color
  73. gamma -- bytearray of 256 corrected colors to choose from for the LPD8806 LEDs
  74. """
  75. gamma_r = gamma.index(struct.pack('>B', gamma[color[0]]))
  76. gamma_g = gamma.index(struct.pack('>B', gamma[color[1]]))
  77. gamma_b = gamma.index(struct.pack('>B', gamma[color[2]]))
  78. return gamma_r, gamma_g, gamma_b
  79. def get_current_color(strip, gamma):
  80. """Extract gamma-indexed RBG tuple from the first LED in the strip.
  81. The strip is ordered in GRB format, but this method returns RGB. Also note
  82. that this method only checks the color of the first LED, and does not take
  83. into account the rest of the strip's colors.
  84. Arguments:
  85. strip -- bytearray of the latest written colors to the LED strip. Array is
  86. three times the length of the strip plus one for '0' byte latch.
  87. gamma -- bytearray of 256 corrected colors to choose from for the LPD8806 LEDs
  88. """
  89. gamma_r = gamma.index(struct.pack('>B', strip[1]))
  90. gamma_g = gamma.index(struct.pack('>B', strip[0]))
  91. gamma_b = gamma.index(struct.pack('>B', strip[2]))
  92. return gamma_r, gamma_g, gamma_b
  93. def fade_to_color(color, strip, gamma, step=1, interval=0.1, pause=1):
  94. """Increment/Decrement LED colors to the target color and pause.
  95. Will convert the RGB color to the gamma-indexed version internally.
  96. Arguments:
  97. color -- triple tuple representing RGB respectively for the desired color
  98. strip -- bytearray of the latest written colors to the LED strip. Array is
  99. three times the length of the strip plus one for '0' byte latch.
  100. gamma -- bytearray of 256 corrected colors to choose from for the LPD8806 LEDs
  101. Keyword Arguments:
  102. step -- amount in RGB to increment/decrement at each interval (default 1)
  103. interval -- time in seconds between each increment/decrement (default 0.1)
  104. pause -- time in seconds to wait once fade is complete (default 1)
  105. """
  106. if verbose: print "color desired: " + str(color)
  107. # Convert color to a gamma-indexed value that this method will certainly reach
  108. color = rgb_to_gamma(color, gamma)
  109. if verbose: print "gamma-indexed color: " + str(color)
  110. strip_length = (len(strip) - 1) / 3
  111. current = get_current_color(strip, gamma)
  112. counter = 0
  113. while (current != color):
  114. # Near the end of the gamma spectrum, some colors are missing, so skip over
  115. # them if they are encountered.
  116. skip_nums = [234, 235, 242, 243, 248, 249, 252, 253]
  117. skip_g = 1
  118. skip_r = 1
  119. skip_b = 1
  120. if current[1] in skip_nums: skip_g = 2
  121. if current[0] in skip_nums: skip_r = 2
  122. if current[2] in skip_nums: skip_b = 2
  123. # Fill strip with next color
  124. for y in range(strip_length):
  125. y3 = y * 3
  126. strip[y3] = gamma[current[1]] + \
  127. (cmp(color[1], current[1]) * skip_g)
  128. strip[y3 + 1] = gamma[current[0]] + \
  129. (cmp(color[0], current[0]) * skip_r)
  130. strip[y3 + 2] = gamma[current[2]] + \
  131. (cmp(color[2], current[2]) * skip_b)
  132. # Increment counter. If at next step, then write to spi and wait
  133. counter = counter + 1
  134. if counter % step == 0:
  135. spidev.write(strip)
  136. spidev.flush()
  137. time.sleep(interval)
  138. # Update the current color for the while condition comparison
  139. current = get_current_color(strip, gamma)
  140. if verbose: print str(current) + " | " + str(color)
  141. # Now write to the spi port!
  142. if verbose: print "Displaying..."
  143. # Firstly, clear the strip and set array to values that are known
  144. for y in range(height):
  145. value = [0]*3
  146. y3 = y * 3
  147. array[y3] = gamma[value[1]]
  148. array[y3 + 1] = gamma[value[0]]
  149. array[y3 + 2] = gamma[value[2]]
  150. spidev.write(array)
  151. spidev.flush()
  152. # Now, glow
  153. while True:
  154. color = tuple([random.randint(0, len(gamma)-1) for x in range(3)])
  155. # Wrap in try/except block for graceful exiting via KeyboardInterrupt
  156. try:
  157. fade_to_color(color, array, gamma, step=step,
  158. interval=interval, pause=glow_pause)
  159. time.sleep(glow_pause)
  160. if not no_dim:
  161. fade_to_color((minimum, minimum, minimum), array, gamma, step=step,
  162. interval=interval, pause=dim_pause)
  163. time.sleep(dim_pause)
  164. except KeyboardInterrupt:
  165. # Clear out array
  166. for y in range(height):
  167. value = [0]*3
  168. y3 = y * 3
  169. array[y3] = gamma[value[1]]
  170. array[y3 + 1] = gamma[value[0]]
  171. array[y3 + 2] = gamma[value[2]]
  172. spidev.write(array)
  173. spidev.flush()
  174. exit(0)