11
11
12
12
from time import sleep
13
13
from collections import namedtuple
14
- from itertools import repeat
14
+ from itertools import repeat , cycle , chain
15
15
16
16
from .exc import InputDeviceError , OutputDeviceError
17
17
from .input_devices import Button
@@ -102,28 +102,46 @@ def toggle(self):
102
102
for led in self .leds :
103
103
led .toggle ()
104
104
105
- def blink (self , on_time = 1 , off_time = 1 , n = None , background = True ):
105
+ def blink (
106
+ self , on_time = 1 , off_time = 1 , fade_in_time = 0 , fade_out_time = 0 ,
107
+ n = None , background = True ):
106
108
"""
107
109
Make all the LEDs turn on and off repeatedly.
108
110
109
111
:param float on_time:
110
- Number of seconds on
112
+ Number of seconds on. Defaults to 1 second.
111
113
112
114
:param float off_time:
113
- Number of seconds off
115
+ Number of seconds off. Defaults to 1 second.
116
+
117
+ :param float fade_in_time:
118
+ Number of seconds to spend fading in. Defaults to 0. Must be 0 if
119
+ ``pwm`` was ``False`` when the class was constructed
120
+ (:exc:`ValueError` will be raised if not).
121
+
122
+ :param float fade_out_time:
123
+ Number of seconds to spend fading out. Defaults to 0. Must be 0 if
124
+ ``pwm`` was ``False`` when the class was constructed
125
+ (:exc:`ValueError` will be raised if not).
114
126
115
127
:param int n:
116
- Number of times to blink; ``None`` means forever
128
+ Number of times to blink; ``None`` (the default) means forever.
117
129
118
130
:param bool background:
119
131
If ``True``, start a background thread to continue blinking and
120
132
return immediately. If ``False``, only return when the blink is
121
133
finished (warning: the default value of *n* will result in this
122
134
method never returning).
123
135
"""
136
+ if isinstance (self .leds [0 ], LED ):
137
+ if fade_in_time :
138
+ raise ValueError ('fade_in_time must be 0 with non-PWM LEDs' )
139
+ if fade_out_time :
140
+ raise ValueError ('fade_out_time must be 0 with non-PWM LEDs' )
124
141
self ._stop_blink ()
125
142
self ._blink_thread = GPIOThread (
126
- target = self ._blink_leds , args = (on_time , off_time , n )
143
+ target = self ._blink_leds ,
144
+ args = (on_time , off_time , fade_in_time , fade_out_time , n )
127
145
)
128
146
self ._blink_thread .start ()
129
147
if not background :
@@ -135,17 +153,29 @@ def _stop_blink(self):
135
153
self ._blink_thread .stop ()
136
154
self ._blink_thread = None
137
155
138
- def _blink_leds (self , on_time , off_time , n ):
139
- iterable = repeat (0 ) if n is None else repeat (0 , n )
140
- for i in iterable :
141
- for led in self .leds :
142
- led .on ()
143
- if self ._blink_thread .stopping .wait (on_time ):
144
- break
156
+ def _blink_leds (self , on_time , off_time , fade_in_time , fade_out_time , n , fps = 50 ):
157
+ sequence = []
158
+ if fade_in_time > 0 :
159
+ sequence += [
160
+ (i * (1 / fps ) / fade_in_time , 1 / fps )
161
+ for i in range (int (fps * fade_in_time ))
162
+ ]
163
+ sequence .append ((1 , on_time ))
164
+ if fade_out_time > 0 :
165
+ sequence += [
166
+ (1 - (i * (1 / fps ) / fade_out_time ), 1 / fps )
167
+ for i in range (int (fps * fade_out_time ))
168
+ ]
169
+ sequence .append ((0 , off_time ))
170
+ sequence = (
171
+ cycle (sequence ) if n is None else
172
+ chain .from_iterable (repeat (sequence , n ))
173
+ )
174
+ for value , delay in sequence :
145
175
for led in self .leds :
146
- led .off ()
147
- if self ._blink_thread .stopping .wait (off_time ):
148
- break
176
+ led .value = value
177
+ if self ._blink_thread .stopping .wait (delay ):
178
+ break
149
179
150
180
151
181
class PiLiter (LEDBoard ):
0 commit comments