Skip to content

Commit

Permalink
Merge pull request #174 from waveform80/rgbled-blink
Browse files Browse the repository at this point in the history
Fix #135
  • Loading branch information
waveform80 committed Feb 8, 2016
2 parents 19c19f6 + 9871ac3 commit a498d29
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 6 deletions.
2 changes: 1 addition & 1 deletion docs/api_output.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ RGBLED
======

.. autoclass:: RGBLED(red, green, blue, active_high=True)
:members: on, off, red, green, blue, value
:members: on, off, blink, red, green, blue, value

Motor
=====
Expand Down
96 changes: 91 additions & 5 deletions gpiozero/output_devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ def __init__(self, pin=None, active_high=True, initial_value=0, frequency=100):
raise

def close(self):
self._stop_blink()
if self._pwm:
# Ensure we wipe out the PWM object so that re-runs don't attempt
# to re-stop the PWM thread (otherwise, the fact that close is
Expand Down Expand Up @@ -484,11 +485,12 @@ class PWMLED(PWMOutputDevice):


def _led_property(index, doc=None):
return property(
lambda self: getattr(self._leds[index], 'value'),
lambda self, value: setattr(self._leds[index], 'value', value),
doc
)
def getter(self):
return self._leds[index].value
def setter(self, value):
self._stop_blink()
self._leds[index].value = value
return property(getter, setter, doc=doc)


class RGBLED(SourceMixin, CompositeDevice):
Expand Down Expand Up @@ -523,6 +525,8 @@ class RGBLED(SourceMixin, CompositeDevice):
(the :meth:`off` method always does the opposite).
"""
def __init__(self, red=None, green=None, blue=None, active_high=True):
self._leds = ()
self._blink_thread = None
if not all([red, green, blue]):
raise OutputDeviceError('red, green, and blue pins must be provided')
super(RGBLED, self).__init__()
Expand Down Expand Up @@ -572,9 +576,91 @@ def off(self):
self.value = (0, 0, 0)

def close(self):
self._stop_blink()
for led in self._leds:
led.close()

def blink(
self, on_time=1, off_time=1, fade_in_time=0, fade_out_time=0,
on_color=(1, 1, 1), off_color=(0, 0, 0), n=None, background=True):
"""
Make the device turn on and off repeatedly.
:param float on_time:
Number of seconds on. Defaults to 1 second.
:param float off_time:
Number of seconds off. Defaults to 1 second.
:param float fade_in_time:
Number of seconds to spend fading in. Defaults to 0.
:param float fade_out_time:
Number of seconds to spend fading out. Defaults to 0.
:param tuple on_color:
The color to use when the LED is "on". Defaults to white.
:param tuple off_color:
The color to use when the LED is "off". Defaults to black.
:param int n:
Number of times to blink; ``None`` (the default) means forever.
:param bool background:
If ``True`` (the default), start a background thread to continue
blinking and return immediately. If ``False``, only return when the
blink is finished (warning: the default value of *n* will result in
this method never returning).
"""
self._stop_blink()
self._blink_thread = GPIOThread(
target=self._blink_device,
args=(on_time, off_time, fade_in_time, fade_out_time, on_color, off_color, n)
)
self._blink_thread.start()
if not background:
self._blink_thread.join()
self._blink_thread = None

def _stop_blink(self):
if self._blink_thread:
self._blink_thread.stop()
self._blink_thread = None

def _blink_device(
self, on_time, off_time, fade_in_time, fade_out_time, on_color,
off_color, n, fps=50):
# Define some simple lambdas to perform linear interpolation between
# off_color and on_color
lerp = lambda t, fade_in: tuple(
(1 - t) * off + t * on
if fade_in else
(1 - t) * on + t * off
for off, on in zip(off_color, on_color)
)
sequence = []
if fade_in_time > 0:
sequence += [
(lerp(i * (1 / fps) / fade_in_time, True), 1 / fps)
for i in range(int(fps * fade_in_time))
]
sequence.append((on_color, on_time))
if fade_out_time > 0:
sequence += [
(lerp(i * (1 / fps) / fade_out_time, False), 1 / fps)
for i in range(int(fps * fade_out_time))
]
sequence.append((off_color, off_time))
sequence = (
cycle(sequence) if n is None else
chain.from_iterable(repeat(sequence, n))
)
for value, delay in sequence:
self._leds[0].value, self._leds[1].value, self._leds[2].value = value
if self._blink_thread.stopping.wait(delay):
break


class Motor(SourceMixin, CompositeDevice):
"""
Expand Down

0 comments on commit a498d29

Please sign in to comment.