diff --git a/MANIFEST.in b/MANIFEST.in index 40b7bf4..c0b7b32 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,3 @@ include README.rst recursive-include tests *.py +include LICENCE.txt diff --git a/README.rst b/README.rst index c3e5b55..8ecedd0 100644 --- a/README.rst +++ b/README.rst @@ -14,7 +14,7 @@ gpiozero :target: https://codecov.io/github/RPi-Distro/python-gpiozero :alt: Code Coverage -A simple interface to everyday GPIO components used with Raspberry Pi. +A simple interface to GPIO devices with Raspberry Pi. Created by `Ben Nuttall`_ of the `Raspberry Pi Foundation`_, `Dave Jones`_, and other contributors. @@ -93,20 +93,46 @@ Alternatively, email suggestions and feedback to ben@raspberrypi.org Contributors ============ -- `Ben Nuttall`_ (project maintainer) +Core developers: + +- `Ben Nuttall`_ - `Dave Jones`_ -- `Martin O'Hanlon`_ - `Andrew Scheller`_ + +Other contributors: + +- `Martin O'Hanlon`_ +- `Steve Amor`_ +- `David Glaude`_ +- `Edward Betts`_ +- `Alex Chan`_ +- `Thijs Triemstra`_ - `Schelto vanDoorn`_ +- `Alex Eames`_ +- `Barry Byford`_ +- `Clare Macrae`_ +- `Tim Golden`_ +- `Phil Howard`_ .. _Raspberry Pi Foundation: https://www.raspberrypi.org/ .. _GitHub: https://github.com/RPi-Distro/python-gpiozero .. _issues: https://github.com/RPi-Distro/python-gpiozero/issues .. _recipes: https://gpiozero.readthedocs.io/en/latest/recipes.html -.. _contribute: https://gpiozero.readthedocs.io/en/latest/contributing.html +.. _Contribute: https://gpiozero.readthedocs.io/en/latest/contributing.html .. _Ben Nuttall: https://github.com/bennuttall .. _Dave Jones: https://github.com/waveform80 -.. _Martin O'Hanlon: https://github.com/martinohanlon .. _Andrew Scheller: https://github.com/lurch -.. _Schelto vanDoorn: https://github.com/pcopa +.. _Martin O'Hanlon: https://github.com/martinohanlon +.. _Steve Amor: https://github.com/SteveAmor +.. _David Glaude: https://github.com/dglaude +.. _Edward Betts: https://github.com/edwardbetts +.. _Alex Chan: https://github.com/alexwlchan +.. _Thijs Triemstra: https://github.com/thijstriemstra +.. _Schelto vanDoorn: https://github.com/goloplo +.. _Alex Eames: https://github.com/raspitv +.. _Barry Byford: https://github.com/ukBaz +.. _Clare Macrae: https://github.com/claremacrae +.. _Tim Golden: https://github.com/tjguk +.. _Phil Howard: https://github.com/Gadgetoid + diff --git a/docs/contributing.rst b/docs/contributing.rst index d1c6d17..5c58da8 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -4,11 +4,7 @@ Contributing ============ -This module was designed for use in education; particularly for young children. -It is intended to provide a simple interface to everyday components. - -If a proposed change added an advanced feature but made basic usage more -complex, it is unlikely to be added. +Contributions to the library are welcome! Here are some guidelines to follow. Suggestions =========== @@ -33,8 +29,13 @@ Commit messages and pull requests Commit messages should be concise but descriptive, and in the form of a patch description, i.e. instructional not past tense ("Add LED example" not "Added -LED example"). Commits that close (or intend to close) an issue should use the -phrase "fix #123" where ``#123`` is the issue number. +LED example"). + +Commits which close (or intend to close) an issue should include the phrase +"fix #123" or "close #123" where ``#123`` is the issue number, as well as +include a short description, for example: "Add LED example, close #123", and +pull requests should aim to match or closely match the correspoding issue +title. Backwards compatibility ======================= @@ -42,11 +43,12 @@ Backwards compatibility Since this library reached v1.0 we aim to maintain backwards-compatibility thereafter. Changes which break backwards-compatibility will not be accepted. -Python -====== +Python 2/3 +========== -* Python 2/3 compatibility -* PEP8-compliance (with exceptions) +The library is 100% compatible with both Python 2 and 3. We intend to drop +Python 2 support in 2020 when Python 2 reaches `end-of-life`_. .. _docs: https://github.com/RPi-Distro/python-gpiozero/tree/master/docs .. _issue: https://github.com/RPi-Distro/python-gpiozero/issues +.. _end-of-life: http://legacy.python.org/dev/peps/pep-0373/ diff --git a/docs/examples/combining_sources.py b/docs/examples/combining_sources.py new file mode 100644 index 0000000..136314c --- /dev/null +++ b/docs/examples/combining_sources.py @@ -0,0 +1,11 @@ +from gpiozero import Button, LED +from gpiozero.tools import all_values +from signal import pause + +button_a = Button(2) +button_b = Button(3) +led = LED(17) + +led.source = all_values(button_a.values, button_b.values) + +pause() diff --git a/docs/examples/custom_generator.py b/docs/examples/custom_generator.py new file mode 100644 index 0000000..19a0f27 --- /dev/null +++ b/docs/examples/custom_generator.py @@ -0,0 +1,12 @@ +from gpiozero import LED +from random import randint +from signal import pause + +def rand(): + while True: + yield randint(0, 1) + +led = LED(17) +led.source = rand() + +pause() diff --git a/docs/examples/custom_generator_finite.py b/docs/examples/custom_generator_finite.py new file mode 100644 index 0000000..1678fa6 --- /dev/null +++ b/docs/examples/custom_generator_finite.py @@ -0,0 +1,7 @@ +from gpiozero import LED +from signal import pause + +led = LED(17) +led.source = [1, 0, 1, 1, 1, 0, 0, 1, 0, 1] + +pause() diff --git a/docs/examples/led_button.py b/docs/examples/led_button.py new file mode 100644 index 0000000..ba66df5 --- /dev/null +++ b/docs/examples/led_button.py @@ -0,0 +1,9 @@ +from gpiozero import LED, Button +from signal import pause + +led = LED(17) +button = Button(2) + +led.source = button.values + +pause() diff --git a/docs/examples/led_button_loop.py b/docs/examples/led_button_loop.py new file mode 100644 index 0000000..0b01872 --- /dev/null +++ b/docs/examples/led_button_loop.py @@ -0,0 +1,9 @@ +from gpiozero import LED, Button +from time import sleep + +led = LED(17) +button = Button(2) + +while True: + led.value = button.value + sleep(0.01) diff --git a/docs/examples/matching_leds.py b/docs/examples/matching_leds.py new file mode 100644 index 0000000..542a711 --- /dev/null +++ b/docs/examples/matching_leds.py @@ -0,0 +1,11 @@ +from gpiozero import LED, Button +from signal import pause + +red = LED(14) +green = LED(15) +button = Button(17) + +red.source = button.values +green.source = red.values + +pause() diff --git a/docs/examples/music_box.py b/docs/examples/music_box.py index 872b08e..80ac929 100644 --- a/docs/examples/music_box.py +++ b/docs/examples/music_box.py @@ -5,14 +5,12 @@ from signal import pause pygame.mixer.init() -sound_pins = { - 2: Sound("samples/drum_tom_mid_hard.wav"), - 3: Sound("samples/drum_cymbal_open.wav"), +button_sounds = { + Button(2): Sound("samples/drum_tom_mid_hard.wav"), + Button(3): Sound("samples/drum_cymbal_open.wav"), } -buttons = [Button(pin) for pin in sound_pins] -for button in buttons: - sound = sound_pins[button.pin.number] +for button, sound in button_sounds.items(): button.when_pressed = sound.play pause() diff --git a/docs/examples/negated.py b/docs/examples/negated.py new file mode 100644 index 0000000..2e5285e --- /dev/null +++ b/docs/examples/negated.py @@ -0,0 +1,10 @@ +from gpiozero import Button, LED +from gpiozero.tools import negated +from signal import pause + +led = LED(4) +btn = Button(17) + +led.source = negated(btn.values) + +pause() diff --git a/docs/examples/pwmled_pot.py b/docs/examples/pwmled_pot.py new file mode 100644 index 0000000..00e1e5c --- /dev/null +++ b/docs/examples/pwmled_pot.py @@ -0,0 +1,9 @@ +from gpiozero import PWMLED, MCP3008 +from signal import pause + +led = PWMLED(17) +pot = MCP3008() + +led.source = pot.values + +pause() diff --git a/docs/examples/random_values.py b/docs/examples/random_values.py new file mode 100644 index 0000000..524e456 --- /dev/null +++ b/docs/examples/random_values.py @@ -0,0 +1,9 @@ +from gpiozero import PWMLED +from gpiozero.tools import random_values +from signal import pause + +led = PWMLED(4) +led.source = random_values() +led.source_delay = 0.1 + +pause() diff --git a/docs/examples/robot_buttons.py b/docs/examples/robot_buttons_1.py similarity index 100% rename from docs/examples/robot_buttons.py rename to docs/examples/robot_buttons_1.py diff --git a/docs/examples/robot_buttons_2.py b/docs/examples/robot_buttons_2.py new file mode 100644 index 0000000..56241f3 --- /dev/null +++ b/docs/examples/robot_buttons_2.py @@ -0,0 +1,34 @@ +from gpiozero import Button, Robot +from time import sleep +from signal import pause + +robot = Robot((17, 18), (22, 23)) + +left = Button(2) +right = Button(3) +forward = Button(4) +backward = Button(5) +go = Button(6) + +instructions = [] + +def add_instruction(btn): + instructions.append({ + left: (-1, 1), + right: (1, -1), + forward: (1, 1), + backward: (-1, -1), + }[btn]) + +def do_instructions(): + instructions.append((0, 0)) + robot.source_delay = 0.5 + robot.source = instructions + sleep(robot.source_delay * len(instructions)) + del instructions[:] + +go.when_pressed = do_instructions +for button in (left, right, forward, backward): + button.when_pressed = add_instruction + +pause() diff --git a/docs/examples/source_value_processing.py b/docs/examples/source_value_processing.py new file mode 100644 index 0000000..bd2b845 --- /dev/null +++ b/docs/examples/source_value_processing.py @@ -0,0 +1,13 @@ +from gpiozero import Button, LED +from signal import pause + +def opposite(values): + for value in values: + yield not value + +led = LED(4) +btn = Button(17) + +led.source = opposite(btn.values) + +pause() diff --git a/docs/images/combining_sources.png b/docs/images/combining_sources.png new file mode 100644 index 0000000..5f9c98e Binary files /dev/null and b/docs/images/combining_sources.png differ diff --git a/docs/images/custom_generator.png b/docs/images/custom_generator.png new file mode 100644 index 0000000..1434cb6 Binary files /dev/null and b/docs/images/custom_generator.png differ diff --git a/docs/images/source_tool.png b/docs/images/source_tool.png new file mode 100644 index 0000000..9563abf Binary files /dev/null and b/docs/images/source_tool.png differ diff --git a/docs/images/source_tool_value_processor.png b/docs/images/source_tool_value_processor.png new file mode 100644 index 0000000..0c6f177 Binary files /dev/null and b/docs/images/source_tool_value_processor.png differ diff --git a/docs/images/source_value_processing.png b/docs/images/source_value_processing.png new file mode 100644 index 0000000..c31aed5 Binary files /dev/null and b/docs/images/source_value_processing.png differ diff --git a/docs/images/source_values.png b/docs/images/source_values.png new file mode 100644 index 0000000..a424928 Binary files /dev/null and b/docs/images/source_values.png differ diff --git a/docs/index.rst b/docs/index.rst index 6ea2d2a..af73305 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -19,6 +19,7 @@ Table of Contents api_pins api_exc cli_tools + source_values changelog license diff --git a/docs/recipes.rst b/docs/recipes.rst index 6ca48d7..5c64dd3 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -331,8 +331,12 @@ Button controlled robot Use four GPIO buttons as forward/back/left/right controls for a robot: -.. literalinclude:: examples/robot_buttons.py +.. literalinclude:: examples/robot_buttons_1.py +Alternatively, use four buttons to program the directions and add a fifth +button to process them in turn, like a Bee-Bot or Turtle robot. + +.. literalinclude:: examples/robot_buttons_2.py Keyboard controlled robot ========================= diff --git a/docs/source_values.rst b/docs/source_values.rst new file mode 100644 index 0000000..4b108d9 --- /dev/null +++ b/docs/source_values.rst @@ -0,0 +1,127 @@ +============= +Source/Values +============= + +.. currentmodule:: gpiozero + +GPIO Zero provides a method of using the declarative programming paradigm to +connect devices together: feeding the values of one device into another, for +example the values of a button into an LED: + +.. literalinclude:: examples/led_button.py + +which is equivalent to: + +.. literalinclude:: examples/led_button_loop.py + +Every device has a ``.value`` property (the device's current value). Input +devices can only have their values read, but output devices can also have their +value set to alter the state of the device:: + + >>> led = PWMLED(17) + >>> led.value # LED is initially off + 0.0 + >>> led.on() # LED is now on + >>> led.value + 1.0 + >>> led.value = 0 # LED is now off + +Every device also has a ``.values`` property (a generator continuously yielding +the device's current value). All output devices have a ``.source`` property +which can be set to any iterator. The device will iterate over the values +provided, setting the device's value to each element at a rate specified in the +``source_delay`` property. + +.. image:: images/source_values.* + +The most common use case for this is to set the source of an output device to +the values of an input device, like the example above. A more interesting +example would be a potentiometer controlling the brightness of an LED: + +.. literalinclude:: examples/pwmled_pot.py + +It is also possible to set an output device's ``source`` to the ``values`` of +another output device, to keep them matching: + +.. literalinclude:: examples/matching_leds.py + +The device's values can also be processed before they are passed to the +``source``: + +.. image:: images/source_value_processing.* + +For example: + +.. literalinclude:: examples/source_value_processing.py + +Alternatively, a custom generator can be used to provide values from an +artificial source: + +.. image:: images/custom_generator.* + +For example: + +.. literalinclude:: examples/custom_generator.py + +If the iterator is infinite (i.e. an infinite generator), the elements will be +processed until the ``source`` is changed or set to ``None``. + +If the iterator is finite (e.g. a list), this will terminate once all elements +are processed (leaving the device's value at the final element): + +.. literalinclude:: examples/custom_generator_finite.py + +Composite devices +----------------- + +Most devices have a ``value`` range between 0 and 1. Some have a range between +-1 and 1 (e.g. ``Motor``). The ``value`` of a composite device is a namedtuple +of such values. For example, the ``Robot`` class:: + + >>> from gpiozero import Robot + >>> robot = Robot(left=(14, 15), right=(17, 18)) + >>> robot.value + RobotValue(left_motor=0.0, right_motor=0.0) + >>> tuple(robot.value) + (0.0, 0.0) + >>> robot.forward() + >>> tuple(robot.value) + (1.0, 1.0) + >>> robot.backward() + >>> tuple(robot.value) + (-1.0, -1.0) + >>> robot.value = (1, 1) # robot is now driven forwards + +Source Tools +------------ + +GPIO Zero provides a set of ready-made functions for dealing with source/values, +called source tools. These are available by importing from ``gpiozero.tools``. + +Some of these source tools are artificial sources which require no input: + +.. image:: images/source_tool.* + +In this example, random values between 0 and 1 are passed to the LED, giving it +a flickering candle effect: + +.. literalinclude:: examples/random_values.py + +Some tools take a single source and process its values: + +.. image:: images/source_tool_value_processor.* + +In this example, the LED is lit only when the button is not pressed: + +.. literalinclude:: examples/negated.py + +Some tools combine the values of multiple sources: + +.. image:: images/combining_sources.* + +In this example, the LED is lit only if both buttons are pressed (like an `AND`_ +gate): + +.. _AND: https://en.wikipedia.org/wiki/AND_gate + +.. literalinclude:: examples/combining_sources.py diff --git a/setup.py b/setup.py index 6d70a29..d737b3c 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ import os import sys from setuptools import setup, find_packages -"A simple interface to everyday GPIO components used with Raspberry Pi" +"A simple interface to GPIO devices with Raspberry Pi." if sys.version_info[0] == 2: if not sys.version_info >= (2, 7): @@ -22,7 +22,7 @@ except ImportError: pass __project__ = 'gpiozero' -__version__ = '1.3.1' +__version__ = '1.3.1.post1' __author__ = 'Ben Nuttall' __author_email__ = 'ben@raspberrypi.org' __url__ = 'https://github.com/RPi-Distro/python-gpiozero'