Merge pull request #172 from waveform80/led-board-pwm-blink

Re: #94 and #161
This commit is contained in:
Dave Jones
2016-02-07 20:30:36 +00:00

View File

@@ -11,7 +11,7 @@ except ImportError:
from time import sleep from time import sleep
from collections import namedtuple from collections import namedtuple
from itertools import repeat from itertools import repeat, cycle, chain
from .exc import InputDeviceError, OutputDeviceError from .exc import InputDeviceError, OutputDeviceError
from .input_devices import Button from .input_devices import Button
@@ -102,18 +102,30 @@ class LEDBoard(SourceMixin, CompositeDevice):
for led in self.leds: for led in self.leds:
led.toggle() led.toggle()
def blink(self, on_time=1, off_time=1, n=None, background=True): def blink(
self, on_time=1, off_time=1, fade_in_time=0, fade_out_time=0,
n=None, background=True):
""" """
Make all the LEDs turn on and off repeatedly. Make all the LEDs turn on and off repeatedly.
:param float on_time: :param float on_time:
Number of seconds on Number of seconds on. Defaults to 1 second.
:param float off_time: :param float off_time:
Number of seconds off Number of seconds off. Defaults to 1 second.
:param float fade_in_time:
Number of seconds to spend fading in. Defaults to 0. Must be 0 if
``pwm`` was ``False`` when the class was constructed
(:exc:`ValueError` will be raised if not).
:param float fade_out_time:
Number of seconds to spend fading out. Defaults to 0. Must be 0 if
``pwm`` was ``False`` when the class was constructed
(:exc:`ValueError` will be raised if not).
:param int n: :param int n:
Number of times to blink; ``None`` means forever Number of times to blink; ``None`` (the default) means forever.
:param bool background: :param bool background:
If ``True``, start a background thread to continue blinking and If ``True``, start a background thread to continue blinking and
@@ -121,9 +133,15 @@ class LEDBoard(SourceMixin, CompositeDevice):
finished (warning: the default value of *n* will result in this finished (warning: the default value of *n* will result in this
method never returning). method never returning).
""" """
if isinstance(self.leds[0], LED):
if fade_in_time:
raise ValueError('fade_in_time must be 0 with non-PWM LEDs')
if fade_out_time:
raise ValueError('fade_out_time must be 0 with non-PWM LEDs')
self._stop_blink() self._stop_blink()
self._blink_thread = GPIOThread( self._blink_thread = GPIOThread(
target=self._blink_leds, args=(on_time, off_time, n) target=self._blink_leds,
args=(on_time, off_time, fade_in_time, fade_out_time, n)
) )
self._blink_thread.start() self._blink_thread.start()
if not background: if not background:
@@ -135,16 +153,28 @@ class LEDBoard(SourceMixin, CompositeDevice):
self._blink_thread.stop() self._blink_thread.stop()
self._blink_thread = None self._blink_thread = None
def _blink_leds(self, on_time, off_time, n): def _blink_leds(self, on_time, off_time, fade_in_time, fade_out_time, n, fps=50):
iterable = repeat(0) if n is None else repeat(0, n) sequence = []
for i in iterable: if fade_in_time > 0:
sequence += [
(i * (1 / fps) / fade_in_time, 1 / fps)
for i in range(int(fps * fade_in_time))
]
sequence.append((1, on_time))
if fade_out_time > 0:
sequence += [
(1 - (i * (1 / fps) / fade_out_time), 1 / fps)
for i in range(int(fps * fade_out_time))
]
sequence.append((0, off_time))
sequence = (
cycle(sequence) if n is None else
chain.from_iterable(repeat(sequence, n))
)
for value, delay in sequence:
for led in self.leds: for led in self.leds:
led.on() led.value = value
if self._blink_thread.stopping.wait(on_time): if self._blink_thread.stopping.wait(delay):
break
for led in self.leds:
led.off()
if self._blink_thread.stopping.wait(off_time):
break break