forked from penguintutor/neopixel-gui
-
Notifications
You must be signed in to change notification settings - Fork 0
/
neopixelseq.py
373 lines (291 loc) · 13.3 KB
/
neopixelseq.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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
import time
import tkinter as tk
from neopixel import *
from dynneopixel import *
# Sequence method should change some LEDs and then return
# If that sequence is still running then the method should resume
# from where it left off. In the case of short sequences then the entire
# sequence can be run in a single run of the method.
# All sequences must include a sleep delay, normally this is
# time.sleep(self.command.getOptions()['delay']/1000)
# Any sequences that are long lasting need to check self.command.getCmdStatus()
# preiodically and if true return
# this is not critical, but will cause updates to be unresponsive
# If used set it to False at the start of the method
# The chaserStartPos variable can be used by sequences to provide a means
# to return to the same point after checking if a configuration change has
# has been made
# Where a sequence is repeats over a set number of LEDs other than the number
# of colours selected by the user then the preferred value is 4
# The magic number of 4 is used as it is a factor of all the neopixels rings
# (12, 16, 24) and it is an easy number to integrate within sequences.
class NeoPixelSeq():
def __init__(self, settings, command):
# class variables to maintain between function calls
self.chaserStartPos = 0 # can use across all chasers as only required when we don't restart chaser
self.settings = settings
self.command = command
self.numPixels = settings['ledcount']
self.strip = Dynamic_NeoPixel(self.settings['ledcount'], self.settings['gpiopin'], self.settings['ledfreq'], self.settings['leddma'], self.settings['ledinvert'], self.settings['ledmaxbrightness'])
# Intialize the library (must be called once before other functions).
self.strip.begin()
# Update settings by replacing existing led strip
def updSettings (self, settings):
self.settings = settings
self.numPixels = settings['ledcount']
self.strip.updSettings(self.settings)
# All on with a single colour (first colour is used)
# Full intensity
def allOnSingleColour(self):
colours = self.command.getColours()
colour = colours[0]
for i in range(self.numPixels):
self.strip.setPixelColor(i, colour)
self.strip.show()
time.sleep(self.command.getOptions()['delay']/1000)
# All on with multiple colours (each colour used in cycle)
# Full intensity
def allOn(self):
colours = self.command.getColours()
currentColour = 0
for i in range(self.numPixels):
self.strip.setPixelColor(i, colours[currentColour])
currentColour += 1
if (currentColour >= len(colours)):
currentColour = 0
self.strip.show()
time.sleep(self.command.getOptions()['delay']/1000)
def allOff(self):
for i in range(self.numPixels):
self.strip.setPixelColor(i, Color(0,0,0))
self.strip.show()
time.sleep(self.command.getOptions()['delay']/1000)
# chase colours across a background
# uses getBackColour - normally black
def chaserBackground(self):
options = self.command.getOptions()
colours = self.command.getColours()
backColour = self.command.getBackColour()
# number of times of the num colours the group occupies
groupsize = 4
colourPixelRange = len(colours) * groupsize
# Check we are within range (ie. number of leds selected reduced)
if (self.chaserStartPos >= colourPixelRange):
self.chaserStartPos = 0
iterations = 4
for iter in range(iterations):
#colourNum = colourNumStart
# Set all pixels to the background - then we update those not
for resetPixel in range(self.strip.numPixels()):
self.strip.setPixelColor (resetPixel, backColour)
for i in range(0, self.strip.numPixels()+1, colourPixelRange):
for j in range(0, len(colours)):
if (i + j + self.chaserStartPos < self.strip.numPixels()) :
self.strip.setPixelColor (i + j + self.chaserStartPos, colours[j])
self.strip.show()
time.sleep(options['delay']/1000.0)
self.chaserStartPos += 1
if (self.chaserStartPos >= colourPixelRange):
self.chaserStartPos = 0
# colors is an array of colors to display
# simple sequencer / shift
def chaser(self):
options = self.command.getOptions()
colours = self.command.getColours()
# colourNum tracks which colour in array we are showing
colourNum = 0
# If less than two colours then add a second for off to create a chase
if (len(colours)<2):
colours.append(0x000000)
# which colour to start on defined in constructor so we maintain across calls to this method
#self.chaserStartPos = 0
# check that chaser number is not too large (ie if we reduce number of colours)
if (self.chaserStartPos >= len(colours)) :
self.chaserStartPos = 0
iterations = 5
for j in range(iterations):
colourNum = self.chaserStartPos
for i in range(self.strip.numPixels()):
self.strip.setPixelColor (i, colours[colourNum])
colourNum = colourNum +1
if (colourNum >= len(colours)):
colourNum = 0
self.strip.show()
time.sleep(options['wait']/1000.0)
self.chaserStartPos = self.chaserStartPos + 1
if (self.chaserStartPos >= len(colours)):
self.chaserStartPos = 0
# Chaser that turns pixels on and off 4 at a time
def chaserSingleColour(self):
options = self.command.getOptions()
colours = self.command.getColours()
colour = colours[0]
for q in range(4):
for i in range(0, self.strip.numPixels(), 4):
self.strip.setPixelColor(i+q, colour)
self.strip.show()
time.sleep(options['delay']/1000.0)
for i in range(0, self.strip.numPixels(), 4):
self.strip.setPixelColor(i+q, 0)
# Define functions which animate LEDs in various ways.
def colourWipe(self):
self.command.setCmdStatus(False)
options = self.command.getOptions()
colours = self.command.getColours()
colourNum = 0
for i in range(self.strip.numPixels()):
self.strip.setPixelColor(i, colours[colourNum])
self.strip.show()
colourNum += 1
if (colourNum >= len(colours)) :
colourNum = 0
# Exit if new command
if (self.command.getCmdStatus()):
return
time.sleep(self.command.getOptions()['delay']/1000.0)
def wheel(self, pos):
"""Generate rainbow colors across 0-255 positions."""
if pos < 85:
return Color(pos * 3, 255 - pos * 3, 0)
elif pos < 170:
pos -= 85
return Color(255 - pos * 3, 0, pos * 3)
else:
pos -= 170
return Color(0, pos * 3, 255 - pos * 3)
def rainbow(self):
"""Draw rainbow that fades across all pixels at once."""
self.command.setCmdStatus(False)
for j in range(256):
for i in range(self.strip.numPixels()):
self.strip.setPixelColor(i, self.wheel((i+j) & 255))
self.strip.show()
# Exit if new command
if (self.command.getCmdStatus()):
return
time.sleep(self.command.getOptions()['delay']/1000.0)
def rainbowCycle(self):
"""Draw rainbow that uniformly distributes itself across all pixels."""
for j in range(256):
for i in range(self.strip.numPixels()):
self.strip.setPixelColor(i, self.wheel((int)((i * 256 / self.strip.numPixels())+ j) & 255))
self.strip.show()
time.sleep(self.command.getOptions()['delay']/10000.0)
def theatreChaseRainbow(self):
self.command.setCmdStatus(False)
"""Rainbow movie theater light style chaser animation."""
for j in range(256):
for q in range(3):
for i in range(0, self.strip.numPixels(), 3):
self.strip.setPixelColor(i+q, self.wheel((i+j) % 255))
self.strip.show()
time.sleep(self.command.getOptions()['delay']/1000.0)
for i in range(0, self.strip.numPixels(), 3):
self.strip.setPixelColor(i+q, 0)
# Exit if new command
if (self.command.getCmdStatus()):
return
def inOut(self):
self.outToIn()
if (self.command.getCmdStatus()):
return
self.inToOutOff()
if (self.command.getCmdStatus()):
return
def outIn(self):
self.inToOut()
if (self.command.getCmdStatus()):
return
self.outToInOff()
if (self.command.getCmdStatus()):
return
# outToIn -
def outToIn(self):
self.command.setCmdStatus(False)
colour = self.command.getSingleColour()
"""Wipe color across starting at both ends"""
for i in range((int)(self.strip.numPixels()/2)):
self.strip.setPixelColor(i, colour)
self.strip.setPixelColor(self.strip.numPixels() - i, colour);
self.strip.show()
if (self.command.getCmdStatus()):
return
time.sleep(self.command.getOptions()['delay']/1000.0)
# inToOut -
def inToOut(self):
"""Wipe color across starting at both ends"""
self.command.setCmdStatus(False)
colour = self.command.getSingleColour()
for i in range((int)(self.strip.numPixels()/2)):
self.strip.setPixelColor((int)(self.strip.numPixels()/2) - i, colour)
self.strip.setPixelColor((int)(self.strip.numPixels()/2) + i, colour);
self.strip.show()
if (self.command.getCmdStatus()):
return
time.sleep(self.command.getOptions()['delay']/1000.0)
def outToInOff(self):
colour = 0x000000
self.command.setCmdStatus(False)
"""Wipe color across starting at both ends"""
for i in range((int)(self.strip.numPixels()/2)):
self.strip.setPixelColor(i, colour)
self.strip.setPixelColor(self.strip.numPixels() - i, colour);
self.strip.show()
if (self.command.getCmdStatus()):
return
time.sleep(self.command.getOptions()['delay']/1000.0)
def inToOutOff(self):
"""Turn off starting at both ends"""
colour = 0x000000
self.command.setCmdStatus(False)
for i in range((int)(self.strip.numPixels()/2)):
self.strip.setPixelColor((int)(self.strip.numPixels()/2) - i, colour)
self.strip.setPixelColor((int)(self.strip.numPixels()/2) + i, colour);
self.strip.show()
if (self.command.getCmdStatus()):
return
time.sleep(self.command.getOptions()['delay']/1000.0)
def twinkleChase(self):
options = self.command.getOptions()
colours = self.command.getColours()
colour = colours[0]
for q in range(4):
for i in range(0, self.strip.numPixels(), 4):
self.strip.setPixelColor(i+q, 0)
self.strip.show()
time.sleep(options['delay']/1000.0)
for i in range(0, self.strip.numPixels(), 4):
self.strip.setPixelColor(i+q, colour)
# Follow me
# uses two colours (or use white)
# uses getBackColour - normally black
def chaseMe(self):
options = self.command.getOptions()
colours = self.command.getColours()
backColour = self.command.getBackColour()
# If we only have one colour then add white
if (len(colours) < 2) :
colours.append(0xffffff)
# number of times of the num colours the group occupies
groupsize = 8
colourPixelRange = 16
# Check we are within range (ie. number of leds selected reduced)
if (self.chaserStartPos >= colourPixelRange):
self.chaserStartPos = 0
iterations = 4
for iter in range(iterations):
# Set all pixels to the background - then we update those not
for resetPixel in range(self.strip.numPixels()):
self.strip.setPixelColor (resetPixel, backColour)
for i in range(0, self.strip.numPixels(), colourPixelRange):
if (self.chaserStartPos + i < self.strip.numPixels()) :
self.strip.setPixelColor (self.chaserStartPos + i, colours[0])
if (self.chaserStartPos + i + 4 < self.strip.numPixels()) :
self.strip.setPixelColor (self.chaserStartPos + i + 4, colours[1])
self.strip.show()
time.sleep(options['delay']/1000.0)
self.chaserStartPos += 1
if (self.chaserStartPos >= colourPixelRange):
self.chaserStartPos = 0
if __name__ == "__main__":
print ("This file is not executable - please run rpnpgp.py\nOr import this into your own code")