Add pin_factory param to all devices

And some docs ...
This commit is contained in:
Dave Jones
2017-07-14 10:44:24 +01:00
parent 1ca017fc6d
commit 8958874a77
16 changed files with 619 additions and 196 deletions

View File

@@ -16,35 +16,35 @@ everyday components. Components must be wired up correctly before use in code.
Button
======
.. autoclass:: Button(pin, pull_up=True, bounce_time=None, hold_time=1, hold_repeat=False)
.. autoclass:: Button(pin, pull_up=True, bounce_time=None, hold_time=1, hold_repeat=False, pin_factory=None)
:members: wait_for_press, wait_for_release, pin, is_pressed, is_held, hold_time, held_time, hold_repeat, pull_up, when_pressed, when_released, when_held
Line Sensor (TRCT5000)
======================
.. autoclass:: LineSensor(pin, queue_len=5, sample_rate=100, threshold=0.5, partial=False)
.. autoclass:: LineSensor(pin, queue_len=5, sample_rate=100, threshold=0.5, partial=False, pin_factory=None)
:members: wait_for_line, wait_for_no_line, pin, line_detected, when_line, when_no_line
Motion Sensor (D-SUN PIR)
=========================
.. autoclass:: MotionSensor(pin, queue_len=1, sample_rate=10, threshold=0.5, partial=False)
.. autoclass:: MotionSensor(pin, queue_len=1, sample_rate=10, threshold=0.5, partial=False, pin_factory=None)
:members: wait_for_motion, wait_for_no_motion, pin, motion_detected, when_motion, when_no_motion
Light Sensor (LDR)
==================
.. autoclass:: LightSensor(pin, queue_len=5, charge_time_limit=0.01, threshold=0.1, partial=False)
.. autoclass:: LightSensor(pin, queue_len=5, charge_time_limit=0.01, threshold=0.1, partial=False, pin_factory=None)
: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)
.. autoclass:: DistanceSensor(echo, trigger, queue_len=30, max_distance=1, threshold_distance=0.3, partial=False, pin_factory=None)
:members: wait_for_in_range, wait_for_out_of_range, trigger, echo, when_in_range, when_out_of_range, max_distance, distance, threshold_distance
Base Classes
@@ -63,7 +63,7 @@ to construct classes for their own devices.
DigitalInputDevice
==================
.. autoclass:: DigitalInputDevice(pin, pull_up=False, bounce_time=None)
.. autoclass:: DigitalInputDevice(pin, pull_up=False, bounce_time=None, pin_factory=None)
:members:
SmoothedInputDevice
@@ -75,12 +75,12 @@ SmoothedInputDevice
InputDevice
===========
.. autoclass:: InputDevice(pin, pull_up=False)
.. autoclass:: InputDevice(pin, pull_up=False, pin_factory=None)
:members:
GPIODevice
==========
.. autoclass:: GPIODevice(pin)
.. autoclass:: GPIODevice(pin, pin_factory=None)
:members:

View File

@@ -11,10 +11,23 @@ are concerned with. However, some users may wish to take advantage of the
capabilities of alternative GPIO implementations or (in future) use GPIO
extender chips. This is the purpose of the pins portion of the library.
When you construct a device, you pass in a pin specification. However, what the
library actually expects is a :class:`Pin` implementation. If it finds anything
else, it uses the existing ``Device.pin_factory`` to construct a :class:`Pin`
implementation based on the specification.
When you construct a device, you pass in a pin specification. This is passed to
a pin :class:`Factory` which turns it into a :class:`Pin` implementation. The
default factory can be queried (and changed) with ``Device.pin_factory``, i.e.
the ``pin_factory`` attribute of the :class:`Device` class. However, all
classes accept a ``pin_factory`` keyword argument to their constructors
permitting the factory to be overridden on a per-device basis (the reason for
allowing per-device factories is made apparent later in the :doc:`remote_gpio`
chapter).
This is illustrated in the following flow-chart:
.. image:: images/device_pin_flowchart.*
The default factory is constructed when GPIO Zero is first imported; if no
default factory can be constructed (e.g. because no GPIO implementations are
installed, or all of them fail to load for whatever reason), an
:exc:`ImportError` will be raised.
Changing the pin factory
========================
@@ -24,7 +37,7 @@ The default pin factory can be replaced by specifying a value for the
.. code-block:: console
pi@raspberrypi $ GPIOZERO_PIN_FACTORY=native python
$ GPIOZERO_PIN_FACTORY=native python
Python 3.4.2 (default, Oct 19 2014, 13:31:11)
[GCC 4.9.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
@@ -37,8 +50,8 @@ export this value:
.. code-block:: console
pi@raspberrypi $ export GPIOZERO_PIN_FACTORY=native
pi@raspberrypi $ python
$ export GPIOZERO_PIN_FACTORY=native
$ python
Python 3.4.2 (default, Oct 19 2014, 13:31:11)
[GCC 4.9.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
@@ -46,7 +59,7 @@ export this value:
>>> gpiozero.Device.pin_factory
<gpiozero.pins.native.NativeFactory object at 0x762c26b0>
>>> quit()
pi@raspberrypi $ python
$ python
Python 3.4.2 (default, Oct 19 2014, 13:31:11)
[GCC 4.9.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
@@ -73,17 +86,30 @@ they are tried by default.
| native | :class:`gpiozero.pins.native.NativeFactory` | :class:`gpiozero.pins.native.NativePin` |
+---------+-----------------------------------------------+-------------------------------------------+
If you need to change the default pin factory from within a script, set
If you need to change the default pin factory from within a script, either set
``Device.pin_factory`` to the new factory instance to use::
from gpiozero.pins.native import NativeFactory
from gpiozero import *
from gpiozero import Device, LED
Device.pin_factory = NativeFactory()
# These will now implicitly use NativePin instead of
# RPiGPIOPin
led1 = LED(16)
led2 = LED(17)
Or use the ``pin_factory`` keyword parameter mentioned above::
from gpiozero.pins.native import NativeFactory
from gpiozero import LED
# This will now use NativePin instead of RPiGPIOPin
led = LED(16)
my_factory = NativeFactory()
# This will use NativePin instead of RPiGPIOPin for led1
# but led2 will continue to use RPiGPIOPin
led1 = LED(16, pin_factory=my_factory)
led2 = LED(17)
Certain factories may take default information from additional sources.
For example, to default to creating pins with
@@ -100,11 +126,13 @@ Like the ``GPIOZERO_PIN_FACTORY`` value, these can be exported from your
.. warning::
The astute and mischievous reader may note that it is possible to mix pin
implementations, e.g. using ``RPiGPIOPin`` for one pin, and ``NativePin``
for another. This is unsupported, and if it results in your script
crashing, your components failing, or your Raspberry Pi turning into an
actual raspberry pie, you have only yourself to blame.
The astute and mischievous reader may note that it is possible to mix
strictly local pin implementations, e.g. using ``RPiGPIOPin`` for one pin,
and ``NativePin`` for another. This is unsupported, and if it results in
your script crashing, your components failing, or your Raspberry Pi turning
into an actual raspberry pie, you have only yourself to blame.
Sensible uses of multiple pin factories are given in :doc:`remote_gpio`.
RPi.GPIO

View File

@@ -0,0 +1,19 @@
/* vim: set et sw=4 sts=4: */
digraph device_pins {
graph [rankdir=TB];
node [shape=rect, shape=filled, fontname=Sans, fontsize=10];
edge [fontname=Sans, fontsize=10];
constructor [label="LED(pin_spec, ...,\npin_factory=None)"];
pin_factory_kwarg [shape=diamond,label="pin_factory == None?"];
default_factory [label="self.pin_factory = Device.pin_factory"];
override_factory [label="self.pin_factory = pin_factory"];
factory_pin [label="self.pin = self.pin_factory.pin(pin_spec)"];
constructor->pin_factory_kwarg;
pin_factory_kwarg->default_factory [label="yes"];
pin_factory_kwarg->override_factory [label="no"];
default_factory->factory_pin;
override_factory->factory_pin;
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: device_pins Pages: 1 -->
<svg width="372pt" height="273pt"
viewBox="0.00 0.00 371.50 273.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 269)">
<title>device_pins</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-269 367.5,-269 367.5,4 -4,4"/>
<!-- constructor -->
<g id="node1" class="node"><title>constructor</title>
<polygon fill="none" stroke="black" points="243.5,-265 136.5,-265 136.5,-229 243.5,-229 243.5,-265"/>
<text text-anchor="middle" x="190" y="-250" font-family="Sans" font-size="10.00">LED(pin_spec, ...,</text>
<text text-anchor="middle" x="190" y="-239" font-family="Sans" font-size="10.00">pin_factory=None)</text>
</g>
<!-- pin_factory_kwarg -->
<g id="node2" class="node"><title>pin_factory_kwarg</title>
<polygon fill="none" stroke="black" points="190,-192 88.3711,-174 190,-156 291.629,-174 190,-192"/>
<text text-anchor="middle" x="190" y="-171.5" font-family="Sans" font-size="10.00">pin_factory == None?</text>
</g>
<!-- constructor&#45;&gt;pin_factory_kwarg -->
<g id="edge1" class="edge"><title>constructor&#45;&gt;pin_factory_kwarg</title>
<path fill="none" stroke="black" d="M190,-228.813C190,-220.789 190,-211.047 190,-202.069"/>
<polygon fill="black" stroke="black" points="193.5,-202.029 190,-192.029 186.5,-202.029 193.5,-202.029"/>
</g>
<!-- default_factory -->
<g id="node3" class="node"><title>default_factory</title>
<polygon fill="none" stroke="black" points="190,-109 0,-109 0,-73 190,-73 190,-109"/>
<text text-anchor="middle" x="95" y="-88.5" font-family="Sans" font-size="10.00">self.pin_factory = Device.pin_factory</text>
</g>
<!-- pin_factory_kwarg&#45;&gt;default_factory -->
<g id="edge2" class="edge"><title>pin_factory_kwarg&#45;&gt;default_factory</title>
<path fill="none" stroke="black" d="M173.452,-158.891C159.473,-146.971 139.158,-129.65 122.703,-115.621"/>
<polygon fill="black" stroke="black" points="124.861,-112.861 114.98,-109.036 120.319,-118.187 124.861,-112.861"/>
<text text-anchor="middle" x="157.5" y="-130" font-family="Sans" font-size="10.00">yes</text>
</g>
<!-- override_factory -->
<g id="node4" class="node"><title>override_factory</title>
<polygon fill="none" stroke="black" points="363.5,-109 208.5,-109 208.5,-73 363.5,-73 363.5,-109"/>
<text text-anchor="middle" x="286" y="-88.5" font-family="Sans" font-size="10.00">self.pin_factory = pin_factory</text>
</g>
<!-- pin_factory_kwarg&#45;&gt;override_factory -->
<g id="edge3" class="edge"><title>pin_factory_kwarg&#45;&gt;override_factory</title>
<path fill="none" stroke="black" d="M206.722,-158.891C220.849,-146.971 241.377,-129.65 258.005,-115.621"/>
<polygon fill="black" stroke="black" points="260.424,-118.16 265.809,-109.036 255.909,-112.81 260.424,-118.16"/>
<text text-anchor="middle" x="250.5" y="-130" font-family="Sans" font-size="10.00">no</text>
</g>
<!-- factory_pin -->
<g id="node5" class="node"><title>factory_pin</title>
<polygon fill="none" stroke="black" points="311,-36 111,-36 111,-0 311,-0 311,-36"/>
<text text-anchor="middle" x="211" y="-15.5" font-family="Sans" font-size="10.00">self.pin = self.pin_factory.pin(pin_spec)</text>
</g>
<!-- default_factory&#45;&gt;factory_pin -->
<g id="edge4" class="edge"><title>default_factory&#45;&gt;factory_pin</title>
<path fill="none" stroke="black" d="M122.785,-72.9937C138.167,-63.5785 157.484,-51.7554 174.117,-41.5748"/>
<polygon fill="black" stroke="black" points="176.338,-44.3193 183.04,-36.1136 172.683,-38.3489 176.338,-44.3193"/>
</g>
<!-- override_factory&#45;&gt;factory_pin -->
<g id="edge5" class="edge"><title>override_factory&#45;&gt;factory_pin</title>
<path fill="none" stroke="black" d="M267.845,-72.8129C258.448,-63.9174 246.82,-52.9094 236.533,-43.1717"/>
<polygon fill="black" stroke="black" points="238.656,-40.3619 228.988,-36.0288 233.844,-45.4454 238.656,-40.3619"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@@ -9,42 +9,58 @@ operating systems, including for PCs using the :doc:`remote_gpio` feature.
Raspberry Pi
============
First, update your repositories list::
First, update your repositories list:
sudo apt update
.. code-block:: console
Then install the package for Python 3::
pi@raspberrypi:~$ sudo apt update
sudo apt install python3-gpiozero
Then install the package for Python 3:
or Python 2::
.. code-block:: console
sudo apt install python-gpiozero
pi@raspberrypi:~$ sudo apt install python3-gpiozero
or Python 2:
.. code-block:: console
pi@raspberrypi:~$ sudo apt install python-gpiozero
Linux
=====
First, update your distribution's repositories list. For example::
First, update your distribution's repositories list. For example:
sudo apt update
.. code-block:: console
Then install pip for Python 3::
$ sudo apt update
sudo apt install python3-pip
Then install pip for Python 3:
or Python 3::
.. code-block:: console
sudo apt install python-pip
$ sudo apt install python3-pip
or Python 3:
.. code-block:: console
$ sudo apt install python-pip
(Alternatively, install pip with `get-pip`_.)
Next, install gpiozero for Python 3::
Next, install gpiozero for Python 3:
sudo pip3 install gpiozero
.. code-block:: console
or Python 2::
$ sudo pip3 install gpiozero
sudo pip install gpiozero
or Python 2:
.. code-block:: console
$ sudo pip install gpiozero
.. note::
@@ -55,24 +71,32 @@ or Python 2::
Mac OS
======
First, install pip::
First, install pip:
???
.. code-block:: console
Next, install gpiozero with pip::
$ ???
pip install gpiozero
Next, install gpiozero with pip:
.. code-block:: console
$ pip install gpiozero
Windows
=======
First, install pip::
First, install pip:
???
.. code-block:: doscon
Next, install gpiozero with pip::
C:\Users\user1> ???
pip install gpiozero
Next, install gpiozero with pip:
.. code-block:: doscon
C:\Users\user1> pip install gpiozero
.. _Raspbian Jessie: https://www.raspberrypi.org/downloads/raspbian/

View File

@@ -102,4 +102,4 @@ the ``pip`` utility. This can be done with the following command in Raspbian:
Alternatively, install pip with `get-pip`_.
.. _get_pip: https://pip.pypa.io/en/stable/installing/
.. _get-pip: https://pip.pypa.io/en/stable/installing/

View File

@@ -36,7 +36,9 @@ functionality without the need to wire up your own LEDs (also useful because
the power and activity LEDs are "known good").
Firstly you need to disable the usual triggers for the built-in LEDs. This can
be done from the terminal with the following commands::
be done from the terminal with the following commands:
.. code-block:: console
$ echo none | sudo tee /sys/class/leds/led0/trigger
$ echo gpio | sudo tee /sys/class/leds/led1/trigger
@@ -46,7 +48,9 @@ Now you can control the LEDs with gpiozero like so:
.. literalinclude:: examples/led_builtin.py
To revert the LEDs to their usual purpose you can either reboot your Pi or
run the following commands::
run the following commands:
.. code-block:: console
$ echo mmc0 | sudo tee /sys/class/leds/led0/trigger
$ echo input | sudo tee /sys/class/leds/led1/trigger

View File

@@ -7,7 +7,7 @@ Remote GPIO
GPIO Zero supports a number of different pin implementations (low-level pin
libraries which deal with the GPIO pins directly). By default, the `RPi.GPIO`_
library is used (assuming it is installed on your system), but you can
optionally specify one to use. For more information, see the :doc:`pins`
optionally specify one to use. For more information, see the :doc:`api_pins`
documentation page.
One of the pin libraries supported, `pigpio`_, provides the ability to control
@@ -23,9 +23,11 @@ Preparing the Raspberry Pi
If you're using Raspbian Jessie (desktop - not Jessie Lite) then you have
everything you need to use the remote GPIO feature. If you're using Jessie Lite,
or another distribution, you'll need to install pigpio::
or another distribution, you'll need to install pigpio:
sudo apt install pigpio
.. code-block:: console
$ sudo apt install pigpio
Then you just need to enable **Remote GPIO** in the Raspberry Pi configuration
tool:
@@ -34,21 +36,25 @@ tool:
(Alternatively, use ``sudo raspi-config`` on the command line)
Then launch the pigpio daemon::
Then launch the pigpio daemon:
sudo pigpiod
.. code-block:: console
$ sudo pigpiod
To only allow connections from a specific IP address, use the ``-n`` flag. For
example::
example:
sudo pigpiod -n localhost # allow localhost only
sudo pigpiod -n 192.168.1.65 # allow 192.168.1.65 only
sudo pigpiod -n localhost -n 192.168.1.65 # allow localhost and 192.168.1.65 only
.. code-block:: console
$ sudo pigpiod -n localhost # allow localhost only
$ sudo pigpiod -n 192.168.1.65 # allow 192.168.1.65 only
$ sudo pigpiod -n localhost -n 192.168.1.65 # allow localhost and 192.168.1.65 only
You will need to launch the pigpio daemon every time you wish to use this
feature. To automate running the daemon at boot time::
sudo systemctl enable pigpiod
$ sudo systemctl enable pigpiod
Preparing the host computer
===========================
@@ -61,72 +67,100 @@ Python library on the PC.
Raspberry Pi
------------
First, update your repositories list::
First, update your repositories list:
sudo apt update
.. code-block:: console
Then install the pigpio library for Python 3::
$ sudo apt update
sudo apt install python3-pigpio
Then install the pigpio library for Python 3:
or Python 2::
.. code-block:: console
sudo apt install python-pigpio
$ sudo apt install python3-pigpio
Alternatively, install with pip::
or Python 2:
sudo pip3 install pigpio
.. code-block:: console
or::
$ sudo apt install python-pigpio
sudo pip install pigpio
Alternatively, install with pip:
.. code-block:: console
$ sudo pip3 install pigpio
or:
.. code-block:: console
$ sudo pip install pigpio
Linux
-----
First, update your distribution's repositories list. For example::
First, update your distribution's repositories list. For example:
sudo apt update
.. code-block:: console
Then install pip for Python 3::
$ sudo apt update
sudo apt install python3-pip
Then install pip for Python 3:
or Python 2::
.. code-block:: console
sudo apt install python-pip
$ sudo apt install python3-pip
or Python 2:
.. code-block:: console
$ sudo apt install python-pip
(Alternatively, install pip with `get-pip`_.)
Next, install pigpio for Python 3::
Next, install pigpio for Python 3:
sudo pip3 install pigpio
.. code-block:: console
or Python 2::
$ sudo pip3 install pigpio
sudo pip install pigpio
or Python 2:
.. code-block:: console
$ sudo pip install pigpio
Mac OS
------
First, install pip::
First, install pip:
???
.. code-block:: console
Next, install pigpio with pip::
$ ???
pip install pigpio
Next, install pigpio with pip:
.. code-block:: console
$ pip install pigpio
Windows
-------
First install pip::
First install pip:
???
.. code-block:: doscon
Next, install pigpio with pip::
C:\Users\user1> ???
pip install pigpio
Next, install pigpio with pip:
.. code-block:: doscon
C:\Users\user1> pip install pigpio
Environment variables
=====================
@@ -135,7 +169,9 @@ The simplest way to use devices with remote pins is to set the ``PIGPIO_ADDR``
environment variable to the IP address of the desired Raspberry Pi. You must
run your Python script or launch your development environment with the
environment variable set using the command line. For example, one of the
following::
following:
.. code-block:: console
$ PIGPIO_ADDR=192.168.1.3 python3 hello.py
$ PIGPIO_ADDR=192.168.1.3 python3
@@ -147,7 +183,9 @@ pigpio Python library installed, this will work with no further configuration.
However, if you are running this from a Raspberry Pi, you will also need to
ensure the default pin factory is set to ``PiGPIOPin``. If ``RPi.GPIO`` is
installed, this will be selected as the default pin factory, so either uninstall
it, or use another environment variable to set it to ``PiGPIOPin``::
it, or use another environment variable to set it to ``PiGPIOPin``:
.. code-block:: console
$ GPIOZERO_PIN_FACTORY=pigpio PIGPIO_ADDR=192.168.1.3 python3 hello.py
@@ -160,12 +198,16 @@ with no modifications needed. For example:
.. literalinclude:: examples/led_1.py
When run with::
When run with:
.. code-block:: console
$ PIGPIO_ADDR=192.168.1.3 python3 led.py
will flash the LED connected to pin 17 of the Raspberry Pi with the IP address
``192.168.1.3``. And::
``192.168.1.3``. And:
.. code-block:: console
$ PIGPIO_ADDR=192.168.1.4 python3 led.py
@@ -236,11 +278,13 @@ computer using remote pins.
First, configure the boot partition of the SD card:
1. Edit ``config.txt`` and add ``dtoverlay=dwc2`` on a new line, then save the
file.
file.
2. Create an empty file called ``ssh`` (no file extension) and save it in the
boot partition.
boot partition.
3. Edit ``cmdline.txt`` and insert ``modules-load=dwc2,g_ether`` after
``rootwait``.
``rootwait``.
(See `blog.gbaman.info`_ for more information)

View File

@@ -47,6 +47,10 @@ class CompositeOutputDevice(SourceMixin, CompositeDevice):
specific order). All keyword arguments *must* be included in the
collection. If omitted, an alphabetically sorted order will be selected
for keyword arguments.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
def on(self):
@@ -124,6 +128,10 @@ class ButtonBoard(HoldMixin, CompositeDevice):
executed once per hold. This parameter can only be specified as a
keyword parameter.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
:param \*\*named_pins:
Specify GPIO pins that buttons of the board are attached to,
associating each button with a property name. You can designate as
@@ -135,6 +143,7 @@ class ButtonBoard(HoldMixin, CompositeDevice):
bounce_time = kwargs.pop('bounce_time', None)
hold_time = kwargs.pop('hold_time', 1)
hold_repeat = kwargs.pop('hold_repeat', False)
pin_factory = kwargs.pop('pin_factory', None)
order = kwargs.pop('_order', None)
super(ButtonBoard, self).__init__(
*(
@@ -142,6 +151,7 @@ class ButtonBoard(HoldMixin, CompositeDevice):
for pin in args
),
_order=order,
pin_factory=pin_factory,
**{
name: Button(pin, pull_up, bounce_time, hold_time, hold_repeat)
for name, pin in kwargs.items()
@@ -209,20 +219,28 @@ class LEDCollection(CompositeOutputDevice):
pwm = kwargs.pop('pwm', False)
active_high = kwargs.pop('active_high', True)
initial_value = kwargs.pop('initial_value', False)
pin_factory = kwargs.pop('pin_factory', None)
order = kwargs.pop('_order', None)
LEDClass = PWMLED if pwm else LED
super(LEDCollection, self).__init__(
*(
pin_or_collection
if isinstance(pin_or_collection, LEDCollection) else
LEDClass(pin_or_collection, active_high, initial_value)
LEDClass(
pin_or_collection, active_high, initial_value,
pin_factory=pin_factory
)
for pin_or_collection in args
),
_order=order,
pin_factory=pin_factory,
**{
name: pin_or_collection
if isinstance(pin_or_collection, LEDCollection) else
LEDClass(pin_or_collection, active_high, initial_value)
LEDClass(
pin_or_collection, active_high, initial_value,
pin_factory=pin_factory
)
for name, pin_or_collection in kwargs.items()
})
leds = []
@@ -283,6 +301,10 @@ class LEDBoard(LEDCollection):
the device will be switched on initially. This parameter can only be
specified as a keyword parameter.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
:param \*\*named_pins:
Specify GPIO pins that LEDs of the board are attached to, associating
each LED with a property name. You can designate as many pins as
@@ -486,6 +508,10 @@ class LEDBarGraph(LEDCollection):
The initial :attr:`value` of the graph given as a float between -1 and
+1. Defaults to ``0.0``. This parameter can only be specified as a
keyword parameter.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
def __init__(self, *pins, **kwargs):
@@ -495,9 +521,12 @@ class LEDBarGraph(LEDCollection):
pwm = kwargs.pop('pwm', False)
active_high = kwargs.pop('active_high', True)
initial_value = kwargs.pop('initial_value', 0.0)
pin_factory = kwargs.pop('pin_factory', None)
if kwargs:
raise TypeError('unexpected keyword argument: %s' % kwargs.popitem()[0])
super(LEDBarGraph, self).__init__(*pins, pwm=pwm, active_high=active_high)
super(LEDBarGraph, self).__init__(
*pins, pwm=pwm, active_high=active_high, pin_factory=pin_factory
)
try:
self.value = initial_value
except:
@@ -572,12 +601,17 @@ class LedBorg(RGBLED):
each component of the LedBorg. If ``False``, construct regular
:class:`LED` instances, which prevents smooth color graduations.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
.. _PiBorg LedBorg: https://www.piborg.org/ledborg
"""
def __init__(self, initial_value=(0, 0, 0), pwm=True):
def __init__(self, initial_value=(0, 0, 0), pwm=True, pin_factory=None):
super(LedBorg, self).__init__(red=17, green=27, blue=22,
pwm=pwm, initial_value=initial_value)
pwm=pwm, initial_value=initial_value,
pin_factory=pin_factory)
class PiLiter(LEDBoard):
@@ -604,12 +638,17 @@ class PiLiter(LEDBoard):
in when configured for output (warning: this can be on). If ``True``,
the device will be switched on initially.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
.. _Ciseco Pi-LITEr: http://shop.ciseco.co.uk/pi-liter-8-led-strip-for-the-raspberry-pi/
"""
def __init__(self, pwm=False, initial_value=False):
def __init__(self, pwm=False, initial_value=False, pin_factory=None):
super(PiLiter, self).__init__(4, 17, 27, 18, 22, 23, 24, 25,
pwm=pwm, initial_value=initial_value)
pwm=pwm, initial_value=initial_value,
pin_factory=pin_factory)
class PiLiterBarGraph(LEDBarGraph):
@@ -634,13 +673,18 @@ class PiLiterBarGraph(LEDBarGraph):
The initial :attr:`value` of the graph given as a float between -1 and
+1. Defaults to ``0.0``.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
.. _Ciseco Pi-LITEr: http://shop.ciseco.co.uk/pi-liter-8-led-strip-for-the-raspberry-pi/
"""
def __init__(self, pwm=False, initial_value=0.0):
def __init__(self, pwm=False, initial_value=0.0, pin_factory=None):
pins = (4, 17, 27, 18, 22, 23, 24, 25)
super(PiLiterBarGraph, self).__init__(*pins,
pwm=pwm, initial_value=initial_value)
super(PiLiterBarGraph, self).__init__(
*pins, pwm=pwm, initial_value=initial_value, pin_factory=pin_factory
)
class TrafficLights(LEDBoard):
@@ -680,9 +724,14 @@ class TrafficLights(LEDBoard):
The GPIO pin that the yellow LED is attached to. This is merely an
alias for the ``amber`` parameter - you can't specify both ``amber``
and ``yellow``.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
def __init__(self, red=None, amber=None, green=None,
pwm=False, initial_value=False, yellow=None):
pwm=False, initial_value=False, yellow=None,
pin_factory=None):
if amber is not None and yellow is not None:
raise OutputDeviceBadValue(
'Only one of amber or yellow can be specified'
@@ -700,7 +749,7 @@ class TrafficLights(LEDBoard):
)
super(TrafficLights, self).__init__(
pwm=pwm, initial_value=initial_value,
_order=devices.keys(),
_order=devices.keys(), pin_factory=pin_factory,
**devices)
def __getattr__(self, name):
@@ -739,11 +788,16 @@ class PiTraffic(TrafficLights):
in when configured for output (warning: this can be on). If ``True``,
the device will be switched on initially.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
.. _Low Voltage Labs PI-TRAFFIC: http://lowvoltagelabs.com/products/pi-traffic/
"""
def __init__(self, pwm=False, initial_value=False):
def __init__(self, pwm=False, initial_value=False, pin_factory=None):
super(PiTraffic, self).__init__(9, 10, 11,
pwm=pwm, initial_value=initial_value)
pwm=pwm, initial_value=initial_value,
pin_factory=pin_factory)
class PiStop(TrafficLights):
@@ -774,6 +828,10 @@ class PiStop(TrafficLights):
in when configured for output (warning: this can be on). If ``True``,
the device will be switched on initially.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
.. _PiHardware Pi-Stop: https://pihw.wordpress.com/meltwaters-pi-hardware-kits/pi-stop/
.. _location: https://github.com/PiHw/Pi-Stop/blob/master/markdown_source/markdown/Discover-PiStop.md
"""
@@ -786,13 +844,17 @@ class PiStop(TrafficLights):
'D': (2, 3, 4),
}
def __init__(self, location=None, pwm=False, initial_value=False):
def __init__(
self, location=None, pwm=False, initial_value=False,
pin_factory=None):
gpios = self.LOCATIONS.get(location, None)
if gpios is None:
raise ValueError('location must be one of: %s' %
', '.join(sorted(self.LOCATIONS.keys())))
super(PiStop, self).__init__(*gpios,
pwm=pwm, initial_value=initial_value)
super(PiStop, self).__init__(
*gpios, pwm=pwm, initial_value=initial_value,
pin_factory=pin_factory
)
class StatusZero(LEDBoard):
@@ -817,6 +879,10 @@ class StatusZero(LEDBoard):
not all strips are given labels, any remaining strips will not be
initialised.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
.. _STATUS Zero: https://thepihut.com/statuszero
"""
default_labels = ('one', 'two', 'three')
@@ -827,6 +893,7 @@ class StatusZero(LEDBoard):
(22, 27),
(9, 10),
)
pin_factory = kwargs.pop('pin_factory', None)
if len(labels) == 0:
labels = self.default_labels
elif len(labels) > len(pins):
@@ -834,10 +901,15 @@ class StatusZero(LEDBoard):
dup, count = Counter(labels).most_common(1)[0]
if count > 1:
raise ValueError("Duplicate label %s" % dup)
super(StatusZero, self).__init__(_order=labels, **{
label: LEDBoard(red=red, green=green, _order=('red', 'green'), **kwargs)
for (green, red), label in zip(pins, labels)
})
super(StatusZero, self).__init__(
_order=labels, pin_factory=pin_factory, **{
label: LEDBoard(
red=red, green=green, _order=('red', 'green'),
pin_factory=pin_factory, **kwargs
)
for (green, red), label in zip(pins, labels)
}
)
class StatusBoard(CompositeOutputDevice):
@@ -862,6 +934,10 @@ class StatusBoard(CompositeOutputDevice):
will be initialised with names 'one' to 'five'. If some, but not all
strips are given labels, any remaining strips will not be initialised.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
.. _STATUS: https://thepihut.com/status
"""
default_labels = ('one', 'two', 'three', 'four', 'five')
@@ -874,6 +950,7 @@ class StatusBoard(CompositeOutputDevice):
(5, 11, 26),
(13, 6, 18),
)
pin_factory = kwargs.pop('pin_factory', None)
if len(labels) == 0:
labels = self.default_labels
elif len(labels) > len(pins):
@@ -881,14 +958,18 @@ class StatusBoard(CompositeOutputDevice):
dup, count = Counter(labels).most_common(1)[0]
if count > 1:
raise ValueError("Duplicate label %s" % dup)
super(StatusBoard, self).__init__(_order=labels, **{
label: CompositeOutputDevice(
button=Button(button),
lights=LEDBoard(
red=red, green=green, _order=('red', 'green'), **kwargs
), _order=('button', 'lights'))
for (green, red, button), label in zip(pins, labels)
})
super(StatusBoard, self).__init__(
_order=labels, pin_factory=pin_factory, **{
label: CompositeOutputDevice(
button=Button(button),
lights=LEDBoard(
red=red, green=green, _order=('red', 'green'),
pin_factory=pin_factory, **kwargs
), _order=('button', 'lights'), pin_factory=pin_factory
)
for (green, red, button), label in zip(pins, labels)
}
)
class SnowPi(LEDBoard):
@@ -917,30 +998,39 @@ class SnowPi(LEDBoard):
in when configured for output (warning: this can be on). If ``True``,
the device will be switched on initially.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
.. _Ryanteck SnowPi: https://ryanteck.uk/raspberry-pi/114-snowpi-the-gpio-snowman-for-raspberry-pi-0635648608303.html
"""
def __init__(self, pwm=False, initial_value=False):
def __init__(self, pwm=False, initial_value=False, pin_factory=None):
super(SnowPi, self).__init__(
arms=LEDBoard(
left=LEDBoard(
top=17, middle=18, bottom=22,
pwm=pwm, initial_value=initial_value,
_order=('top', 'middle', 'bottom')),
_order=('top', 'middle', 'bottom'),
pin_factory=pin_factory),
right=LEDBoard(
top=7, middle=8, bottom=9,
pwm=pwm, initial_value=initial_value,
_order=('top', 'middle', 'bottom')),
_order=('left', 'right')
_order=('top', 'middle', 'bottom'),
pin_factory=pin_factory),
_order=('left', 'right'),
pin_factory=pin_factory
),
eyes=LEDBoard(
left=23, right=24,
pwm=pwm, initial_value=initial_value,
_order=('left', 'right')
_order=('left', 'right'),
pin_factory=pin_factory
),
nose=25,
pwm=pwm, initial_value=initial_value,
_order=('eyes', 'nose', 'arms')
)
_order=('eyes', 'nose', 'arms'),
pin_factory=pin_factory
)
class TrafficLightsBuzzer(CompositeOutputDevice):
@@ -957,12 +1047,18 @@ class TrafficLightsBuzzer(CompositeOutputDevice):
:param Button button:
An instance of :class:`Button` representing the button on the HAT.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
def __init__(self, lights, buzzer, button):
def __init__(self, lights, buzzer, button, pin_factory=None):
super(TrafficLightsBuzzer, self).__init__(
lights=lights, buzzer=buzzer, button=button,
_order=('lights', 'buzzer', 'button'))
_order=('lights', 'buzzer', 'button'),
pin_factory=pin_factory
)
class FishDish(TrafficLightsBuzzer):
@@ -985,14 +1081,19 @@ class FishDish(TrafficLightsBuzzer):
LED. If ``False`` (the default), construct regular :class:`LED`
instances.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
.. _Pi Supply FishDish: https://www.pi-supply.com/product/fish-dish-raspberry-pi-led-buzzer-board/
"""
def __init__(self, pwm=False):
def __init__(self, pwm=False, pin_factory=None):
super(FishDish, self).__init__(
TrafficLights(9, 22, 4, pwm=pwm),
Buzzer(8),
Button(7, pull_up=False),
TrafficLights(9, 22, 4, pwm=pwm, pin_factory=pin_factory),
Buzzer(8, pin_factory=pin_factory),
Button(7, pull_up=False, pin_factory=pin_factory),
pin_factory=pin_factory
)
@@ -1016,14 +1117,19 @@ class TrafficHat(TrafficLightsBuzzer):
LED. If ``False`` (the default), construct regular :class:`LED`
instances.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
.. _Ryanteck Traffic HAT: https://ryanteck.uk/hats/1-traffichat-0635648607122.html
"""
def __init__(self, pwm=False):
def __init__(self, pwm=False, pin_factory=None):
super(TrafficHat, self).__init__(
TrafficLights(24, 23, 22, pwm=pwm),
Buzzer(5),
Button(25),
TrafficLights(24, 23, 22, pwm=pwm, pin_factory=pin_factory),
Buzzer(5, pin_factory=pin_factory),
Button(25, pin_factory=pin_factory),
pin_factory=pin_factory
)
@@ -1049,13 +1155,19 @@ class Robot(SourceMixin, CompositeDevice):
:param tuple right:
A tuple of two GPIO pins representing the forward and backward inputs
of the right motor's controller.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
def __init__(self, left=None, right=None):
def __init__(self, left=None, right=None, pin_factory=None):
super(Robot, self).__init__(
left_motor=Motor(*left),
right_motor=Motor(*right),
_order=('left_motor', 'right_motor'))
left_motor=Motor(*left, pin_factory=pin_factory),
right_motor=Motor(*right, pin_factory=pin_factory),
_order=('left_motor', 'right_motor'),
pin_factory=pin_factory
)
@property
def value(self):
@@ -1148,11 +1260,17 @@ class RyanteckRobot(Robot):
robot = RyanteckRobot()
robot.forward()
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
.. _Ryanteck MCB: https://ryanteck.uk/add-ons/6-ryanteck-rpi-motor-controller-board-0635648607160.html
"""
def __init__(self):
super(RyanteckRobot, self).__init__((17, 18), (22, 23))
def __init__(self, pin_factory=None):
super(RyanteckRobot, self).__init__(
(17, 18), (22, 23), pin_factory=pin_factory
)
class CamJamKitRobot(Robot):
@@ -1168,20 +1286,31 @@ class CamJamKitRobot(Robot):
robot = CamJamKitRobot()
robot.forward()
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
.. _CamJam #3 EduKit: http://camjam.me/?page_id=1035
"""
def __init__(self):
super(CamJamKitRobot, self).__init__((9, 10), (7, 8))
def __init__(self, pin_factory=None):
super(CamJamKitRobot, self).__init__(
(9, 10), (7, 8), pin_factory=pin_factory
)
class _EnergenieMaster(SharedMixin, CompositeOutputDevice):
def __init__(self):
def __init__(self, pin_factory=None):
self._lock = Lock()
super(_EnergenieMaster, self).__init__(
*(OutputDevice(pin) for pin in (17, 22, 23, 27)),
mode=OutputDevice(24), enable=OutputDevice(25),
_order=('mode', 'enable'))
*(
OutputDevice(pin, pin_factory=pin_factory)
for pin in (17, 22, 23, 27)
),
mode=OutputDevice(24, pin_factory=pin_factory),
enable=OutputDevice(25, pin_factory=pin_factory),
_order=('mode', 'enable'), pin_factory=pin_factory
)
def close(self):
if self._lock:
@@ -1190,7 +1319,7 @@ class _EnergenieMaster(SharedMixin, CompositeOutputDevice):
self._lock = None
@classmethod
def _shared_key(cls):
def _shared_key(cls, pin_factory):
# There's only one Energenie master
return None
@@ -1231,18 +1360,22 @@ class Energenie(SourceMixin, Device):
the socket, which will be set upon construction. This defaults to
``False`` which will switch the socket off.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
.. _Energenie socket: https://energenie4u.co.uk/index.php/catalogue/product/ENER002-2PI
"""
def __init__(self, socket=None, initial_value=False):
def __init__(self, socket=None, initial_value=False, pin_factory=None):
if socket is None:
raise EnergenieSocketMissing('socket number must be provided')
if not (1 <= socket <= 4):
raise EnergenieBadSocket('socket number must be between 1 and 4')
self._value = None
super(Energenie, self).__init__()
super(Energenie, self).__init__(pin_factory=pin_factory)
self._socket = socket
self._master = _EnergenieMaster()
self._master = _EnergenieMaster(pin_factory=pin_factory)
if initial_value:
self.on()
else:

View File

@@ -197,7 +197,11 @@ class Device(ValuesMixin, GPIOBase):
def __init__(self, **kwargs):
# Force pin_factory to be keyword-only, even in Python 2
self.pin_factory = kwargs.pop('pin_factory', Device.pin_factory)
pin_factory = kwargs.pop('pin_factory', None)
if pin_factory is None:
self.pin_factory = Device.pin_factory
else:
self.pin_factory = pin_factory
if kwargs:
raise TypeError("Device.__init__() got unexpected keyword "
"argument '%s'" % kwargs.popitem()[0])
@@ -281,8 +285,7 @@ class CompositeDevice(Device):
dev.close()
raise
self._all = args + tuple(kwargs[v] for v in self._order)
kwargs = {'pin_factory': pin_factory} if pin_factory is not None else {}
super(CompositeDevice, self).__init__(**kwargs)
super(CompositeDevice, self).__init__(pin_factory=pin_factory)
def __getattr__(self, name):
# if _named doesn't exist yet, pretend it's an empty dict

View File

@@ -32,9 +32,13 @@ class InputDevice(GPIODevice):
:param bool pull_up:
If ``True``, the pin will be pulled high with an internal resistor. If
``False`` (the default), the pin will be pulled low.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
def __init__(self, pin=None, pull_up=False):
super(InputDevice, self).__init__(pin)
def __init__(self, pin=None, pull_up=False, pin_factory=None):
super(InputDevice, self).__init__(pin, pin_factory=pin_factory)
try:
self.pin.function = 'input'
pull = 'up' if pull_up else 'down'
@@ -75,9 +79,16 @@ class DigitalInputDevice(EventsMixin, InputDevice):
Specifies the length of time (in seconds) that the component will
ignore changes in state after an initial change. This defaults to
``None`` which indicates that no bounce compensation will be performed.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
def __init__(self, pin=None, pull_up=False, bounce_time=None):
super(DigitalInputDevice, self).__init__(pin, pull_up)
def __init__(
self, pin=None, pull_up=False, bounce_time=None, pin_factory=None):
super(DigitalInputDevice, self).__init__(
pin, pull_up, pin_factory=pin_factory
)
try:
self.pin.bounce = bounce_time
self.pin.edges = 'both'
@@ -127,12 +138,18 @@ class SmoothedInputDevice(EventsMixin, InputDevice):
(from the :attr:`is_active` property) will block until the queue has
filled. If ``True``, a value will be returned immediately, but be
aware that this value is likely to fluctuate excessively.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
def __init__(
self, pin=None, pull_up=False, threshold=0.5,
queue_len=5, sample_wait=0.0, partial=False):
queue_len=5, sample_wait=0.0, partial=False, pin_factory=None):
self._queue = None
super(SmoothedInputDevice, self).__init__(pin, pull_up)
super(SmoothedInputDevice, self).__init__(
pin, pull_up, pin_factory=pin_factory
)
try:
self._queue = GPIOQueue(self, queue_len, sample_wait, partial)
self.threshold = float(threshold)
@@ -263,11 +280,17 @@ class Button(HoldMixin, DigitalInputDevice):
as long as the device remains active, every *hold_time* seconds. If
``False`` (the default) the :attr:`when_held` handler will be only be
executed once per hold.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
def __init__(
self, pin=None, pull_up=True, bounce_time=None,
hold_time=1, hold_repeat=False):
super(Button, self).__init__(pin, pull_up, bounce_time)
hold_time=1, hold_repeat=False, pin_factory=None):
super(Button, self).__init__(
pin, pull_up, bounce_time, pin_factory=pin_factory
)
self.hold_time = hold_time
self.hold_repeat = hold_repeat
@@ -325,14 +348,19 @@ class LineSensor(SmoothedInputDevice):
filled with values. Only set this to ``True`` if you require values
immediately after object construction.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
.. _CamJam #3 EduKit: http://camjam.me/?page_id=1035
"""
def __init__(
self, pin=None, queue_len=5, sample_rate=100, threshold=0.5,
partial=False):
partial=False, pin_factory=None):
super(LineSensor, self).__init__(
pin, pull_up=False, threshold=threshold,
queue_len=queue_len, sample_wait=1 / sample_rate, partial=partial
queue_len=queue_len, sample_wait=1 / sample_rate, partial=partial,
pin_factory=pin_factory
)
try:
self._queue.start()
@@ -394,13 +422,18 @@ class MotionSensor(SmoothedInputDevice):
:attr:`~SmoothedInputDevice.is_active` until the internal queue has
filled with values. Only set this to ``True`` if you require values
immediately after object construction.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
def __init__(
self, pin=None, queue_len=1, sample_rate=10, threshold=0.5,
partial=False):
partial=False, pin_factory=None):
super(MotionSensor, self).__init__(
pin, pull_up=False, threshold=threshold,
queue_len=queue_len, sample_wait=1 / sample_rate, partial=partial
queue_len=queue_len, sample_wait=1 / sample_rate, partial=partial,
pin_factory=pin_factory
)
try:
self._queue.start()
@@ -460,14 +493,19 @@ class LightSensor(SmoothedInputDevice):
filled with values. Only set this to ``True`` if you require values
immediately after object construction.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
.. _CamJam #2 EduKit: http://camjam.me/?page_id=623
"""
def __init__(
self, pin=None, queue_len=5, charge_time_limit=0.01,
threshold=0.1, partial=False):
threshold=0.1, partial=False, pin_factory=None):
super(LightSensor, self).__init__(
pin, pull_up=False, threshold=threshold,
queue_len=queue_len, sample_wait=0.0, partial=partial
queue_len=queue_len, sample_wait=0.0, partial=partial,
pin_factory=pin_factory
)
try:
self._charge_time_limit = charge_time_limit
@@ -568,17 +606,22 @@ class DistanceSensor(SmoothedInputDevice):
filled with values. Only set this to ``True`` if you require values
immediately after object construction.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
.. _CamJam #3 EduKit: http://camjam.me/?page_id=1035
"""
def __init__(
self, echo=None, trigger=None, queue_len=30, max_distance=1,
threshold_distance=0.3, partial=False):
threshold_distance=0.3, partial=False, pin_factory=None):
if max_distance <= 0:
raise ValueError('invalid maximum distance (must be positive)')
self._trigger = None
super(DistanceSensor, self).__init__(
echo, pull_up=False, threshold=threshold_distance / max_distance,
queue_len=queue_len, sample_wait=0.0, partial=partial
queue_len=queue_len, sample_wait=0.0, partial=partial,
pin_factory=pin_factory
)
try:
self.speed_of_sound = 343.26 # m/s

View File

@@ -36,9 +36,15 @@ class OutputDevice(SourceMixin, GPIODevice):
``None``, the device will be left in whatever state the pin is found in
when configured for output (warning: this can be on). If ``True``, the
device will be switched on initially.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
def __init__(self, pin=None, active_high=True, initial_value=False):
super(OutputDevice, self).__init__(pin)
def __init__(
self, pin=None, active_high=True, initial_value=False,
pin_factory=None):
super(OutputDevice, self).__init__(pin, pin_factory=pin_factory)
self._lock = Lock()
self.active_high = active_high
if initial_value is None:
@@ -126,10 +132,14 @@ class DigitalOutputDevice(OutputDevice):
uses an optional background thread to handle toggling the device state
without further interaction.
"""
def __init__(self, pin=None, active_high=True, initial_value=False):
def __init__(
self, pin=None, active_high=True, initial_value=False,
pin_factory=None):
self._blink_thread = None
self._controller = None
super(DigitalOutputDevice, self).__init__(pin, active_high, initial_value)
super(DigitalOutputDevice, self).__init__(
pin, active_high, initial_value, pin_factory=pin_factory
)
@property
def value(self):
@@ -230,6 +240,10 @@ class LED(DigitalOutputDevice):
``None``, the LED will be left in whatever state the pin is found in
when configured for output (warning: this can be on). If ``True``, the
LED will be switched on initially.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
pass
@@ -265,6 +279,10 @@ class Buzzer(DigitalOutputDevice):
``None``, the buzzer will be left in whatever state the pin is found in
when configured for output (warning: this can be on). If ``True``, the
buzzer will be switched on initially.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
pass
@@ -293,13 +311,21 @@ class PWMOutputDevice(OutputDevice):
:param int frequency:
The frequency (in Hz) of pulses emitted to drive the device. Defaults
to 100Hz.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
def __init__(self, pin=None, active_high=True, initial_value=0, frequency=100):
def __init__(
self, pin=None, active_high=True, initial_value=0, frequency=100,
pin_factory=None):
self._blink_thread = None
self._controller = None
if not 0 <= initial_value <= 1:
raise OutputDeviceBadValue("initial_value must be between 0 and 1")
super(PWMOutputDevice, self).__init__(pin, active_high, initial_value=None)
super(PWMOutputDevice, self).__init__(
pin, active_high, initial_value=None, pin_factory=pin_factory
)
try:
# XXX need a way of setting these together
self.pin.frequency = frequency
@@ -500,6 +526,10 @@ class PWMLED(PWMOutputDevice):
:param int frequency:
The frequency (in Hz) of pulses emitted to drive the LED. Defaults
to 100Hz.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
pass
@@ -552,17 +582,24 @@ class RGBLED(SourceMixin, Device):
If ``True`` (the default), construct :class:`PWMLED` instances for
each component of the RGBLED. If ``False``, construct regular
:class:`LED` instances, which prevents smooth color graduations.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
def __init__(
self, red=None, green=None, blue=None, active_high=True,
initial_value=(0, 0, 0), pwm=True):
initial_value=(0, 0, 0), pwm=True, pin_factory=None):
self._leds = ()
self._blink_thread = None
if not all(p is not None for p in [red, green, blue]):
raise GPIOPinMissing('red, green, and blue pins must be provided')
LEDClass = PWMLED if pwm else LED
super(RGBLED, self).__init__()
self._leds = tuple(LEDClass(pin, active_high) for pin in (red, green, blue))
super(RGBLED, self).__init__(pin_factory=pin_factory)
self._leds = tuple(
LEDClass(pin, active_high, pin_factory=pin_factory)
for pin in (red, green, blue)
)
self.value = initial_value
red = _led_property(0)
@@ -803,17 +840,23 @@ class Motor(SourceMixin, CompositeDevice):
variable speed control. If ``False``, construct
:class:`DigitalOutputDevice` instances, allowing only direction
control.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
def __init__(self, forward=None, backward=None, pwm=True):
def __init__(self, forward=None, backward=None, pwm=True, pin_factory=None):
if not all(p is not None for p in [forward, backward]):
raise GPIOPinMissing(
'forward and backward pins must be provided'
)
PinClass = PWMOutputDevice if pwm else DigitalOutputDevice
super(Motor, self).__init__(
forward_device=PinClass(forward),
backward_device=PinClass(backward),
_order=('forward_device', 'backward_device'))
forward_device=PinClass(forward, pin_factory=pin_factory),
backward_device=PinClass(backward, pin_factory=pin_factory),
_order=('forward_device', 'backward_device'),
pin_factory=pin_factory
)
@property
def value(self):
@@ -946,11 +989,15 @@ class Servo(SourceMixin, CompositeDevice):
:param float frame_width:
The length of time between servo control pulses measured in seconds.
This defaults to 20ms which is a common value for servos.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
def __init__(
self, pin=None, initial_value=0.0,
min_pulse_width=1/1000, max_pulse_width=2/1000,
frame_width=20/1000):
frame_width=20/1000, pin_factory=None):
if min_pulse_width >= max_pulse_width:
raise ValueError('min_pulse_width must be less than max_pulse_width')
if max_pulse_width >= frame_width:
@@ -961,7 +1008,11 @@ class Servo(SourceMixin, CompositeDevice):
self._min_value = -1
self._value_range = 2
super(Servo, self).__init__(
pwm_device=PWMOutputDevice(pin, frequency=int(1 / frame_width)))
pwm_device=PWMOutputDevice(
pin, frequency=int(1 / frame_width), pin_factory=pin_factory
),
pin_factory=pin_factory
)
try:
self.value = initial_value
except:
@@ -1146,17 +1197,23 @@ class AngularServo(Servo):
:param float frame_width:
The length of time between servo control pulses measured in seconds.
This defaults to 20ms which is a common value for servos.
:param Factory pin_factory:
See :doc:`api_pins` for more information (this is an advanced feature
which most users can ignore).
"""
def __init__(
self, pin=None, initial_angle=0.0,
min_angle=-90, max_angle=90,
min_pulse_width=1/1000, max_pulse_width=2/1000,
frame_width=20/1000):
frame_width=20/1000, pin_factory=None):
self._min_angle = min_angle
self._angular_range = max_angle - min_angle
initial_value = 2 * ((initial_angle - min_angle) / self._angular_range) - 1
super(AngularServo, self).__init__(
pin, initial_value, min_pulse_width, max_pulse_width, frame_width)
pin, initial_value, min_pulse_width, max_pulse_width, frame_width,
pin_factory=pin_factory
)
@property
def min_angle(self):

View File

@@ -28,7 +28,9 @@ class SPIDevice(Device):
"""
def __init__(self, **spi_args):
self._spi = None
super(SPIDevice, self).__init__()
super(SPIDevice, self).__init__(
pin_factory=spi_args.pop('pin_factory', None)
)
self._spi = self.pin_factory.spi(**spi_args)
def close(self):