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

@@ -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):