Skip to content

Commit

Permalink
Merge branch 'master' of github.com:rpi-distro/python-gpiozero
Browse files Browse the repository at this point in the history
  • Loading branch information
bennuttall committed Feb 12, 2016
2 parents 052a998 + 0978b4c commit b3ef744
Show file tree
Hide file tree
Showing 14 changed files with 599 additions and 17 deletions.
2 changes: 2 additions & 0 deletions docs/api_exc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ so you can still do::

.. autoexception:: GPIOBadQueueLen

.. autoexception:: GPIOBadSampleWait

.. autoexception:: InputDeviceError

.. autoexception:: OutputDeviceError
Expand Down
12 changes: 10 additions & 2 deletions docs/api_input.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ Button
:members: wait_for_press, wait_for_release, pin, is_pressed, pull_up, when_pressed, when_released


Motion Sensor (PIR)
===================
Motion Sensor (D-SUN PIR)
=========================

.. autoclass:: MotionSensor(pin, queue_len=1, sample_rate=10, threshold=0.5, partial=False)
:members: wait_for_motion, wait_for_no_motion, pin, motion_detected, when_motion, when_no_motion
Expand All @@ -33,6 +33,14 @@ Light Sensor (LDR)
.. autoclass:: LightSensor(pin, queue_len=5, charge_time_limit=0.01, threshold=0.1, partial=False)
:members: wait_for_light, wait_for_dark, pin, light_detected, when_light, when_dark


Distance Sensor (HC-SR04)
=========================

.. autoclass:: DistanceSensor(echo, trigger, queue_len=30, max_distance=1, threshold_distance=0.3, partial=False)
:members: wait_for_in_range, wait_for_out_of_range, trigger, echo, when_in_range, when_out_of_range, max_distance, distance, threshold_distance


Analog to Digital Converters (ADC)
==================================

Expand Down
48 changes: 37 additions & 11 deletions docs/api_pins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ integer number instead, it uses one of the following classes to provide the

2. :class:`gpiozero.pins.rpio.RPIOPin`

3. :class:`gpiozero.pins.native.NativePin`
3. :class:`gpiozero.pins.pigpiod.PiGPIOPin`

4. :class:`gpiozero.pins.native.NativePin`

You can change the default pin implementation by over-writing the
``DefaultPin`` global in devices like so::
``DefaultPin`` global in the ``devices`` module like so::

from gpiozero.pins.native import NativePin
import gpiozero.devices
Expand All @@ -35,8 +37,24 @@ You can change the default pin implementation by over-writing the
# This will now use NativePin instead of RPiGPIOPin
led = LED(16)

In future, this separation should allow the library to utilize pins that are
part of IO extender chips. For example::
Alternatively, instead of passing an integer to the device constructor, you
can pass a :class:`Pin` object itself::

from gpiozero.pins.native import NativePin
from gpiozero import LED

led = LED(NativePin(16))

This is particularly useful with implementations that can take extra parameters
such as :class:`PiGPIOPin` which can address pins on remote machines::

from gpiozero.pins.pigpiod import PiGPIOPin
from gpiozero import LED

led = LED(PiGPIOPin(16, host='my_other_pi'))

In future, this separation of pins and devices should also permit the library
to utilize pins that are part of IO extender chips. For example::

from gpiozero import IOExtender, LED

Expand All @@ -52,13 +70,6 @@ part of IO extender chips. For example::
comments from testers!


Abstract Pin
============

.. autoclass:: Pin
:members:


RPiGPIOPin
==========

Expand All @@ -75,10 +86,25 @@ RPIOPin
.. autoclass:: RPIOPin


PiGPIOPin
=========

.. currentmodule:: gpiozero.pins.pigpiod

.. autoclass:: PiGPIOPin


NativePin
=========

.. currentmodule:: gpiozero.pins.native

.. autoclass:: NativePin


Abstract Pin
============

.. autoclass:: Pin
:members:

1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def __getattr__(cls, name):
sys.modules['RPi.GPIO'] = sys.modules['RPi'].GPIO
sys.modules['RPIO'] = Mock()
sys.modules['RPIO.PWM'] = sys.modules['RPIO'].PWM
sys.modules['pigpio'] = Mock()
sys.modules['w1thermsensor'] = Mock()
sys.modules['spidev'] = Mock()

Expand Down
43 changes: 43 additions & 0 deletions docs/recipes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,36 @@ level::
pause()


Distance sensor
===============

.. IMAGE TBD
Have a :class:`DistanceSensor` detect the distance to the nearest object::

from gpiozero import DistanceSensor
from time import sleep

sensor = DistanceSensor(23, 24)

while True:
print('Distance to nearest object is', sensor.distance, 'm')
sleep(1)

Run a function when something gets near the sensor::

from gpiozero import DistanceSensor, LED
from signal import pause

sensor = DistanceSensor(23, 24, max_distance=1, threshold_distance=0.2)
led = LED(16)

sensor.when_in_range = led.on
sensor.when_out_of_range = led.off

pause()


Motors
======

Expand Down Expand Up @@ -480,6 +510,19 @@ Make a :class:`Robot` drive around in (roughly) a square::
robot.right()
sleep(1)

Make a robot with a distance sensor that runs away when things get within
20cm of it::

from gpiozero import Robot, DistanceSensor
from signal import pause

sensor = DistanceSensor(23, 24, max_distance=1, threshold_distance=0.2)
robot = Robot(left=(4, 14), right=(17, 18))

sensor.when_in_range = robot.backward
sensor.when_out_of_range = robot.stop
pause()


Button controlled robot
=======================
Expand Down
2 changes: 2 additions & 0 deletions gpiozero/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
GPIOPinInUse,
GPIOPinMissing,
GPIOBadQueueLen,
GPIOBadSampleWait,
InputDeviceError,
OutputDeviceError,
OutputDeviceBadValue,
Expand Down Expand Up @@ -48,6 +49,7 @@
LineSensor,
MotionSensor,
LightSensor,
DistanceSensor,
AnalogInputDevice,
MCP3008,
MCP3004,
Expand Down
26 changes: 26 additions & 0 deletions gpiozero/compat.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# vim: set fileencoding=utf-8:

from __future__ import (
unicode_literals,
absolute_import,
Expand Down Expand Up @@ -25,3 +27,27 @@ def isclose(a, b, rel_tol=1e-9, abs_tol=0.0):
(diff <= abs(rel_tol * a)) or
(diff <= abs_tol)
)


# Backported from py3.4
def mean(data):
if iter(data) is data:
data = list(data)
n = len(data)
if not n:
raise ValueError('cannot calculate mean of empty data')
return sum(data) / n


# Backported from py3.4
def median(data):
data = sorted(data)
n = len(data)
if not n:
raise ValueError('cannot calculate median of empty data')
elif n % 2:
return data[n // 2]
else:
i = n // 2
return (data[n - 1] + data[n]) / 2

23 changes: 19 additions & 4 deletions gpiozero/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,17 @@
from threading import Thread, Event, RLock
from collections import deque
from types import FunctionType
try:
from statistics import median, mean
except ImportError:
from .compat import median, mean

from .exc import (
GPIOPinMissing,
GPIOPinInUse,
GPIODeviceClosed,
GPIOBadQueueLen,
GPIOBadSampleWait,
)

# Get a pin implementation to use as the default; we prefer RPi.GPIO's here
Expand All @@ -33,8 +38,12 @@
from .pins.rpio import RPIOPin
DefaultPin = RPIOPin
except ImportError:
from .pins.native import NativePin
DefaultPin = NativePin
try:
from .pins.pigipod import PiGPIOPin
DefaultPin = PiGPIOPin
except ImportError:
from .pins.native import NativePin
DefaultPin = NativePin


_THREADS = set()
Expand Down Expand Up @@ -344,23 +353,29 @@ def join(self):


class GPIOQueue(GPIOThread):
def __init__(self, parent, queue_len=5, sample_wait=0.0, partial=False):
def __init__(
self, parent, queue_len=5, sample_wait=0.0, partial=False,
average=median):
assert isinstance(parent, GPIODevice)
assert callable(average)
super(GPIOQueue, self).__init__(target=self.fill)
if queue_len < 1:
raise GPIOBadQueueLen('queue_len must be at least one')
if sample_wait < 0:
raise GPIOBadSampleWait('sample_wait must be 0 or greater')
self.queue = deque(maxlen=queue_len)
self.partial = partial
self.sample_wait = sample_wait
self.full = Event()
self.parent = weakref.proxy(parent)
self.average = average

@property
def value(self):
if not self.partial:
self.full.wait()
try:
return sum(self.queue) / len(self.queue)
return self.average(self.queue)
except ZeroDivisionError:
# No data == inactive value
return 0.0
Expand Down
3 changes: 3 additions & 0 deletions gpiozero/exc.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ class GPIOPinMissing(GPIODeviceError, ValueError):
class GPIOBadQueueLen(GPIODeviceError, ValueError):
"Error raised when non-positive queue length is specified"

class GPIOBadSampleWait(GPIODeviceError, ValueError):
"Error raised when a negative sampling wait period is specified"

class InputDeviceError(GPIODeviceError):
"Base class for errors specific to the InputDevice hierarchy"

Expand Down

0 comments on commit b3ef744

Please sign in to comment.