Skip to content

Commit

Permalink
Merge pull request #176 from waveform80/led-bargraph
Browse files Browse the repository at this point in the history
Merge-clean update of PR #126
  • Loading branch information
waveform80 committed Feb 8, 2016
2 parents a498d29 + 55e99f3 commit 0c2f750
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 38 deletions.
14 changes: 14 additions & 0 deletions docs/api_boards.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ LED Board
:inherited-members:
:members:

LED Bar Graph
=============

.. autoclass:: LEDBarGraph(\*pins, initial_value=0)
:inherited-members:
:members:

Traffic Lights
==============

Expand All @@ -36,6 +43,13 @@ PiLITEr
:inherited-members:
:members:

PiLITEr Bar Graph
=================

.. autoclass:: PiLiterBarGraph
:inherited-members:
:members:

PI-TRAFFIC
==========

Expand Down
2 changes: 2 additions & 0 deletions gpiozero/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@
)
from .boards import (
LEDBoard,
LEDBarGraph,
PiLiter,
PiLiterBarGraph,
TrafficLights,
PiTraffic,
TrafficLightsBuzzer,
Expand Down
212 changes: 174 additions & 38 deletions gpiozero/boards.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,37 +19,19 @@
from .devices import GPIOThread, CompositeDevice, SourceMixin


class LEDBoard(SourceMixin, CompositeDevice):
class LEDCollection(SourceMixin, CompositeDevice):
"""
Extends :class:`CompositeDevice` and represents a generic LED board or
collection of LEDs.
The following example turns on all the LEDs on a board containing 5 LEDs
attached to GPIO pins 2 through 6::
from gpiozero import LEDBoard
leds = LEDBoard(2, 3, 4, 5, 6)
leds.on()
:param int \*pins:
Specify the GPIO pins that the LEDs of the board are attached to. You
can designate as many pins as necessary.
:param bool pwm:
If ``True``, construct :class:`PWMLED` instances for each pin. If
``False`` (the default), construct regular :class:`LED` instances. This
parameter can only be specified as a keyword parameter.
Abstract base class for :class:`LEDBoard` and :class:`LEDBarGraph`.
"""

def __init__(self, *pins, **kwargs):
self._blink_thread = None
super(LEDBoard, self).__init__()
super(LEDCollection, self).__init__()
pwm = kwargs.get('pwm', False)
LEDClass = PWMLED if pwm else LED
self._leds = tuple(LEDClass(pin) for pin in pins)

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

Expand All @@ -65,32 +47,17 @@ def leds(self):
"""
return self._leds

@property
def value(self):
"""
A tuple containing a value for each LED on the board. This property can
also be set to update the state of all LEDs on the board.
"""
return tuple(led.value for led in self._leds)

@value.setter
def value(self, value):
for l, v in zip(self.leds, value):
l.value = v

def on(self):
"""
Turn all the LEDs on.
"""
self._stop_blink()
for led in self.leds:
led.on()

def off(self):
"""
Turn all the LEDs off.
"""
self._stop_blink()
for led in self.leds:
led.off()

Expand All @@ -102,6 +69,61 @@ def toggle(self):
for led in self.leds:
led.toggle()



class LEDBoard(LEDCollection):
"""
Extends :class:`CompositeDevice` and represents a generic LED board or
collection of LEDs.
The following example turns on all the LEDs on a board containing 5 LEDs
attached to GPIO pins 2 through 6::
from gpiozero import LEDBoard
leds = LEDBoard(2, 3, 4, 5, 6)
leds.on()
:param int \*pins:
Specify the GPIO pins that the LEDs of the board are attached to. You
can designate as many pins as necessary.
:param bool pwm:
If ``True``, construct :class:`PWMLED` instances for each pin. If
``False`` (the default), construct regular :class:`LED` instances. This
parameter can only be specified as a keyword parameter.
"""

def close(self):
self._stop_blink()
super(LEDBoard, self).close()

@property
def value(self):
"""
A tuple containing a value for each LED on the board. This property can
also be set to update the state of all LEDs on the board.
"""
return tuple(led.value for led in self._leds)

@value.setter
def value(self, value):
self._stop_blink()
for l, v in zip(self.leds, value):
l.value = v

def on(self):
self._stop_blink()
super(LEDBoard, self).on()

def off(self):
self._stop_blink()
super(LEDBoard, self).off()

def toggle(self):
self._stop_blink()
super(LEDBoard, self).toggle()

def blink(
self, on_time=1, off_time=1, fade_in_time=0, fade_out_time=0,
n=None, background=True):
Expand Down Expand Up @@ -178,9 +200,96 @@ def _blink_device(self, on_time, off_time, fade_in_time, fade_out_time, n, fps=5
break


class LEDBarGraph(LEDCollection):
"""
Extends :class:`CompositeDevice` to control a line of LEDs representing a
bar graph. Positive values (0 to 1) light the LEDs from first to last.
Negative values (-1 to 0) light the LEDs from last to first.
The following example turns on all the LEDs on a board containing 5 LEDs
attached to GPIO pins 2 through 6::
from gpiozero import LEDBarGraph
graph = LEDBarGraph(2, 3, 4, 5, 6)
graph.value = 2/5 # Light the first two LEDs only
graph.value = -2/5 # Light the last two LEDs only
graph.off()
As with other output devices, :attr:`source` and :attr:`values` are
supported::
from gpiozero import LEDBarGraph, MCP3008
from signal import pause
graph = LEDBarGraph(2, 3, 4, 5, 6)
pot = MCP3008(channel=0)
graph.source = pot.values
pause()
:param int \*pins:
Specify the GPIO pins that the LEDs of the bar graph are attached to.
You can designate as many pins as necessary.
:param float initial_value:
The initial :attr:`value` of the graph given as a float between -1 and
+1. Defaults to 0.0.
"""

def __init__(self, *pins, **kwargs):
super(LEDBarGraph, self).__init__(*pins, pwm=False)
initial_value = kwargs.get('initial_value', 0)
self.value = initial_value

@property
def value(self):
"""
The value of the LED bar graph. When no LEDs are lit, the value is 0.
When all LEDs are lit, the value is 1. Values between 0 and 1
light LEDs linearly from first to last. Values between 0 and -1
light LEDs linearly from last to first.
To light a particular number of LEDs, simply divide that number by
the number of LEDs. For example, if your graph contains 3 LEDs, the
following will light the first::
from gpiozero import LEDBarGraph
graph = LEDBarGraph(12, 16, 19)
graph.value = 1/3
.. note::
Setting value to -1 will light all LEDs. However, querying it
subsequently will return 1 as both representations are the same in
hardware.
"""
for index, led in enumerate(self.leds):
if not led.is_lit:
break
else:
index = len(self.leds)
if not index:
for index, led in enumerate(reversed(self.leds)):
if not led.is_lit:
break
index = -index
return index / len(self.leds)

@value.setter
def value(self, value):
count = len(self.leds)
if value >= 0:
for index, led in enumerate(self.leds, start=1):
led.value = value >= (index / count)
else:
for index, led in enumerate(reversed(self.leds), start=1):
led.value = value <= -(index / count)


class PiLiter(LEDBoard):
"""
Extends :class:`LEDBoard` for the Ciseco Pi-LITEr: a strip of 8 very bright
Extends :class:`LEDBoard` for the `Ciseco Pi-LITEr`_: a strip of 8 very bright
LEDs.
The Pi-LITEr pins are fixed and therefore there's no need to specify them
Expand All @@ -196,11 +305,38 @@ class PiLiter(LEDBoard):
If ``True``, construct :class:`PWMLED` instances for each pin. If
``False`` (the default), construct regular :class:`LED` instances. This
parameter can only be specified as a keyword parameter.
.. _Ciseco Pi-LITEr: http://shop.ciseco.co.uk/pi-liter-8-led-strip-for-the-raspberry-pi/
"""
def __init__(self, pwm=False):
super(PiLiter, self).__init__(4, 17, 27, 18, 22, 23, 24, 25, pwm=pwm)


class PiLiterBarGraph(LEDBarGraph):
"""
Extends :class:`LEDBarGraph` to treat the `Ciseco Pi-LITEr`_ as an
8-segment bar graph.
The Pi-LITEr pins are fixed and therefore there's no need to specify them
when constructing this class. The following example sets the graph value
to 0.5::
from gpiozero import PiLiterBarGraph
graph = PiLiterBarGraph()
graph.value = 0.5
:param bool initial_value:
The initial value of the graph given as a float between -1 and +1.
Defaults to 0.0.
.. _Ciseco Pi-LITEr: http://shop.ciseco.co.uk/pi-liter-8-led-strip-for-the-raspberry-pi/
"""
def __init__(self, initial_value=0):
super(PiLiterBarGraph, self).__init__(
4, 17, 27, 18, 22, 23, 24, 25, initial_value=initial_value)


TrafficLightTuple = namedtuple('TrafficLightTuple', ('red', 'amber', 'green'))


Expand Down

0 comments on commit 0c2f750

Please sign in to comment.