Skip to content

Commit 1575863

Browse files
committed
Merge pull request gpiozero#312 from lurch/rgbled_pulse
Add RGBLED.pulse method
2 parents 4ff0f3f + 18bb3f5 commit 1575863

File tree

3 files changed

+239
-7
lines changed

3 files changed

+239
-7
lines changed

docs/api_output.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ PWMLED
2323
======
2424

2525
.. autoclass:: PWMLED(pin, active_high=True, initial_value=0, frequency=100)
26-
:members: on, off, toggle, blink, pin, is_lit, value
26+
:members: on, off, toggle, blink, pulse, pin, is_lit, value
2727

2828
RGBLED
2929
======
3030

3131
.. autoclass:: RGBLED(red, green, blue, active_high=True, initial_value=(0, 0, 0))
32-
:members: on, off, toggle, blink, red, green, blue, is_lit, color
32+
:members: on, off, toggle, blink, pulse, red, green, blue, is_lit, color
3333

3434
Buzzer
3535
======

gpiozero/output_devices.py

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -435,12 +435,12 @@ def pulse(self, fade_in_time=1, fade_out_time=1, n=None, background=True):
435435
Number of seconds to spend fading out. Defaults to 1.
436436
437437
:param int n:
438-
Number of times to blink; ``None`` (the default) means forever.
438+
Number of times to pulse; ``None`` (the default) means forever.
439439
440440
:param bool background:
441441
If ``True`` (the default), start a background thread to continue
442-
blinking and return immediately. If ``False``, only return when the
443-
blink is finished (warning: the default value of *n* will result in
442+
pulsing and return immediately. If ``False``, only return when the
443+
pulse is finished (warning: the default value of *n* will result in
444444
this method never returning).
445445
"""
446446
on_time = off_time = 0
@@ -670,13 +670,49 @@ def blink(
670670
self._stop_blink()
671671
self._blink_thread = GPIOThread(
672672
target=self._blink_device,
673-
args=(on_time, off_time, fade_in_time, fade_out_time, on_color, off_color, n)
673+
args=(
674+
on_time, off_time, fade_in_time, fade_out_time,
675+
on_color, off_color, n
676+
)
674677
)
675678
self._blink_thread.start()
676679
if not background:
677680
self._blink_thread.join()
678681
self._blink_thread = None
679682

683+
def pulse(
684+
self, fade_in_time=1, fade_out_time=1,
685+
on_color=(1, 1, 1), off_color=(0, 0, 0), n=None, background=True):
686+
"""
687+
Make the device fade in and out repeatedly.
688+
689+
:param float fade_in_time:
690+
Number of seconds to spend fading in. Defaults to 1.
691+
692+
:param float fade_out_time:
693+
Number of seconds to spend fading out. Defaults to 1.
694+
695+
:param tuple on_color:
696+
The color to use when the LED is "on". Defaults to white.
697+
698+
:param tuple off_color:
699+
The color to use when the LED is "off". Defaults to black.
700+
701+
:param int n:
702+
Number of times to pulse; ``None`` (the default) means forever.
703+
704+
:param bool background:
705+
If ``True`` (the default), start a background thread to continue
706+
pulsing and return immediately. If ``False``, only return when the
707+
pulse is finished (warning: the default value of *n* will result in
708+
this method never returning).
709+
"""
710+
on_time = off_time = 0
711+
self.blink(
712+
on_time, off_time, fade_in_time, fade_out_time,
713+
on_color, off_color, n, background
714+
)
715+
680716
def _stop_blink(self, led=None):
681717
# If this is called with a single led, we stop all blinking anyway
682718
if self._blink_thread:

tests/test_outputs.py

Lines changed: 197 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99

1010
import sys
11-
from time import sleep
11+
from time import sleep, time
1212
try:
1313
from math import isclose
1414
except ImportError:
@@ -95,8 +95,11 @@ def test_output_digital_toggle():
9595
def test_output_blink_background():
9696
pin = MockPin(2)
9797
with DigitalOutputDevice(pin) as device:
98+
start = time()
9899
device.blink(0.1, 0.1, n=2)
100+
assert isclose(time() - start, 0, abs_tol=0.05)
99101
device._blink_thread.join() # naughty, but ensures no arbitrary waits in the test
102+
assert isclose(time() - start, 0.4, abs_tol=0.05)
100103
pin.assert_states_and_times([
101104
(0.0, False),
102105
(0.0, True),
@@ -110,7 +113,9 @@ def test_output_blink_background():
110113
def test_output_blink_foreground():
111114
pin = MockPin(2)
112115
with DigitalOutputDevice(pin) as device:
116+
start = time()
113117
device.blink(0.1, 0.1, n=2, background=False)
118+
assert isclose(time() - start, 0.4, abs_tol=0.05)
114119
pin.assert_states_and_times([
115120
(0.0, False),
116121
(0.0, True),
@@ -212,8 +217,11 @@ def test_output_pwm_write_silly():
212217
def test_output_pwm_blink_background():
213218
pin = MockPWMPin(2)
214219
with PWMOutputDevice(pin) as device:
220+
start = time()
215221
device.blink(0.1, 0.1, n=2)
222+
assert isclose(time() - start, 0, abs_tol=0.05)
216223
device._blink_thread.join()
224+
assert isclose(time() - start, 0.4, abs_tol=0.05)
217225
pin.assert_states_and_times([
218226
(0.0, 0),
219227
(0.0, 1),
@@ -227,7 +235,9 @@ def test_output_pwm_blink_background():
227235
def test_output_pwm_blink_foreground():
228236
pin = MockPWMPin(2)
229237
with PWMOutputDevice(pin) as device:
238+
start = time()
230239
device.blink(0.1, 0.1, n=2, background=False)
240+
assert isclose(time() - start, 0.4, abs_tol=0.05)
231241
pin.assert_states_and_times([
232242
(0.0, 0),
233243
(0.0, 1),
@@ -241,8 +251,11 @@ def test_output_pwm_blink_foreground():
241251
def test_output_pwm_fade_background():
242252
pin = MockPWMPin(2)
243253
with PWMOutputDevice(pin) as device:
254+
start = time()
244255
device.blink(0, 0, 0.2, 0.2, n=2)
256+
assert isclose(time() - start, 0, abs_tol=0.05)
245257
device._blink_thread.join()
258+
assert isclose(time() - start, 0.8, abs_tol=0.05)
246259
pin.assert_states_and_times([
247260
(0.0, 0),
248261
(0.04, 0.2),
@@ -272,7 +285,75 @@ def test_output_pwm_fade_background():
272285
def test_output_pwm_fade_foreground():
273286
pin = MockPWMPin(2)
274287
with PWMOutputDevice(pin) as device:
288+
start = time()
275289
device.blink(0, 0, 0.2, 0.2, n=2, background=False)
290+
assert isclose(time() - start, 0.8, abs_tol=0.05)
291+
pin.assert_states_and_times([
292+
(0.0, 0),
293+
(0.04, 0.2),
294+
(0.04, 0.4),
295+
(0.04, 0.6),
296+
(0.04, 0.8),
297+
(0.04, 1),
298+
(0.04, 0.8),
299+
(0.04, 0.6),
300+
(0.04, 0.4),
301+
(0.04, 0.2),
302+
(0.04, 0),
303+
(0.04, 0.2),
304+
(0.04, 0.4),
305+
(0.04, 0.6),
306+
(0.04, 0.8),
307+
(0.04, 1),
308+
(0.04, 0.8),
309+
(0.04, 0.6),
310+
(0.04, 0.4),
311+
(0.04, 0.2),
312+
(0.04, 0),
313+
])
314+
315+
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
316+
reason='timing is too random on pypy')
317+
def test_output_pwm_pulse_background():
318+
pin = MockPWMPin(2)
319+
with PWMOutputDevice(pin) as device:
320+
start = time()
321+
device.pulse(0.2, 0.2, n=2)
322+
assert isclose(time() - start, 0, abs_tol=0.05)
323+
device._blink_thread.join()
324+
assert isclose(time() - start, 0.8, abs_tol=0.05)
325+
pin.assert_states_and_times([
326+
(0.0, 0),
327+
(0.04, 0.2),
328+
(0.04, 0.4),
329+
(0.04, 0.6),
330+
(0.04, 0.8),
331+
(0.04, 1),
332+
(0.04, 0.8),
333+
(0.04, 0.6),
334+
(0.04, 0.4),
335+
(0.04, 0.2),
336+
(0.04, 0),
337+
(0.04, 0.2),
338+
(0.04, 0.4),
339+
(0.04, 0.6),
340+
(0.04, 0.8),
341+
(0.04, 1),
342+
(0.04, 0.8),
343+
(0.04, 0.6),
344+
(0.04, 0.4),
345+
(0.04, 0.2),
346+
(0.04, 0),
347+
])
348+
349+
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
350+
reason='timing is too random on pypy')
351+
def test_output_pwm_pulse_foreground():
352+
pin = MockPWMPin(2)
353+
with PWMOutputDevice(pin) as device:
354+
start = time()
355+
device.pulse(0.2, 0.2, n=2, background=False)
356+
assert isclose(time() - start, 0.8, abs_tol=0.05)
276357
pin.assert_states_and_times([
277358
(0.0, 0),
278359
(0.04, 0.2),
@@ -409,8 +490,11 @@ def test_rgbled_toggle():
409490
def test_rgbled_blink_background():
410491
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
411492
with RGBLED(r, g, b) as device:
493+
start = time()
412494
device.blink(0.1, 0.1, n=2)
495+
assert isclose(time() - start, 0, abs_tol=0.05)
413496
device._blink_thread.join()
497+
assert isclose(time() - start, 0.4, abs_tol=0.05)
414498
expected = [
415499
(0.0, 0),
416500
(0.0, 1),
@@ -427,7 +511,9 @@ def test_rgbled_blink_background():
427511
def test_rgbled_blink_foreground():
428512
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
429513
with RGBLED(r, g, b) as device:
514+
start = time()
430515
device.blink(0.1, 0.1, n=2, background=False)
516+
assert isclose(time() - start, 0.4, abs_tol=0.05)
431517
expected = [
432518
(0.0, 0),
433519
(0.0, 1),
@@ -444,8 +530,118 @@ def test_rgbled_blink_foreground():
444530
def test_rgbled_fade_background():
445531
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
446532
with RGBLED(r, g, b) as device:
533+
start = time()
447534
device.blink(0, 0, 0.2, 0.2, n=2)
535+
assert isclose(time() - start, 0, abs_tol=0.05)
536+
device._blink_thread.join()
537+
assert isclose(time() - start, 0.8, abs_tol=0.05)
538+
expected = [
539+
(0.0, 0),
540+
(0.04, 0.2),
541+
(0.04, 0.4),
542+
(0.04, 0.6),
543+
(0.04, 0.8),
544+
(0.04, 1),
545+
(0.04, 0.8),
546+
(0.04, 0.6),
547+
(0.04, 0.4),
548+
(0.04, 0.2),
549+
(0.04, 0),
550+
(0.04, 0.2),
551+
(0.04, 0.4),
552+
(0.04, 0.6),
553+
(0.04, 0.8),
554+
(0.04, 1),
555+
(0.04, 0.8),
556+
(0.04, 0.6),
557+
(0.04, 0.4),
558+
(0.04, 0.2),
559+
(0.04, 0),
560+
]
561+
r.assert_states_and_times(expected)
562+
g.assert_states_and_times(expected)
563+
b.assert_states_and_times(expected)
564+
565+
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
566+
reason='timing is too random on pypy')
567+
def test_rgbled_fade_foreground():
568+
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
569+
with RGBLED(r, g, b) as device:
570+
start = time()
571+
device.blink(0, 0, 0.2, 0.2, n=2, background=False)
572+
assert isclose(time() - start, 0.8, abs_tol=0.05)
573+
expected = [
574+
(0.0, 0),
575+
(0.04, 0.2),
576+
(0.04, 0.4),
577+
(0.04, 0.6),
578+
(0.04, 0.8),
579+
(0.04, 1),
580+
(0.04, 0.8),
581+
(0.04, 0.6),
582+
(0.04, 0.4),
583+
(0.04, 0.2),
584+
(0.04, 0),
585+
(0.04, 0.2),
586+
(0.04, 0.4),
587+
(0.04, 0.6),
588+
(0.04, 0.8),
589+
(0.04, 1),
590+
(0.04, 0.8),
591+
(0.04, 0.6),
592+
(0.04, 0.4),
593+
(0.04, 0.2),
594+
(0.04, 0),
595+
]
596+
r.assert_states_and_times(expected)
597+
g.assert_states_and_times(expected)
598+
b.assert_states_and_times(expected)
599+
600+
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
601+
reason='timing is too random on pypy')
602+
def test_rgbled_pulse_background():
603+
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
604+
with RGBLED(r, g, b) as device:
605+
start = time()
606+
device.pulse(0.2, 0.2, n=2)
607+
assert isclose(time() - start, 0, abs_tol=0.05)
448608
device._blink_thread.join()
609+
assert isclose(time() - start, 0.8, abs_tol=0.05)
610+
expected = [
611+
(0.0, 0),
612+
(0.04, 0.2),
613+
(0.04, 0.4),
614+
(0.04, 0.6),
615+
(0.04, 0.8),
616+
(0.04, 1),
617+
(0.04, 0.8),
618+
(0.04, 0.6),
619+
(0.04, 0.4),
620+
(0.04, 0.2),
621+
(0.04, 0),
622+
(0.04, 0.2),
623+
(0.04, 0.4),
624+
(0.04, 0.6),
625+
(0.04, 0.8),
626+
(0.04, 1),
627+
(0.04, 0.8),
628+
(0.04, 0.6),
629+
(0.04, 0.4),
630+
(0.04, 0.2),
631+
(0.04, 0),
632+
]
633+
r.assert_states_and_times(expected)
634+
g.assert_states_and_times(expected)
635+
b.assert_states_and_times(expected)
636+
637+
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
638+
reason='timing is too random on pypy')
639+
def test_rgbled_pulse_foreground():
640+
r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
641+
with RGBLED(r, g, b) as device:
642+
start = time()
643+
device.pulse(0.2, 0.2, n=2, background=False)
644+
assert isclose(time() - start, 0.8, abs_tol=0.05)
449645
expected = [
450646
(0.0, 0),
451647
(0.04, 0.2),

0 commit comments

Comments
 (0)