-
Notifications
You must be signed in to change notification settings - Fork 0
/
rpi_ws281x.py
152 lines (125 loc) · 5.86 KB
/
rpi_ws281x.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# Adafruit NeoPixel library port to the rpi_ws281x library.
# Author: Tony DiCola ([email protected]), Jeremy Garff ([email protected])
import _rpi_ws281x as ws
import atexit
class FutevWS281():
pass
def Color(red, green, blue):
"""Convert the provided red, green, blue color to a 24-bit color value.
Each color component should be a value 0-255 where 0 is the lowest intensity
and 255 is the highest intensity.
"""
return (red << 16) | (green << 8) | blue
class _LED_Data(object):
"""Wrapper class which makes a SWIG LED color data array look and feel like
a Python list of integers.
"""
def __init__(self, channel, size):
self.size = size
self.channel = channel
def __getitem__(self, pos):
"""Return the 24-bit RGB color value at the provided position or slice
of positions.
"""
# Handle if a slice of positions are passed in by grabbing all the values
# and returning them in a list.
if isinstance(pos, slice):
return [ws.ws2811_led_get(self.channel, n) for n in range(pos.indices(self.size))]
# Else assume the passed in value is a number to the position.
else:
return ws.ws2811_led_get(self.channel, pos)
def __setitem__(self, pos, value):
"""Set the 24-bit RGB color value at the provided position or slice of
positions.
"""
# Handle if a slice of positions are passed in by setting the appropriate
# LED data values to the provided values.
if isinstance(pos, slice):
index = 0
for n in range(pos.indices(self.size)):
ws.ws2811_led_set(self.channel, n, value[index])
index += 1
# Else assume the passed in value is a number to the position.
else:
return ws.ws2811_led_set(self.channel, pos, value)
class PixelStrip(object):
def __init__(self, num, pin, freq_hz=800000, dma=10, invert=False, brightness=128, channel=0, gamma=None):
"""Class to represent a SK6812/WS281x LED display. Num should be the
number of pixels in the display, and pin should be the GPIO pin connected
to the display signal line (must be a PWM pin like 18!). Optional
parameters are freq, the frequency of the display signal in hertz (default
800khz), dma, the DMA channel to use (default 10), invert, a boolean
specifying if the signal line should be inverted (default False), and
channel, the PWM channel to use (defaults to 0).
"""
if gamma is None:
gamma = list(range(256))
self._gamma = gamma
# Create ws2811_t structure and fill in parameters.
self._leds = ws.new_ws2811_t()
# Initialize the channels to zero
for channum in range(2):
chan = ws.ws2811_channel_get(self._leds, channum)
ws.ws2811_channel_t_count_set(chan, 0)
ws.ws2811_channel_t_gpionum_set(chan, 0)
ws.ws2811_channel_t_invert_set(chan, 0)
ws.ws2811_channel_t_brightness_set(chan, 0)
# Initialize the channel in use
self._channel = ws.ws2811_channel_get(self._leds, channel)
ws.ws2811_channel_t_gamma_set(self._channel, self._gamma)
ws.ws2811_channel_t_count_set(self._channel, num)
ws.ws2811_channel_t_gpionum_set(self._channel, pin)
ws.ws2811_channel_t_invert_set(self._channel, 0 if not invert else 1)
ws.ws2811_channel_t_brightness_set(self._channel, brightness)
ws.ws2811_channel_t_strip_type_set(self._channel, ws.WS2811_STRIP_GRB)
# Initialize the controller
ws.ws2811_t_freq_set(self._leds, freq_hz)
ws.ws2811_t_dmanum_set(self._leds, dma)
# Grab the led data array.
self._led_data = _LED_Data(self._channel, num)
# Substitute for __del__, traps an exit condition and cleans up properly
atexit.register(self._cleanup)
def _cleanup(self):
# Clean up memory used by the library when not needed anymore.
if self._leds is not None:
ws.delete_ws2811_t(self._leds)
self._leds = None
self._channel = None
def setGamma(self, gamma):
if type(gamma) is list and len(gamma) == 256:
self._gamma = gamma
ws.ws2811_channel_t_gamma_set(self._channel, self._gamma)
def begin(self):
"""Initialize library, must be called once before other functions are
called.
"""
resp = ws.ws2811_init(self._leds)
if resp != 0:
str_resp = ws.ws2811_get_return_t_str(resp)
raise RuntimeError('ws2811_init failed with code {0} ({1})'.format(resp, str_resp))
def show(self):
"""Update the display with the data from the LED buffer."""
resp = ws.ws2811_render(self._leds)
if resp != 0:
str_resp = ws.ws2811_get_return_t_str(resp)
raise RuntimeError('ws2811_render failed with code {0} ({1})'.format(resp, str_resp))
def setPixelColor(self, n, color):
"""Set LED at position n to the provided 24-bit color value (in RGB order).
"""
self._led_data[n] = color
def setPixelColorRGB(self, n, red, green, blue):
"""Set LED at position n to the provided red, green, and blue color.
Each color component should be a value from 0 to 255 (where 0 is the
lowest intensity and 255 is the highest intensity).
"""
self.setPixelColor(n, Color(red, green, blue))
def getBrightness(self):
return ws.ws2811_channel_t_brightness_get(self._channel)
def setBrightness(self, brightness):
"""Scale each LED in the buffer by the provided brightness. A brightness
of 0 is the darkest and 255 is the brightest.
"""
ws.ws2811_channel_t_brightness_set(self._channel, brightness)
# Shim for back-compatibility
class Adafruit_NeoPixel(PixelStrip):
pass