/
controller.py
153 lines (115 loc) · 3.65 KB
/
controller.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
#!/usr/bin/env python
import math
from functools import partial
import re
import struct
import time
import threading
import pigpio
COLORS = {
"red" : "FF0000",
"green" : "00FF00",
"blue" : "0000FF",
"white" : "FFFFFF",
"purple" : "A020F0",
"black" : "000000",
}
def is_rgb(rgb):
return re.match("[a-fA-F0-9]{6}", rgb) is not None
class Controller:
def __init__(self, pins):
assert len(pins) == 3
self.PINS = pins
self.MIN_SPEED = 1
self.MAX_SPEED = 20
self.interval = 1
self.speed = 1
self.set_speed(self.MIN_SPEED)
self.gpio = None
self.gpio = pigpio.pi()
self.stop_event = threading.Event()
self.thread = None
self.programs = {
"off" : self.off,
"fade" : self.fade,
"flash" : self.flash,
"strobe" : self.strobe,
"smooth" : self.smooth
}
def __del__(self):
if self.gpio is not None:
self.gpio.close()
def clear(self):
if (self.thread is not None) and self.thread.is_alive():
self.stop_event.set()
self.thread.join()
self.stop_event.clear()
self.thread = None
def status(self):
pass
def get_speed(self):
return self.speed
def set_speed(self, speed):
if speed < self.MIN_SPEED:
speed = self.MIN_SPEED
elif speed > self.MAX_SPEED:
speed = self.MAX_SPEED
self.speed = speed
self.interval = 2.0 / speed
def program(self, name):
self.clear()
target = None
if name in self.programs:
target = self.programs[name]
elif name in COLORS:
target = partial(self.color, struct.unpack('BBB', COLORS[name].decode('hex')))
elif is_rgb(name):
target = partial(self.color, struct.unpack('BBB', name.decode('hex')))
else:
print("invalid program: " + name)
if target is not None:
print("Starting program: " + name)
self.thread = threading.Thread(target=target)
self.thread.start()
return
###### PROGRAM UTILITIES ###################################################
def color(self, rgb):
assert len(self.PINS) == len(rgb)
for i in range(len(rgb)):
self.gpio.set_PWM_dutycycle(self.PINS[i], rgb[i])
def presets(self, l):
while True:
for preset in l:
self.color(preset)
self.stop_event.wait(timeout=self.interval)
if self.stop_event.is_set():
return
###### PROGRAMS ############################################################
def off(self):
self.color((0, 0, 0))
def fade(self):
phase = [0, math.pi * 2/3, math.pi*4/3]
width = 127
center = 128
length = 50
i = 0
while True:
self.color([ math.sin(0.05 * i + phase[x]) * width + center for x in range(len(phase)) ])
i += 1
self.stop_event.wait(timeout=self.interval / 5)
if self.stop_event.is_set():
return
def flash(self):
self.presets([
(255, 0, 0),
( 0, 255, 0),
( 0, 0, 255),
(255, 255, 0),
(255, 0, 255),
( 0, 255, 255),
(255, 255, 255),
])
def smooth(self):
self.presets([ (255, 0, 0), (0, 255, 0), (0, 0, 255) ])
def strobe(self):
self.presets([ [x,x,x] for x in range(1, 256, 2) + range(254, 0, -2) ])