Make tests work reliably on the Pi

While the tests work well on a PC or Travis, the Pi (where I ought to be
running them!) has some issues with the timing tests. Need to relax the
tolerance of the "assert_states_and_times" method to 0.05 seconds
otherwise it periodically fails even on something reasonably quick like
a Pi 2 (less failures on a Pi 3 but still occasionally).

Also reduced default fps to 25; if the default timing occasionally fails
on a Pi 2 it's evidently too fast for a Pi 1 and shouldn't be the
default; 25 also doesn't look any different to me on a pulsing LED.

There's also a bunch of miscellaneous fixes in here; last minute typos
and chart re-gens for the 1.2 release.
This commit is contained in:
Dave Jones
2016-04-08 11:10:59 +01:00
parent 44422bd6c9
commit c2a9392ea5
28 changed files with 846 additions and 842 deletions

View File

@@ -18,7 +18,7 @@ individually.
LED Board LED Board
========= =========
.. autoclass:: LEDBoard(\*pins, pwm=False, active_high=True, initial_value=False) .. autoclass:: LEDBoard(\*pins, pwm=False, active_high=True, initial_value=False, \*\*named_pins)
:inherited-members: :inherited-members:
:members: :members:

View File

@@ -81,10 +81,10 @@ Base Classes
.. autoclass:: SPIDevice .. autoclass:: SPIDevice
:members: :members:
.. autoclass:: InternalDevice .. autoclass:: InternalDevice()
:members: :members:
.. autoclass:: CompositeDevice .. autoclass:: CompositeDevice(\*args, _order=None, \*\*kwargs)
:members: :members:
Input Devices Input Devices

View File

@@ -2,13 +2,20 @@
Source Tools Source Tools
============ ============
.. currentmodule:: gpiozero .. currentmodule:: gpiozero.tools
GPIO Zero includes several utility routines which are intended to be used with GPIO Zero includes several utility routines which are intended to be used with
the :attr:`~SourceMixin.source` and :attr:`~ValuesMixin.values` attributes the :attr:`~gpiozero.SourceMixin.source` and
common to most devices in the library. Given that ``source`` and ``values`` :attr:`~gpiozero.ValuesMixin.values` attributes common to most devices in the
deal with infinite iterators, another excellent source of utilities is the library. These utility routines are in the ``tools`` module of GPIO Zero and
:mod:`itertools` module in the standard library. are typically imported as follows::
from gpiozero.tools import scaled, negated, conjunction
Given that :attr:`~gpiozero.SourceMixin.source` and
:attr:`~gpiozero.ValuesMixin.values` deal with infinite iterators, another
excellent source of utilities is the :mod:`itertools` module in the standard
library.
Single source conversions Single source conversions
========================= =========================

View File

@@ -12,6 +12,8 @@ Release 1.2.0 (2016-04-??)
* Added :class:`LineSensor` class for single line-sensors (`#109`_) * Added :class:`LineSensor` class for single line-sensors (`#109`_)
* Added :class:`DistanceSensor` class for HC-SR04 ultra-sonic sensors (`#114`_) * Added :class:`DistanceSensor` class for HC-SR04 ultra-sonic sensors (`#114`_)
* Added :class:`SnowPi` class for the Ryanteck Snow-pi board (`#130`_) * Added :class:`SnowPi` class for the Ryanteck Snow-pi board (`#130`_)
* Added :attr:`~Button.when_held` (and related properties) to :class:`Button`
(`#115`_)
* Fixed issues with installing GPIO Zero for python 3 on Raspbian Wheezy * Fixed issues with installing GPIO Zero for python 3 on Raspbian Wheezy
releases (`#140`_) releases (`#140`_)
* Added support for lots of ADC chips (MCP3xxx family) (`#162`_) - many thanks * Added support for lots of ADC chips (MCP3xxx family) (`#162`_) - many thanks
@@ -35,6 +37,7 @@ reports in this version - keep 'em coming!
.. _#69: https://github.com/RPi-Distro/python-gpiozero/issues/69 .. _#69: https://github.com/RPi-Distro/python-gpiozero/issues/69
.. _#109: https://github.com/RPi-Distro/python-gpiozero/issues/109 .. _#109: https://github.com/RPi-Distro/python-gpiozero/issues/109
.. _#114: https://github.com/RPi-Distro/python-gpiozero/issues/114 .. _#114: https://github.com/RPi-Distro/python-gpiozero/issues/114
.. _#115: https://github.com/RPi-Distro/python-gpiozero/issues/115
.. _#130: https://github.com/RPi-Distro/python-gpiozero/issues/130 .. _#130: https://github.com/RPi-Distro/python-gpiozero/issues/130
.. _#140: https://github.com/RPi-Distro/python-gpiozero/issues/140 .. _#140: https://github.com/RPi-Distro/python-gpiozero/issues/140
.. _#162: https://github.com/RPi-Distro/python-gpiozero/issues/162 .. _#162: https://github.com/RPi-Distro/python-gpiozero/issues/162

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -4,11 +4,11 @@
<!-- Generated by graphviz version 2.36.0 (20140111.2315) <!-- Generated by graphviz version 2.36.0 (20140111.2315)
--> -->
<!-- Title: classes Pages: 1 --> <!-- Title: classes Pages: 1 -->
<svg width="447pt" height="116pt" <svg width="538pt" height="116pt"
viewBox="0.00 0.00 447.00 116.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> viewBox="0.00 0.00 538.00 116.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 112)"> <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 112)">
<title>classes</title> <title>classes</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-112 443,-112 443,4 -4,4"/> <polygon fill="white" stroke="none" points="-4,4 -4,-112 534,-112 534,4 -4,4"/>
<!-- RGBLED --> <!-- RGBLED -->
<g id="node1" class="node"><title>RGBLED</title> <g id="node1" class="node"><title>RGBLED</title>
<polygon fill="#298029" stroke="#298029" points="55.5,-108 0.5,-108 0.5,-72 55.5,-72 55.5,-108"/> <polygon fill="#298029" stroke="#298029" points="55.5,-108 0.5,-108 0.5,-72 55.5,-72 55.5,-108"/>
@@ -16,83 +16,98 @@
</g> </g>
<!-- PWMLED --> <!-- PWMLED -->
<g id="node2" class="node"><title>PWMLED</title> <g id="node2" class="node"><title>PWMLED</title>
<polygon fill="#298029" stroke="#298029" points="58.5,-36 1.5,-36 1.5,-0 58.5,-0 58.5,-36"/> <polygon fill="#298029" stroke="#298029" points="143.5,-36 86.5,-36 86.5,-0 143.5,-0 143.5,-36"/>
<text text-anchor="middle" x="30" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">PWMLED</text> <text text-anchor="middle" x="115" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">PWMLED</text>
</g> </g>
<!-- RGBLED&#45;&gt;PWMLED --> <!-- RGBLED&#45;&gt;PWMLED -->
<g id="edge1" class="edge"><title>RGBLED&#45;&gt;PWMLED</title> <g id="edge1" class="edge"><title>RGBLED&#45;&gt;PWMLED</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M28.4944,-71.6966C28.7148,-63.9827 28.9796,-54.7125 29.2254,-46.1124"/> <path fill="none" stroke="black" stroke-dasharray="5,2" d="M49.5056,-71.6966C60.4625,-62.8807 73.9459,-52.0321 85.8249,-42.4742"/>
<polygon fill="none" stroke="black" points="32.7242,-46.2002 29.5113,-36.1043 25.727,-46.0003 32.7242,-46.2002"/> <polygon fill="none" stroke="black" points="88.1446,-45.1001 93.7418,-36.1043 83.7565,-39.6462 88.1446,-45.1001"/>
</g> </g>
<!-- LEDBoard --> <!-- LEDBoard -->
<g id="node3" class="node"><title>LEDBoard</title> <g id="node3" class="node"><title>LEDBoard</title>
<polygon fill="#298029" stroke="#298029" points="138,-108 74,-108 74,-72 138,-72 138,-108"/> <polygon fill="#298029" stroke="#298029" points="238,-108 174,-108 174,-72 238,-72 238,-108"/>
<text text-anchor="middle" x="106" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">LEDBoard</text> <text text-anchor="middle" x="206" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">LEDBoard</text>
</g> </g>
<!-- LEDBoard&#45;&gt;PWMLED --> <!-- LEDBoard&#45;&gt;PWMLED -->
<g id="edge3" class="edge"><title>LEDBoard&#45;&gt;PWMLED</title> <g id="edge3" class="edge"><title>LEDBoard&#45;&gt;PWMLED</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M87.2135,-71.6966C77.826,-63.0503 66.3156,-52.4486 56.0865,-43.027"/> <path fill="none" stroke="black" stroke-dasharray="5,2" d="M183.506,-71.6966C172.045,-62.8807 157.942,-52.0321 145.516,-42.4742"/>
<polygon fill="none" stroke="black" points="58.2971,-40.3047 48.5704,-36.1043 53.5547,-45.4535 58.2971,-40.3047"/> <polygon fill="none" stroke="black" points="147.296,-39.4273 137.236,-36.1043 143.028,-44.9757 147.296,-39.4273"/>
</g> </g>
<!-- LED --> <!-- LED -->
<g id="node4" class="node"><title>LED</title> <g id="node4" class="node"><title>LED</title>
<polygon fill="#298029" stroke="#298029" points="133,-36 79,-36 79,-0 133,-0 133,-36"/> <polygon fill="#298029" stroke="#298029" points="224,-36 170,-36 170,-0 224,-0 224,-36"/>
<text text-anchor="middle" x="106" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">LED</text> <text text-anchor="middle" x="197" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">LED</text>
</g> </g>
<!-- LEDBoard&#45;&gt;LED --> <!-- LEDBoard&#45;&gt;LED -->
<g id="edge2" class="edge"><title>LEDBoard&#45;&gt;LED</title> <g id="edge2" class="edge"><title>LEDBoard&#45;&gt;LED</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M106,-71.6966C106,-63.9827 106,-54.7125 106,-46.1124"/> <path fill="none" stroke="black" stroke-dasharray="5,2" d="M203.775,-71.6966C202.783,-63.9827 201.592,-54.7125 200.486,-46.1124"/>
<polygon fill="none" stroke="black" points="109.5,-46.1043 106,-36.1043 102.5,-46.1044 109.5,-46.1043"/> <polygon fill="none" stroke="black" points="203.946,-45.5763 199.199,-36.1043 197.003,-46.469 203.946,-45.5763"/>
</g>
<!-- LEDBarGraph -->
<g id="node5" class="node"><title>LEDBarGraph</title>
<polygon fill="#298029" stroke="#298029" points="155.25,-108 74.75,-108 74.75,-72 155.25,-72 155.25,-108"/>
<text text-anchor="middle" x="115" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">LEDBarGraph</text>
</g>
<!-- LEDBarGraph&#45;&gt;PWMLED -->
<g id="edge5" class="edge"><title>LEDBarGraph&#45;&gt;PWMLED</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M115,-71.6966C115,-63.9827 115,-54.7125 115,-46.1124"/>
<polygon fill="none" stroke="black" points="118.5,-46.1043 115,-36.1043 111.5,-46.1044 118.5,-46.1043"/>
</g>
<!-- LEDBarGraph&#45;&gt;LED -->
<g id="edge4" class="edge"><title>LEDBarGraph&#45;&gt;LED</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M135.27,-71.6966C145.498,-62.9655 158.061,-52.2405 169.178,-42.7503"/>
<polygon fill="none" stroke="black" points="171.63,-45.259 176.963,-36.1043 167.085,-39.935 171.63,-45.259"/>
</g> </g>
<!-- TrafficLightsBuzzer --> <!-- TrafficLightsBuzzer -->
<g id="node5" class="node"><title>TrafficLightsBuzzer</title> <g id="node6" class="node"><title>TrafficLightsBuzzer</title>
<polygon fill="#298029" stroke="#298029" points="320.25,-108 215.75,-108 215.75,-72 320.25,-72 320.25,-108"/> <polygon fill="#298029" stroke="#298029" points="411.25,-108 306.75,-108 306.75,-72 411.25,-72 411.25,-108"/>
<text text-anchor="middle" x="268" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">TrafficLightsBuzzer</text> <text text-anchor="middle" x="359" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">TrafficLightsBuzzer</text>
</g> </g>
<!-- TrafficLights --> <!-- TrafficLights -->
<g id="node6" class="node"><title>TrafficLights</title> <g id="node7" class="node"><title>TrafficLights</title>
<polygon fill="#298029" stroke="#298029" points="223,-36 151,-36 151,-0 223,-0 223,-36"/> <polygon fill="#298029" stroke="#298029" points="314,-36 242,-36 242,-0 314,-0 314,-36"/>
<text text-anchor="middle" x="187" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">TrafficLights</text> <text text-anchor="middle" x="278" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">TrafficLights</text>
</g> </g>
<!-- TrafficLightsBuzzer&#45;&gt;TrafficLights --> <!-- TrafficLightsBuzzer&#45;&gt;TrafficLights -->
<g id="edge4" class="edge"><title>TrafficLightsBuzzer&#45;&gt;TrafficLights</title> <g id="edge6" class="edge"><title>TrafficLightsBuzzer&#45;&gt;TrafficLights</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M247.978,-71.6966C237.874,-62.9655 225.464,-52.2405 214.482,-42.7503"/> <path fill="none" stroke="black" stroke-dasharray="5,2" d="M338.978,-71.6966C328.874,-62.9655 316.464,-52.2405 305.482,-42.7503"/>
<polygon fill="none" stroke="black" points="216.647,-39.9948 206.792,-36.1043 212.07,-45.2912 216.647,-39.9948"/> <polygon fill="none" stroke="black" points="307.647,-39.9948 297.792,-36.1043 303.07,-45.2912 307.647,-39.9948"/>
</g> </g>
<!-- Buzzer --> <!-- Buzzer -->
<g id="node7" class="node"><title>Buzzer</title> <g id="node8" class="node"><title>Buzzer</title>
<polygon fill="#298029" stroke="#298029" points="295,-36 241,-36 241,-0 295,-0 295,-36"/> <polygon fill="#298029" stroke="#298029" points="386,-36 332,-36 332,-0 386,-0 386,-36"/>
<text text-anchor="middle" x="268" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">Buzzer</text> <text text-anchor="middle" x="359" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">Buzzer</text>
</g> </g>
<!-- TrafficLightsBuzzer&#45;&gt;Buzzer --> <!-- TrafficLightsBuzzer&#45;&gt;Buzzer -->
<g id="edge5" class="edge"><title>TrafficLightsBuzzer&#45;&gt;Buzzer</title> <g id="edge7" class="edge"><title>TrafficLightsBuzzer&#45;&gt;Buzzer</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M268,-71.6966C268,-63.9827 268,-54.7125 268,-46.1124"/> <path fill="none" stroke="black" stroke-dasharray="5,2" d="M359,-71.6966C359,-63.9827 359,-54.7125 359,-46.1124"/>
<polygon fill="none" stroke="black" points="271.5,-46.1043 268,-36.1043 264.5,-46.1044 271.5,-46.1043"/> <polygon fill="none" stroke="black" points="362.5,-46.1043 359,-36.1043 355.5,-46.1044 362.5,-46.1043"/>
</g> </g>
<!-- Button --> <!-- Button -->
<g id="node8" class="node"><title>Button</title> <g id="node9" class="node"><title>Button</title>
<polygon fill="#298029" stroke="#298029" points="367,-36 313,-36 313,-0 367,-0 367,-36"/> <polygon fill="#298029" stroke="#298029" points="458,-36 404,-36 404,-0 458,-0 458,-36"/>
<text text-anchor="middle" x="340" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">Button</text> <text text-anchor="middle" x="431" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">Button</text>
</g> </g>
<!-- TrafficLightsBuzzer&#45;&gt;Button --> <!-- TrafficLightsBuzzer&#45;&gt;Button -->
<g id="edge6" class="edge"><title>TrafficLightsBuzzer&#45;&gt;Button</title> <g id="edge8" class="edge"><title>TrafficLightsBuzzer&#45;&gt;Button</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M285.798,-71.6966C294.604,-63.135 305.382,-52.6562 315.001,-43.3045"/> <path fill="none" stroke="black" stroke-dasharray="5,2" d="M376.798,-71.6966C385.604,-63.135 396.382,-52.6562 406.001,-43.3045"/>
<polygon fill="none" stroke="black" points="317.677,-45.5846 322.407,-36.1043 312.797,-40.5657 317.677,-45.5846"/> <polygon fill="none" stroke="black" points="408.677,-45.5846 413.407,-36.1043 403.797,-40.5657 408.677,-45.5846"/>
</g> </g>
<!-- Robot --> <!-- Robot -->
<g id="node9" class="node"><title>Robot</title> <g id="node10" class="node"><title>Robot</title>
<polygon fill="#298029" stroke="#298029" points="439,-108 385,-108 385,-72 439,-72 439,-108"/> <polygon fill="#298029" stroke="#298029" points="530,-108 476,-108 476,-72 530,-72 530,-108"/>
<text text-anchor="middle" x="412" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">Robot</text> <text text-anchor="middle" x="503" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">Robot</text>
</g> </g>
<!-- Motor --> <!-- Motor -->
<g id="node10" class="node"><title>Motor</title> <g id="node11" class="node"><title>Motor</title>
<polygon fill="#298029" stroke="#298029" points="439,-36 385,-36 385,-0 439,-0 439,-36"/> <polygon fill="#298029" stroke="#298029" points="530,-36 476,-36 476,-0 530,-0 530,-36"/>
<text text-anchor="middle" x="412" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">Motor</text> <text text-anchor="middle" x="503" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">Motor</text>
</g> </g>
<!-- Robot&#45;&gt;Motor --> <!-- Robot&#45;&gt;Motor -->
<g id="edge7" class="edge"><title>Robot&#45;&gt;Motor</title> <g id="edge9" class="edge"><title>Robot&#45;&gt;Motor</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M412,-71.6966C412,-63.9827 412,-54.7125 412,-46.1124"/> <path fill="none" stroke="black" stroke-dasharray="5,2" d="M503,-71.6966C503,-63.9827 503,-54.7125 503,-46.1124"/>
<polygon fill="none" stroke="black" points="415.5,-46.1043 412,-36.1043 408.5,-46.1044 415.5,-46.1043"/> <polygon fill="none" stroke="black" points="506.5,-46.1043 503,-36.1043 499.5,-46.1044 506.5,-46.1043"/>
</g> </g>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -32,6 +32,5 @@ digraph classes {
RyanteckRobot->Robot; RyanteckRobot->Robot;
CamJamKitRobot->Robot; CamJamKitRobot->Robot;
RGBLED->CompositeDevice;
Motor->CompositeDevice; Motor->CompositeDevice;
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -4,25 +4,25 @@
<!-- Generated by graphviz version 2.36.0 (20140111.2315) <!-- Generated by graphviz version 2.36.0 (20140111.2315)
--> -->
<!-- Title: classes Pages: 1 --> <!-- Title: classes Pages: 1 -->
<svg width="603pt" height="476pt" <svg width="587pt" height="476pt"
viewBox="0.00 0.00 603.00 476.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> viewBox="0.00 0.00 587.00 476.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 472)"> <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 472)">
<title>classes</title> <title>classes</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-472 599,-472 599,4 -4,4"/> <polygon fill="white" stroke="none" points="-4,4 -4,-472 583,-472 583,4 -4,4"/>
<!-- Device --> <!-- Device -->
<g id="node1" class="node"><title>Device</title> <g id="node1" class="node"><title>Device</title>
<polygon fill="#9ec6e0" stroke="#9ec6e0" points="485,-468 431,-468 431,-432 485,-432 485,-468"/> <polygon fill="#9ec6e0" stroke="#9ec6e0" points="449,-468 395,-468 395,-432 449,-432 449,-468"/>
<text text-anchor="middle" x="458" y="-447.5" font-family="Sans" font-size="10.00" fill="#000000">Device</text> <text text-anchor="middle" x="422" y="-447.5" font-family="Sans" font-size="10.00" fill="#000000">Device</text>
</g> </g>
<!-- CompositeDevice --> <!-- CompositeDevice -->
<g id="node2" class="node"><title>CompositeDevice</title> <g id="node2" class="node"><title>CompositeDevice</title>
<polygon fill="#9ec6e0" stroke="#9ec6e0" points="508.5,-396 407.5,-396 407.5,-360 508.5,-360 508.5,-396"/> <polygon fill="#9ec6e0" stroke="#9ec6e0" points="472.5,-396 371.5,-396 371.5,-360 472.5,-360 472.5,-396"/>
<text text-anchor="middle" x="458" y="-375.5" font-family="Sans" font-size="10.00" fill="#000000">CompositeDevice</text> <text text-anchor="middle" x="422" y="-375.5" font-family="Sans" font-size="10.00" fill="#000000">CompositeDevice</text>
</g> </g>
<!-- CompositeDevice&#45;&gt;Device --> <!-- CompositeDevice&#45;&gt;Device -->
<g id="edge1" class="edge"><title>CompositeDevice&#45;&gt;Device</title> <g id="edge1" class="edge"><title>CompositeDevice&#45;&gt;Device</title>
<path fill="none" stroke="black" d="M458,-396.303C458,-404.017 458,-413.288 458,-421.888"/> <path fill="none" stroke="black" d="M422,-396.303C422,-404.017 422,-413.288 422,-421.888"/>
<polygon fill="black" stroke="black" points="454.5,-421.896 458,-431.896 461.5,-421.896 454.5,-421.896"/> <polygon fill="black" stroke="black" points="418.5,-421.896 422,-431.896 425.5,-421.896 418.5,-421.896"/>
</g> </g>
<!-- CompositeOutputDevice --> <!-- CompositeOutputDevice -->
<g id="node3" class="node"><title>CompositeOutputDevice</title> <g id="node3" class="node"><title>CompositeOutputDevice</title>
@@ -31,8 +31,8 @@
</g> </g>
<!-- CompositeOutputDevice&#45;&gt;CompositeDevice --> <!-- CompositeOutputDevice&#45;&gt;CompositeDevice -->
<g id="edge2" class="edge"><title>CompositeOutputDevice&#45;&gt;CompositeDevice</title> <g id="edge2" class="edge"><title>CompositeOutputDevice&#45;&gt;CompositeDevice</title>
<path fill="none" stroke="black" d="M344.694,-324.124C365.018,-333.608 390.471,-345.487 412.102,-355.581"/> <path fill="none" stroke="black" d="M335.888,-324.124C350.793,-333.276 369.329,-344.658 385.382,-354.515"/>
<polygon fill="black" stroke="black" points="410.883,-358.874 421.425,-359.932 413.843,-352.531 410.883,-358.874"/> <polygon fill="black" stroke="black" points="383.652,-357.56 394.005,-359.81 387.315,-351.595 383.652,-357.56"/>
</g> </g>
<!-- LEDCollection --> <!-- LEDCollection -->
<g id="node4" class="node"><title>LEDCollection</title> <g id="node4" class="node"><title>LEDCollection</title>
@@ -141,8 +141,8 @@
</g> </g>
<!-- Robot&#45;&gt;CompositeDevice --> <!-- Robot&#45;&gt;CompositeDevice -->
<g id="edge13" class="edge"><title>Robot&#45;&gt;CompositeDevice</title> <g id="edge13" class="edge"><title>Robot&#45;&gt;CompositeDevice</title>
<path fill="none" stroke="black" d="M430.899,-324.303C434.997,-332.272 439.949,-341.9 444.493,-350.736"/> <path fill="none" stroke="black" d="M422,-324.303C422,-332.017 422,-341.288 422,-349.888"/>
<polygon fill="black" stroke="black" points="441.517,-352.604 449.203,-359.896 447.742,-349.402 441.517,-352.604"/> <polygon fill="black" stroke="black" points="418.5,-349.896 422,-359.896 425.5,-349.896 418.5,-349.896"/>
</g> </g>
<!-- RyanteckRobot --> <!-- RyanteckRobot -->
<g id="node15" class="node"><title>RyanteckRobot</title> <g id="node15" class="node"><title>RyanteckRobot</title>
@@ -164,25 +164,15 @@
<path fill="none" stroke="black" d="M504.336,-252.124C490.216,-261.192 472.689,-272.448 457.439,-282.241"/> <path fill="none" stroke="black" d="M504.336,-252.124C490.216,-261.192 472.689,-272.448 457.439,-282.241"/>
<polygon fill="black" stroke="black" points="455.29,-279.462 448.767,-287.81 459.073,-285.352 455.29,-279.462"/> <polygon fill="black" stroke="black" points="455.29,-279.462 448.767,-287.81 459.073,-285.352 455.29,-279.462"/>
</g> </g>
<!-- RGBLED -->
<g id="node17" class="node"><title>RGBLED</title>
<polygon fill="#2980b9" stroke="#2980b9" points="523,-324 467,-324 467,-288 523,-288 523,-324"/>
<text text-anchor="middle" x="495" y="-303.5" font-family="Sans" font-size="10.00" fill="#ffffff">RGBLED</text>
</g>
<!-- RGBLED&#45;&gt;CompositeDevice -->
<g id="edge16" class="edge"><title>RGBLED&#45;&gt;CompositeDevice</title>
<path fill="none" stroke="black" d="M485.854,-324.303C481.597,-332.356 476.444,-342.106 471.734,-351.018"/>
<polygon fill="black" stroke="black" points="468.62,-349.419 467.041,-359.896 474.808,-352.69 468.62,-349.419"/>
</g>
<!-- Motor --> <!-- Motor -->
<g id="node18" class="node"><title>Motor</title> <g id="node17" class="node"><title>Motor</title>
<polygon fill="#2980b9" stroke="#2980b9" points="595,-324 541,-324 541,-288 595,-288 595,-324"/> <polygon fill="#2980b9" stroke="#2980b9" points="521,-324 467,-324 467,-288 521,-288 521,-324"/>
<text text-anchor="middle" x="568" y="-303.5" font-family="Sans" font-size="10.00" fill="#ffffff">Motor</text> <text text-anchor="middle" x="494" y="-303.5" font-family="Sans" font-size="10.00" fill="#ffffff">Motor</text>
</g> </g>
<!-- Motor&#45;&gt;CompositeDevice --> <!-- Motor&#45;&gt;CompositeDevice -->
<g id="edge17" class="edge"><title>Motor&#45;&gt;CompositeDevice</title> <g id="edge16" class="edge"><title>Motor&#45;&gt;CompositeDevice</title>
<path fill="none" stroke="black" d="M541.091,-324.124C526.842,-333.192 509.154,-344.448 493.764,-354.241"/> <path fill="none" stroke="black" d="M476.202,-324.303C467.396,-332.865 456.618,-343.344 446.999,-352.696"/>
<polygon fill="black" stroke="black" points="491.57,-351.489 485.012,-359.81 495.328,-357.394 491.57,-351.489"/> <polygon fill="black" stroke="black" points="444.323,-350.415 439.593,-359.896 449.203,-355.434 444.323,-350.415"/>
</g> </g>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -30,5 +30,6 @@ digraph classes {
Buzzer->DigitalOutputDevice; Buzzer->DigitalOutputDevice;
PWMOutputDevice->OutputDevice; PWMOutputDevice->OutputDevice;
PWMLED->PWMOutputDevice; PWMLED->PWMOutputDevice;
RGBLED->Device;
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -11,8 +11,8 @@
<polygon fill="white" stroke="none" points="-4,4 -4,-328 717,-328 717,4 -4,4"/> <polygon fill="white" stroke="none" points="-4,4 -4,-328 717,-328 717,4 -4,4"/>
<!-- Device --> <!-- Device -->
<g id="node1" class="node"><title>Device</title> <g id="node1" class="node"><title>Device</title>
<polygon fill="#9ec6e0" stroke="#9ec6e0" points="499,-324 445,-324 445,-288 499,-288 499,-324"/> <polygon fill="#9ec6e0" stroke="#9ec6e0" points="540,-324 486,-324 486,-288 540,-288 540,-324"/>
<text text-anchor="middle" x="472" y="-303.5" font-family="Sans" font-size="10.00" fill="#000000">Device</text> <text text-anchor="middle" x="513" y="-303.5" font-family="Sans" font-size="10.00" fill="#000000">Device</text>
</g> </g>
<!-- GPIODevice --> <!-- GPIODevice -->
<g id="node2" class="node"><title>GPIODevice</title> <g id="node2" class="node"><title>GPIODevice</title>
@@ -21,8 +21,8 @@
</g> </g>
<!-- GPIODevice&#45;&gt;Device --> <!-- GPIODevice&#45;&gt;Device -->
<g id="edge1" class="edge"><title>GPIODevice&#45;&gt;Device</title> <g id="edge1" class="edge"><title>GPIODevice&#45;&gt;Device</title>
<path fill="none" stroke="black" d="M472,-252.303C472,-260.017 472,-269.288 472,-277.888"/> <path fill="none" stroke="black" d="M482.135,-252.303C486.852,-260.356 492.562,-270.106 497.782,-279.018"/>
<polygon fill="black" stroke="black" points="468.5,-277.896 472,-287.896 475.5,-277.896 468.5,-277.896"/> <polygon fill="black" stroke="black" points="494.908,-281.036 502.982,-287.896 500.948,-277.498 494.908,-281.036"/>
</g> </g>
<!-- SmoothedInputDevice --> <!-- SmoothedInputDevice -->
<g id="node3" class="node"><title>SmoothedInputDevice</title> <g id="node3" class="node"><title>SmoothedInputDevice</title>
@@ -164,5 +164,15 @@
<path fill="none" stroke="black" d="M661,-36.3034C661,-44.0173 661,-53.2875 661,-61.8876"/> <path fill="none" stroke="black" d="M661,-36.3034C661,-44.0173 661,-53.2875 661,-61.8876"/>
<polygon fill="black" stroke="black" points="657.5,-61.8956 661,-71.8957 664.5,-61.8957 657.5,-61.8956"/> <polygon fill="black" stroke="black" points="657.5,-61.8956 661,-71.8957 664.5,-61.8957 657.5,-61.8956"/>
</g> </g>
<!-- RGBLED -->
<g id="node17" class="node"><title>RGBLED</title>
<polygon fill="#2980b9" stroke="#2980b9" points="582,-252 526,-252 526,-216 582,-216 582,-252"/>
<text text-anchor="middle" x="554" y="-231.5" font-family="Sans" font-size="10.00" fill="#ffffff">RGBLED</text>
</g>
<!-- RGBLED&#45;&gt;Device -->
<g id="edge16" class="edge"><title>RGBLED&#45;&gt;Device</title>
<path fill="none" stroke="black" d="M543.865,-252.303C539.148,-260.356 533.438,-270.106 528.218,-279.018"/>
<polygon fill="black" stroke="black" points="525.052,-277.498 523.018,-287.896 531.092,-281.036 525.052,-277.498"/>
</g>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -14,7 +14,7 @@ Table of Contents
api_boards api_boards
api_other api_other
api_generic api_generic
api_source_tools api_tools
api_pins api_pins
api_exc api_exc
changelog changelog

View File

@@ -121,19 +121,3 @@ from .other_devices import (
PingServer, PingServer,
TimeOfDay, TimeOfDay,
) )
from .source_tools import (
averaged,
clamped,
conjunction,
cos_values,
disjunction,
inverted,
negated,
post_delayed,
pre_delayed,
quantized,
queued,
random_values,
scaled,
sin_values,
)

View File

@@ -258,7 +258,7 @@ class LEDBoard(LEDCollection):
on_time, off_time, fade_in_time, fade_out_time, n, background on_time, off_time, fade_in_time, fade_out_time, n, background
) )
def _blink_device(self, on_time, off_time, fade_in_time, fade_out_time, n, fps=50): def _blink_device(self, on_time, off_time, fade_in_time, fade_out_time, n, fps=25):
sequence = [] sequence = []
if fade_in_time > 0: if fade_in_time > 0:
sequence += [ sequence += [

View File

@@ -107,7 +107,13 @@ class GPIOMeta(type):
try: try:
old_close() old_close()
finally: finally:
del cls._INSTANCES[key] try:
del cls._INSTANCES[key]
except KeyError:
# If the _refs go negative (too many closes)
# just ignore the resulting KeyError here -
# it's already gone
pass
self.close = close self.close = close
cls._INSTANCES[key] = weakref.proxy(self) cls._INSTANCES[key] = weakref.proxy(self)
else: else:

View File

@@ -374,7 +374,7 @@ class HoldMixin(EventsMixin):
@hold_time.setter @hold_time.setter
def hold_time(self, value): def hold_time(self, value):
if value < 0: if value < 0:
raise BadWaitTime('source_delay must be 0 or greater') raise BadWaitTime('hold_time must be 0 or greater')
self._hold_time = float(value) self._hold_time = float(value)
@property @property
@@ -403,8 +403,8 @@ class HoldMixin(EventsMixin):
The length of time (in seconds) that the device has been held for. The length of time (in seconds) that the device has been held for.
This is counted from the first execution of the :attr:`when_held` event This is counted from the first execution of the :attr:`when_held` event
rather than when the device activated, in contrast to rather than when the device activated, in contrast to
:attr:`active_time`. If the device is not currently held, this is :attr:`~EventsMixin.active_time`. If the device is not currently held,
``None``. this is ``None``.
""" """
if self._held_from is not None: if self._held_from is not None:
return time() - self._held_from return time() - self._held_from

View File

@@ -19,8 +19,8 @@ class OutputDevice(SourceMixin, GPIODevice):
Represents a generic GPIO output device. Represents a generic GPIO output device.
This class extends :class:`GPIODevice` to add facilities common to GPIO This class extends :class:`GPIODevice` to add facilities common to GPIO
output devices: an :meth:`on` method to switch the device on, and a output devices: an :meth:`on` method to switch the device on, a
corresponding :meth:`off` method. corresponding :meth:`off` method, and a :meth:`toggle` method.
:param int pin: :param int pin:
The GPIO pin (in BCM numbering) that the device is connected to. If The GPIO pin (in BCM numbering) that the device is connected to. If
@@ -123,10 +123,9 @@ class DigitalOutputDevice(OutputDevice):
""" """
Represents a generic output device with typical on/off behaviour. Represents a generic output device with typical on/off behaviour.
This class extends :class:`OutputDevice` with a :meth:`toggle` method to This class extends :class:`OutputDevice` with a :meth:`blink` method which
switch the device between its on and off states, and a :meth:`blink` method uses an optional background thread to handle toggling the device state
which uses an optional background thread to handle toggling the device without further interaction.
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):
self._blink_thread = None self._blink_thread = None
@@ -458,7 +457,7 @@ class PWMOutputDevice(OutputDevice):
self._blink_thread = None self._blink_thread = None
def _blink_device( def _blink_device(
self, on_time, off_time, fade_in_time, fade_out_time, n, fps=50): self, on_time, off_time, fade_in_time, fade_out_time, n, fps=25):
sequence = [] sequence = []
if fade_in_time > 0: if fade_in_time > 0:
sequence += [ sequence += [
@@ -686,7 +685,7 @@ class RGBLED(SourceMixin, Device):
def _blink_device( def _blink_device(
self, on_time, off_time, fade_in_time, fade_out_time, on_color, self, on_time, off_time, fade_in_time, fade_out_time, on_color,
off_color, n, fps=50): off_color, n, fps=25):
# Define some simple lambdas to perform linear interpolation between # Define some simple lambdas to perform linear interpolation between
# off_color and on_color # off_color and on_color
lerp = lambda t, fade_in: tuple( lerp = lambda t, fade_in: tuple(

View File

@@ -159,7 +159,7 @@ class MockPin(Pin):
# that's about all we can reasonably expect in a non-realtime # that's about all we can reasonably expect in a non-realtime
# environment on a Pi 1) # environment on a Pi 1)
for actual, expected in zip(self.states, expected_states): for actual, expected in zip(self.states, expected_states):
assert isclose(actual.timestamp, expected[0], rel_tol=0.01, abs_tol=0.01) assert isclose(actual.timestamp, expected[0], rel_tol=0.05, abs_tol=0.05)
assert isclose(actual.state, expected[1]) assert isclose(actual.state, expected[1])

View File

@@ -31,84 +31,84 @@ def test_composite_output_on_off():
pin1 = MockPin(2) pin1 = MockPin(2)
pin2 = MockPin(3) pin2 = MockPin(3)
pin3 = MockPin(4) pin3 = MockPin(4)
device = CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) with CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) as device:
device.on() device.on()
assert all((pin1.state, pin2.state, pin3.state)) assert all((pin1.state, pin2.state, pin3.state))
device.off() device.off()
assert not any((pin1.state, pin2.state, pin3.state)) assert not any((pin1.state, pin2.state, pin3.state))
def test_composite_output_toggle(): def test_composite_output_toggle():
pin1 = MockPin(2) pin1 = MockPin(2)
pin2 = MockPin(3) pin2 = MockPin(3)
pin3 = MockPin(4) pin3 = MockPin(4)
device = CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) with CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) as device:
device.toggle() device.toggle()
assert all((pin1.state, pin2.state, pin3.state)) assert all((pin1.state, pin2.state, pin3.state))
device[0].off() device[0].off()
device.toggle() device.toggle()
assert pin1.state assert pin1.state
assert not pin2.state assert not pin2.state
assert not pin3.state assert not pin3.state
def test_composite_output_value(): def test_composite_output_value():
pin1 = MockPin(2) pin1 = MockPin(2)
pin2 = MockPin(3) pin2 = MockPin(3)
pin3 = MockPin(4) pin3 = MockPin(4)
device = CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) with CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) as device:
assert device.value == (0, 0, 0) assert device.value == (0, 0, 0)
device.toggle() device.toggle()
assert device.value == (1, 1, 1) assert device.value == (1, 1, 1)
device.value = (1, 0, 1) device.value = (1, 0, 1)
assert device[0].is_active assert device[0].is_active
assert not device[1].is_active assert not device[1].is_active
assert device[2].is_active assert device[2].is_active
def test_led_board_on_off(): def test_led_board_on_off():
pin1 = MockPin(2) pin1 = MockPin(2)
pin2 = MockPin(3) pin2 = MockPin(3)
pin3 = MockPin(4) pin3 = MockPin(4)
board = LEDBoard(pin1, pin2, foo=pin3) with LEDBoard(pin1, pin2, foo=pin3) as board:
assert isinstance(board[0], LED) assert isinstance(board[0], LED)
assert isinstance(board[1], LED) assert isinstance(board[1], LED)
assert isinstance(board[2], LED) assert isinstance(board[2], LED)
board.on() board.on()
assert all((pin1.state, pin2.state, pin3.state)) assert all((pin1.state, pin2.state, pin3.state))
board.off() board.off()
assert not any((pin1.state, pin2.state, pin3.state)) assert not any((pin1.state, pin2.state, pin3.state))
board[0].on() board[0].on()
assert board.value == (1, 0, 0) assert board.value == (1, 0, 0)
assert pin1.state assert pin1.state
assert not pin2.state assert not pin2.state
assert not pin3.state assert not pin3.state
board.toggle() board.toggle()
assert board.value == (0, 1, 1) assert board.value == (0, 1, 1)
assert not pin1.state assert not pin1.state
assert pin2.state assert pin2.state
assert pin3.state assert pin3.state
def test_led_board_nested(): def test_led_board_nested():
pin1 = MockPin(2) pin1 = MockPin(2)
pin2 = MockPin(3) pin2 = MockPin(3)
pin3 = MockPin(4) pin3 = MockPin(4)
board = LEDBoard(pin1, LEDBoard(pin2, pin3)) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board:
assert list(led.pin for led in board.leds) == [pin1, pin2, pin3] assert list(led.pin for led in board.leds) == [pin1, pin2, pin3]
assert board.value == (0, (0, 0)) assert board.value == (0, (0, 0))
board.value = (1, (0, 1)) board.value = (1, (0, 1))
assert pin1.state assert pin1.state
assert not pin2.state assert not pin2.state
assert pin3.state assert pin3.state
def test_led_board_bad_blink(): def test_led_board_bad_blink():
pin1 = MockPin(2) pin1 = MockPin(2)
pin2 = MockPin(3) pin2 = MockPin(3)
pin3 = MockPin(4) pin3 = MockPin(4)
board = LEDBoard(pin1, LEDBoard(pin2, pin3)) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board:
with pytest.raises(ValueError): with pytest.raises(ValueError):
board.blink(fade_in_time=1, fade_out_time=1) board.blink(fade_in_time=1, fade_out_time=1)
with pytest.raises(ValueError): with pytest.raises(ValueError):
board.blink(fade_out_time=1) board.blink(fade_out_time=1)
with pytest.raises(ValueError): with pytest.raises(ValueError):
board.pulse() board.pulse()
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
@@ -116,19 +116,19 @@ def test_led_board_blink_background():
pin1 = MockPin(2) pin1 = MockPin(2)
pin2 = MockPin(3) pin2 = MockPin(3)
pin3 = MockPin(4) pin3 = MockPin(4)
board = LEDBoard(pin1, LEDBoard(pin2, pin3)) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board:
board.blink(0.1, 0.1, n=2) board.blink(0.1, 0.1, n=2)
board._blink_thread.join() # naughty, but ensures no arbitrary waits in the test board._blink_thread.join() # naughty, but ensures no arbitrary waits in the test
test = [ test = [
(0.0, False), (0.0, False),
(0.0, True), (0.0, True),
(0.1, False), (0.1, False),
(0.1, True), (0.1, True),
(0.1, False) (0.1, False)
] ]
pin1.assert_states_and_times(test) pin1.assert_states_and_times(test)
pin2.assert_states_and_times(test) pin2.assert_states_and_times(test)
pin3.assert_states_and_times(test) pin3.assert_states_and_times(test)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
@@ -136,18 +136,18 @@ def test_led_board_blink_foreground():
pin1 = MockPin(2) pin1 = MockPin(2)
pin2 = MockPin(3) pin2 = MockPin(3)
pin3 = MockPin(4) pin3 = MockPin(4)
board = LEDBoard(pin1, LEDBoard(pin2, pin3)) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board:
board.blink(0.1, 0.1, n=2, background=False) board.blink(0.1, 0.1, n=2, background=False)
test = [ test = [
(0.0, False), (0.0, False),
(0.0, True), (0.0, True),
(0.1, False), (0.1, False),
(0.1, True), (0.1, True),
(0.1, False) (0.1, False)
] ]
pin1.assert_states_and_times(test) pin1.assert_states_and_times(test)
pin2.assert_states_and_times(test) pin2.assert_states_and_times(test)
pin3.assert_states_and_times(test) pin3.assert_states_and_times(test)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
@@ -155,24 +155,24 @@ def test_led_board_blink_control():
pin1 = MockPin(2) pin1 = MockPin(2)
pin2 = MockPin(3) pin2 = MockPin(3)
pin3 = MockPin(4) pin3 = MockPin(4)
board = LEDBoard(pin1, LEDBoard(pin2, pin3)) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board:
board.blink(0.1, 0.1, n=2) board.blink(0.1, 0.1, n=2)
# make sure the blink thread's started # make sure the blink thread's started
while not board._blink_leds: while not board._blink_leds:
sleep(0.00001) sleep(0.00001)
board[1][0].off() # immediately take over the second LED board[1][0].off() # immediately take over the second LED
board._blink_thread.join() # naughty, but ensures no arbitrary waits in the test board._blink_thread.join() # naughty, but ensures no arbitrary waits in the test
test = [ test = [
(0.0, False), (0.0, False),
(0.0, True), (0.0, True),
(0.1, False), (0.1, False),
(0.1, True), (0.1, True),
(0.1, False) (0.1, False)
] ]
pin1.assert_states_and_times(test) pin1.assert_states_and_times(test)
pin3.assert_states_and_times(test) pin3.assert_states_and_times(test)
print(pin2.states) print(pin2.states)
pin2.assert_states_and_times([(0.0, False), (0.0, True), (0.0, False)]) pin2.assert_states_and_times([(0.0, False), (0.0, True), (0.0, False)])
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
@@ -180,21 +180,21 @@ def test_led_board_blink_take_over():
pin1 = MockPin(2) pin1 = MockPin(2)
pin2 = MockPin(3) pin2 = MockPin(3)
pin3 = MockPin(4) pin3 = MockPin(4)
board = LEDBoard(pin1, LEDBoard(pin2, pin3)) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board:
board[1].blink(0.1, 0.1, n=2) board[1].blink(0.1, 0.1, n=2)
board.blink(0.1, 0.1, n=2) # immediately take over blinking board.blink(0.1, 0.1, n=2) # immediately take over blinking
board[1]._blink_thread.join() board[1]._blink_thread.join()
board._blink_thread.join() board._blink_thread.join()
test = [ test = [
(0.0, False), (0.0, False),
(0.0, True), (0.0, True),
(0.1, False), (0.1, False),
(0.1, True), (0.1, True),
(0.1, False) (0.1, False)
] ]
pin1.assert_states_and_times(test) pin1.assert_states_and_times(test)
pin2.assert_states_and_times(test) pin2.assert_states_and_times(test)
pin3.assert_states_and_times(test) pin3.assert_states_and_times(test)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
@@ -202,47 +202,47 @@ def test_led_board_blink_control_all():
pin1 = MockPin(2) pin1 = MockPin(2)
pin2 = MockPin(3) pin2 = MockPin(3)
pin3 = MockPin(4) pin3 = MockPin(4)
board = LEDBoard(pin1, LEDBoard(pin2, pin3)) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board:
board.blink(0.1, 0.1, n=2) board.blink(0.1, 0.1, n=2)
# make sure the blink thread's started # make sure the blink thread's started
while not board._blink_leds: while not board._blink_leds:
sleep(0.00001) sleep(0.00001)
board[0].off() # immediately take over all LEDs board[0].off() # immediately take over all LEDs
board[1][0].off() board[1][0].off()
board[1][1].off() board[1][1].off()
board._blink_thread.join() # blink should terminate here anyway board._blink_thread.join() # blink should terminate here anyway
test = [ test = [
(0.0, False), (0.0, False),
(0.0, True), (0.0, True),
(0.0, False), (0.0, False),
] ]
pin1.assert_states_and_times(test) pin1.assert_states_and_times(test)
pin2.assert_states_and_times(test) pin2.assert_states_and_times(test)
pin3.assert_states_and_times(test) pin3.assert_states_and_times(test)
def test_led_board_blink_interrupt_on(): def test_led_board_blink_interrupt_on():
pin1 = MockPin(2) pin1 = MockPin(2)
pin2 = MockPin(3) pin2 = MockPin(3)
pin3 = MockPin(4) pin3 = MockPin(4)
board = LEDBoard(pin1, LEDBoard(pin2, pin3)) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board:
board.blink(1, 0.1) board.blink(1, 0.1)
sleep(0.2) sleep(0.2)
board.off() # should interrupt while on board.off() # should interrupt while on
pin1.assert_states([False, True, False]) pin1.assert_states([False, True, False])
pin2.assert_states([False, True, False]) pin2.assert_states([False, True, False])
pin3.assert_states([False, True, False]) pin3.assert_states([False, True, False])
def test_led_board_blink_interrupt_off(): def test_led_board_blink_interrupt_off():
pin1 = MockPin(2) pin1 = MockPin(2)
pin2 = MockPin(3) pin2 = MockPin(3)
pin3 = MockPin(4) pin3 = MockPin(4)
board = LEDBoard(pin1, LEDBoard(pin2, pin3)) with LEDBoard(pin1, LEDBoard(pin2, pin3)) as board:
board.blink(0.1, 1) board.blink(0.1, 1)
sleep(0.2) sleep(0.2)
board.off() # should interrupt while off board.off() # should interrupt while off
pin1.assert_states([False, True, False]) pin1.assert_states([False, True, False])
pin2.assert_states([False, True, False]) pin2.assert_states([False, True, False])
pin3.assert_states([False, True, False]) pin3.assert_states([False, True, False])
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
@@ -250,76 +250,76 @@ def test_led_board_fade_background():
pin1 = MockPWMPin(2) pin1 = MockPWMPin(2)
pin2 = MockPWMPin(3) pin2 = MockPWMPin(3)
pin3 = MockPWMPin(4) pin3 = MockPWMPin(4)
board = LEDBoard(pin1, LEDBoard(pin2, pin3, pwm=True), pwm=True) with LEDBoard(pin1, LEDBoard(pin2, pin3, pwm=True), pwm=True) as board:
board.blink(0, 0, 0.1, 0.1, n=2) board.blink(0, 0, 0.2, 0.2, n=2)
board._blink_thread.join() board._blink_thread.join()
test = [ test = [
(0.0, 0), (0.0, 0),
(0.02, 0.2), (0.04, 0.2),
(0.02, 0.4), (0.04, 0.4),
(0.02, 0.6), (0.04, 0.6),
(0.02, 0.8), (0.04, 0.8),
(0.02, 1), (0.04, 1),
(0.02, 0.8), (0.04, 0.8),
(0.02, 0.6), (0.04, 0.6),
(0.02, 0.4), (0.04, 0.4),
(0.02, 0.2), (0.04, 0.2),
(0.02, 0), (0.04, 0),
(0.02, 0.2), (0.04, 0.2),
(0.02, 0.4), (0.04, 0.4),
(0.02, 0.6), (0.04, 0.6),
(0.02, 0.8), (0.04, 0.8),
(0.02, 1), (0.04, 1),
(0.02, 0.8), (0.04, 0.8),
(0.02, 0.6), (0.04, 0.6),
(0.02, 0.4), (0.04, 0.4),
(0.02, 0.2), (0.04, 0.2),
(0.02, 0), (0.04, 0),
] ]
pin1.assert_states_and_times(test) pin1.assert_states_and_times(test)
pin2.assert_states_and_times(test) pin2.assert_states_and_times(test)
pin3.assert_states_and_times(test) pin3.assert_states_and_times(test)
def test_led_bar_graph_value(): def test_led_bar_graph_value():
pin1 = MockPin(2) pin1 = MockPin(2)
pin2 = MockPin(3) pin2 = MockPin(3)
pin3 = MockPin(4) pin3 = MockPin(4)
graph = LEDBarGraph(pin1, pin2, pin3) with LEDBarGraph(pin1, pin2, pin3) as graph:
graph.value = 0 graph.value = 0
assert not any((pin1.state, pin2.state, pin3.state)) assert not any((pin1.state, pin2.state, pin3.state))
graph.value = 1 graph.value = 1
assert all((pin1.state, pin2.state, pin3.state)) assert all((pin1.state, pin2.state, pin3.state))
graph.value = 1/3 graph.value = 1/3
assert pin1.state and not (pin2.state or pin3.state) assert pin1.state and not (pin2.state or pin3.state)
graph.value = -1/3 graph.value = -1/3
assert pin3.state and not (pin1.state or pin2.state) assert pin3.state and not (pin1.state or pin2.state)
pin1.state = True pin1.state = True
pin2.state = True pin2.state = True
assert graph.value == 1 assert graph.value == 1
pin3.state = False pin3.state = False
assert graph.value == 2/3 assert graph.value == 2/3
pin3.state = True pin3.state = True
pin1.state = False pin1.state = False
assert graph.value == -2/3 assert graph.value == -2/3
def test_led_bar_graph_pwm_value(): def test_led_bar_graph_pwm_value():
pin1 = MockPWMPin(2) pin1 = MockPWMPin(2)
pin2 = MockPWMPin(3) pin2 = MockPWMPin(3)
pin3 = MockPWMPin(4) pin3 = MockPWMPin(4)
graph = LEDBarGraph(pin1, pin2, pin3, pwm=True) with LEDBarGraph(pin1, pin2, pin3, pwm=True) as graph:
graph.value = 0 graph.value = 0
assert not any((pin1.state, pin2.state, pin3.state)) assert not any((pin1.state, pin2.state, pin3.state))
graph.value = 1 graph.value = 1
assert all((pin1.state, pin2.state, pin3.state)) assert all((pin1.state, pin2.state, pin3.state))
graph.value = 1/3 graph.value = 1/3
assert pin1.state and not (pin2.state or pin3.state) assert pin1.state and not (pin2.state or pin3.state)
graph.value = -1/3 graph.value = -1/3
assert pin3.state and not (pin1.state or pin2.state) assert pin3.state and not (pin1.state or pin2.state)
graph.value = 1/2 graph.value = 1/2
assert (pin1.state, pin2.state, pin3.state) == (1, 0.5, 0) assert (pin1.state, pin2.state, pin3.state) == (1, 0.5, 0)
pin1.state = 0 pin1.state = 0
pin3.state = 1 pin3.state = 1
assert graph.value == -1/2 assert graph.value == -1/2
def test_led_bar_graph_bad_init(): def test_led_bar_graph_bad_init():
pin1 = MockPin(2) pin1 = MockPin(2)
@@ -330,26 +330,26 @@ def test_led_bar_graph_bad_init():
def test_pi_liter(): def test_pi_liter():
pins = [MockPin(n) for n in (4, 17, 27, 18, 22, 23, 24, 25)] pins = [MockPin(n) for n in (4, 17, 27, 18, 22, 23, 24, 25)]
board = PiLiter() with PiLiter() as board:
assert [device.pin for device in board] == pins assert [device.pin for device in board] == pins
def test_pi_liter_graph(): def test_pi_liter_graph():
pins = [MockPin(n) for n in (4, 17, 27, 18, 22, 23, 24, 25)] pins = [MockPin(n) for n in (4, 17, 27, 18, 22, 23, 24, 25)]
board = PiLiterBarGraph() with PiLiterBarGraph() as board:
board.value = 0.5 board.value = 0.5
assert [pin.state for pin in pins] == [1, 1, 1, 1, 0, 0, 0, 0] assert [pin.state for pin in pins] == [1, 1, 1, 1, 0, 0, 0, 0]
pins[4].state = 1 pins[4].state = 1
assert board.value == 5/8 assert board.value == 5/8
def test_traffic_lights(): def test_traffic_lights():
red_pin = MockPin(2) red_pin = MockPin(2)
amber_pin = MockPin(3) amber_pin = MockPin(3)
green_pin = MockPin(4) green_pin = MockPin(4)
board = TrafficLights(red_pin, amber_pin, green_pin) with TrafficLights(red_pin, amber_pin, green_pin) as board:
board.red.on() board.red.on()
assert red_pin.state assert red_pin.state
assert not amber_pin.state assert not amber_pin.state
assert not green_pin.state assert not green_pin.state
def test_traffic_lights_bad_init(): def test_traffic_lights_bad_init():
with pytest.raises(ValueError): with pytest.raises(ValueError):
@@ -357,13 +357,13 @@ def test_traffic_lights_bad_init():
def test_pi_traffic(): def test_pi_traffic():
pins = [MockPin(n) for n in (9, 10, 11)] pins = [MockPin(n) for n in (9, 10, 11)]
board = PiTraffic() with PiTraffic() as board:
assert [device.pin for device in board] == pins assert [device.pin for device in board] == pins
def test_snow_pi(): def test_snow_pi():
pins = [MockPin(n) for n in (23, 24, 25, 17, 18, 22, 7, 8, 9)] pins = [MockPin(n) for n in (23, 24, 25, 17, 18, 22, 7, 8, 9)]
board = SnowPi() with SnowPi() as board:
assert [device.pin for device in board.leds] == pins assert [device.pin for device in board.leds] == pins
def test_traffic_lights_buzzer(): def test_traffic_lights_buzzer():
red_pin = MockPin(2) red_pin = MockPin(2)
@@ -371,59 +371,59 @@ def test_traffic_lights_buzzer():
green_pin = MockPin(4) green_pin = MockPin(4)
buzzer_pin = MockPin(5) buzzer_pin = MockPin(5)
button_pin = MockPin(6) button_pin = MockPin(6)
board = TrafficLightsBuzzer( with TrafficLightsBuzzer(
TrafficLights(red_pin, amber_pin, green_pin), TrafficLights(red_pin, amber_pin, green_pin),
Buzzer(buzzer_pin), Buzzer(buzzer_pin),
Button(button_pin)) Button(button_pin)) as board:
board.lights.red.on() board.lights.red.on()
board.buzzer.on() board.buzzer.on()
assert red_pin.state assert red_pin.state
assert not amber_pin.state assert not amber_pin.state
assert not green_pin.state assert not green_pin.state
assert buzzer_pin.state assert buzzer_pin.state
button_pin.drive_low() button_pin.drive_low()
assert board.button.is_active assert board.button.is_active
def test_fish_dish(): def test_fish_dish():
pins = [MockPin(n) for n in (9, 22, 4, 8, 7)] pins = [MockPin(n) for n in (9, 22, 4, 8, 7)]
board = FishDish() with FishDish() as board:
assert [led.pin for led in board.lights] + [board.buzzer.pin, board.button.pin] == pins assert [led.pin for led in board.lights] + [board.buzzer.pin, board.button.pin] == pins
def test_traffic_hat(): def test_traffic_hat():
pins = [MockPin(n) for n in (24, 23, 22, 5, 25)] pins = [MockPin(n) for n in (24, 23, 22, 5, 25)]
board = TrafficHat() with TrafficHat() as board:
assert [led.pin for led in board.lights] + [board.buzzer.pin, board.button.pin] == pins assert [led.pin for led in board.lights] + [board.buzzer.pin, board.button.pin] == pins
def test_robot(): def test_robot():
pins = [MockPWMPin(n) for n in (2, 3, 4, 5)] pins = [MockPWMPin(n) for n in (2, 3, 4, 5)]
robot = Robot((2, 3), (4, 5)) with Robot((2, 3), (4, 5)) as robot:
assert ( assert (
[device.pin for device in robot.left_motor] + [device.pin for device in robot.left_motor] +
[device.pin for device in robot.right_motor]) == pins [device.pin for device in robot.right_motor]) == pins
robot.forward() robot.forward()
assert [pin.state for pin in pins] == [1, 0, 1, 0] assert [pin.state for pin in pins] == [1, 0, 1, 0]
robot.backward() robot.backward()
assert [pin.state for pin in pins] == [0, 1, 0, 1] assert [pin.state for pin in pins] == [0, 1, 0, 1]
robot.forward(0.5) robot.forward(0.5)
assert [pin.state for pin in pins] == [0.5, 0, 0.5, 0] assert [pin.state for pin in pins] == [0.5, 0, 0.5, 0]
robot.left() robot.left()
assert [pin.state for pin in pins] == [0, 1, 1, 0] assert [pin.state for pin in pins] == [0, 1, 1, 0]
robot.right() robot.right()
assert [pin.state for pin in pins] == [1, 0, 0, 1] assert [pin.state for pin in pins] == [1, 0, 0, 1]
robot.reverse() robot.reverse()
assert [pin.state for pin in pins] == [0, 1, 1, 0] assert [pin.state for pin in pins] == [0, 1, 1, 0]
robot.stop() robot.stop()
assert [pin.state for pin in pins] == [0, 0, 0, 0] assert [pin.state for pin in pins] == [0, 0, 0, 0]
def test_ryanteck_robot(): def test_ryanteck_robot():
pins = [MockPWMPin(n) for n in (17, 18, 22, 23)] pins = [MockPWMPin(n) for n in (17, 18, 22, 23)]
board = RyanteckRobot() with RyanteckRobot() as board:
assert [device.pin for motor in board for device in motor] == pins assert [device.pin for motor in board for device in motor] == pins
def test_camjam_kit_robot(): def test_camjam_kit_robot():
pins = [MockPWMPin(n) for n in (9, 10, 7, 8)] pins = [MockPWMPin(n) for n in (9, 10, 7, 8)]
board = CamJamKitRobot() with CamJamKitRobot() as board:
assert [device.pin for motor in board for device in motor] == pins assert [device.pin for motor in board for device in motor] == pins
def test_energenie_bad_init(): def test_energenie_bad_init():
with pytest.raises(ValueError): with pytest.raises(ValueError):
@@ -433,26 +433,26 @@ def test_energenie_bad_init():
def test_energenie(): def test_energenie():
pins = [MockPin(n) for n in (17, 22, 23, 27, 24, 25)] pins = [MockPin(n) for n in (17, 22, 23, 27, 24, 25)]
device1 = Energenie(1, initial_value=True) with Energenie(1, initial_value=True) as device1, \
device2 = Energenie(2, initial_value=False) Energenie(2, initial_value=False) as device2:
assert device1.value assert device1.value
assert not device2.value assert not device2.value
[pin.clear_states() for pin in pins] [pin.clear_states() for pin in pins]
device1.on() device1.on()
assert device1.value assert device1.value
pins[0].assert_states_and_times([(0.0, False), (0.0, True)]) pins[0].assert_states_and_times([(0.0, False), (0.0, True)])
pins[1].assert_states_and_times([(0.0, True), (0.0, True)]) pins[1].assert_states_and_times([(0.0, True), (0.0, True)])
pins[2].assert_states_and_times([(0.0, True), (0.0, True)]) pins[2].assert_states_and_times([(0.0, True), (0.0, True)])
pins[3].assert_states_and_times([(0.0, False), (0.0, True)]) pins[3].assert_states_and_times([(0.0, False), (0.0, True)])
pins[4].assert_states_and_times([(0.0, False)]) pins[4].assert_states_and_times([(0.0, False)])
pins[5].assert_states_and_times([(0.0, False), (0.1, True), (0.25, False)]) pins[5].assert_states_and_times([(0.0, False), (0.1, True), (0.25, False)])
[pin.clear_states() for pin in pins] [pin.clear_states() for pin in pins]
device2.on() device2.on()
assert device2.value assert device2.value
pins[0].assert_states_and_times([(0.0, True), (0.0, False)]) pins[0].assert_states_and_times([(0.0, True), (0.0, False)])
pins[1].assert_states_and_times([(0.0, True), (0.0, True)]) pins[1].assert_states_and_times([(0.0, True), (0.0, True)])
pins[2].assert_states_and_times([(0.0, True), (0.0, True)]) pins[2].assert_states_and_times([(0.0, True), (0.0, True)])
pins[3].assert_states_and_times([(0.0, True), (0.0, True)]) pins[3].assert_states_and_times([(0.0, True), (0.0, True)])
pins[4].assert_states_and_times([(0.0, False)]) pins[4].assert_states_and_times([(0.0, False)])
pins[5].assert_states_and_times([(0.0, False), (0.1, True), (0.25, False)]) pins[5].assert_states_and_times([(0.0, False), (0.1, True), (0.25, False)])

View File

@@ -24,21 +24,22 @@ def test_device_no_pin():
def test_device_init(): def test_device_init():
pin = MockPin(2) pin = MockPin(2)
device = GPIODevice(pin) with GPIODevice(pin) as device:
assert not device.closed assert not device.closed
assert device.pin == pin assert device.pin == pin
def test_device_init_twice_same_pin(): def test_device_init_twice_same_pin():
pin = MockPin(2) pin = MockPin(2)
device = GPIODevice(pin) with GPIODevice(pin) as device:
with pytest.raises(GPIOPinInUse): with pytest.raises(GPIOPinInUse):
device2 = GPIODevice(pin) device2 = GPIODevice(pin)
def test_device_init_twice_different_pin(): def test_device_init_twice_different_pin():
pin = MockPin(2) pin = MockPin(2)
device = GPIODevice(pin)
pin2 = MockPin(3) pin2 = MockPin(3)
device2 = GPIODevice(pin2) with GPIODevice(pin) as device:
with GPIODevice(pin2) as device2:
pass
def test_device_close(): def test_device_close():
pin = MockPin(2) pin = MockPin(2)
@@ -56,11 +57,12 @@ def test_device_reopen_same_pin():
assert device2.pin == pin assert device2.pin == pin
assert device.closed assert device.closed
assert device.pin is None assert device.pin is None
device2.close()
def test_device_repr(): def test_device_repr():
pin = MockPin(2) pin = MockPin(2)
device = GPIODevice(pin) with GPIODevice(pin) as device:
assert repr(device) == '<gpiozero.GPIODevice object on pin %s, is_active=False>' % pin assert repr(device) == '<gpiozero.GPIODevice object on pin %s, is_active=False>' % pin
def test_device_repr_after_close(): def test_device_repr_after_close():
pin = MockPin(2) pin = MockPin(2)
@@ -70,9 +72,9 @@ def test_device_repr_after_close():
def test_device_unknown_attr(): def test_device_unknown_attr():
pin = MockPin(2) pin = MockPin(2)
device = GPIODevice(pin) with GPIODevice(pin) as device:
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
device.foo = 1 device.foo = 1
def test_device_context_manager(): def test_device_context_manager():
pin = MockPin(2) pin = MockPin(2)
@@ -81,35 +83,35 @@ def test_device_context_manager():
assert device.closed assert device.closed
def test_composite_device_sequence(): def test_composite_device_sequence():
device = CompositeDevice( with CompositeDevice(
InputDevice(MockPin(2)), InputDevice(MockPin(2)),
InputDevice(MockPin(3)) InputDevice(MockPin(3))
) ) as device:
assert len(device) == 2 assert len(device) == 2
assert device[0].pin.number == 2 assert device[0].pin.number == 2
assert device[1].pin.number == 3 assert device[1].pin.number == 3
assert device.tuple._fields == ('_0', '_1') assert device.tuple._fields == ('_0', '_1')
def test_composite_device_values(): def test_composite_device_values():
device = CompositeDevice( with CompositeDevice(
InputDevice(MockPin(2)), InputDevice(MockPin(2)),
InputDevice(MockPin(3)) InputDevice(MockPin(3))
) ) as device:
assert device.value == (0, 0) assert device.value == (0, 0)
assert not device.is_active assert not device.is_active
device[0].pin.drive_high() device[0].pin.drive_high()
assert device.value == (1, 0) assert device.value == (1, 0)
assert device.is_active assert device.is_active
def test_composite_device_named(): def test_composite_device_named():
device = CompositeDevice( with CompositeDevice(
foo=InputDevice(MockPin(2)), foo=InputDevice(MockPin(2)),
bar=InputDevice(MockPin(3)), bar=InputDevice(MockPin(3)),
_order=('foo', 'bar') _order=('foo', 'bar')
) ) as device:
assert device.tuple._fields == ('foo', 'bar') assert device.tuple._fields == ('foo', 'bar')
assert device.value == (0, 0) assert device.value == (0, 0)
assert not device.is_active assert not device.is_active
def test_composite_device_bad_init(): def test_composite_device_bad_init():
with pytest.raises(ValueError): with pytest.raises(ValueError):

View File

@@ -25,131 +25,121 @@ def teardown_function(function):
def test_input_initial_values(): def test_input_initial_values():
pin = MockPin(2) pin = MockPin(2)
device = InputDevice(pin, pull_up=True) with InputDevice(pin, pull_up=True) as device:
assert pin.function == 'input' assert pin.function == 'input'
assert pin.pull == 'up' assert pin.pull == 'up'
assert device.pull_up assert device.pull_up
device.close() device.close()
device = InputDevice(pin, pull_up=False) device = InputDevice(pin, pull_up=False)
assert pin.pull == 'down' assert pin.pull == 'down'
assert not device.pull_up assert not device.pull_up
device.close()
def test_input_is_active(): def test_input_is_active():
pin = MockPin(2) pin = MockPin(2)
device = InputDevice(pin, pull_up=True) with InputDevice(pin, pull_up=True) as device:
pin.drive_high() pin.drive_high()
assert not device.is_active assert not device.is_active
pin.drive_low() pin.drive_low()
assert device.is_active assert device.is_active
def test_input_pulled_up(): def test_input_pulled_up():
pin = MockPulledUpPin(2) pin = MockPulledUpPin(2)
with pytest.raises(PinFixedPull): with pytest.raises(PinFixedPull):
device = InputDevice(pin, pull_up=False) InputDevice(pin, pull_up=False)
def test_input_event_activated(): def test_input_event_activated():
event = Event() event = Event()
pin = MockPin(2) pin = MockPin(2)
device = DigitalInputDevice(pin) with DigitalInputDevice(pin) as device:
device.when_activated = lambda: event.set() device.when_activated = lambda: event.set()
assert not event.wait(0) assert not event.wait(0)
pin.drive_high() pin.drive_high()
assert event.wait(0) assert event.wait(0)
def test_input_event_deactivated(): def test_input_event_deactivated():
event = Event() event = Event()
pin = MockPin(2) pin = MockPin(2)
device = DigitalInputDevice(pin) with DigitalInputDevice(pin) as device:
device.when_deactivated = lambda: event.set() device.when_deactivated = lambda: event.set()
assert not event.wait(0) assert not event.wait(0)
pin.drive_high() pin.drive_high()
assert not event.wait(0) assert not event.wait(0)
pin.drive_low() pin.drive_low()
assert event.wait(0) assert event.wait(0)
def test_input_wait_active(): def test_input_wait_active():
pin = MockPin(2) pin = MockPin(2)
device = DigitalInputDevice(pin) with DigitalInputDevice(pin) as device:
pin.drive_high() pin.drive_high()
assert device.wait_for_active(1) assert device.wait_for_active(1)
assert not device.wait_for_inactive(0) assert not device.wait_for_inactive(0)
def test_input_wait_inactive(): def test_input_wait_inactive():
pin = MockPin(2) pin = MockPin(2)
device = DigitalInputDevice(pin) with DigitalInputDevice(pin) as device:
assert device.wait_for_inactive(1) assert device.wait_for_inactive(1)
assert not device.wait_for_active(0) assert not device.wait_for_active(0)
def test_input_smoothed_attrib(): def test_input_smoothed_attrib():
pin = MockPin(2) pin = MockPin(2)
device = SmoothedInputDevice(pin, threshold=0.5, queue_len=5, partial=False) with SmoothedInputDevice(pin, threshold=0.5, queue_len=5, partial=False) as device:
assert device.threshold == 0.5 assert device.threshold == 0.5
assert device.queue_len == 5 assert device.queue_len == 5
assert not device.partial assert not device.partial
device._queue.start() device._queue.start()
assert not device.is_active assert not device.is_active
def test_input_smoothed_silly():
pin = MockPin(2)
with pytest.raises(InputDeviceError):
device = SmoothedInputDevice(pin, threshold=-1)
device = SmoothedInputDevice(pin)
del device._queue.stopping
with pytest.raises(AttributeError):
device.close()
def test_input_smoothed_values(): def test_input_smoothed_values():
pin = MockPin(2) pin = MockPin(2)
device = SmoothedInputDevice(pin) with SmoothedInputDevice(pin) as device:
device._queue.start() device._queue.start()
assert not device.is_active assert not device.is_active
pin.drive_high() pin.drive_high()
assert device.wait_for_active(1) assert device.wait_for_active(1)
pin.drive_low() pin.drive_low()
assert device.wait_for_inactive(1) assert device.wait_for_inactive(1)
def test_input_button(): def test_input_button():
pin = MockPin(2) pin = MockPin(2)
button = Button(pin) with Button(pin) as button:
assert pin.pull == 'up' assert pin.pull == 'up'
assert not button.is_pressed assert not button.is_pressed
pin.drive_low() pin.drive_low()
assert button.is_pressed assert button.is_pressed
assert button.wait_for_press(1) assert button.wait_for_press(1)
pin.drive_high() pin.drive_high()
assert not button.is_pressed assert not button.is_pressed
assert button.wait_for_release(1) assert button.wait_for_release(1)
def test_input_line_sensor(): def test_input_line_sensor():
pin = MockPin(2) pin = MockPin(2)
sensor = LineSensor(pin) with LineSensor(pin) as sensor:
pin.drive_low() # logic is inverted for line sensor pin.drive_low() # logic is inverted for line sensor
assert sensor.wait_for_line(1) assert sensor.wait_for_line(1)
assert sensor.line_detected assert sensor.line_detected
pin.drive_high() pin.drive_high()
assert sensor.wait_for_no_line(1) assert sensor.wait_for_no_line(1)
assert not sensor.line_detected assert not sensor.line_detected
def test_input_motion_sensor(): def test_input_motion_sensor():
pin = MockPin(2) pin = MockPin(2)
sensor = MotionSensor(pin) with MotionSensor(pin) as sensor:
pin.drive_high() pin.drive_high()
assert sensor.wait_for_motion(1) assert sensor.wait_for_motion(1)
assert sensor.motion_detected assert sensor.motion_detected
pin.drive_low() pin.drive_low()
assert sensor.wait_for_no_motion(1) assert sensor.wait_for_no_motion(1)
assert not sensor.motion_detected assert not sensor.motion_detected
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
def test_input_light_sensor(): def test_input_light_sensor():
pin = MockChargingPin(2) pin = MockChargingPin(2)
sensor = LightSensor(pin) with LightSensor(pin) as sensor:
pin.charge_time = 0.1 pin.charge_time = 0.1
assert sensor.wait_for_dark(1) assert sensor.wait_for_dark(1)
pin.charge_time = 0.0 pin.charge_time = 0.0
assert sensor.wait_for_light(1) assert sensor.wait_for_light(1)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
@@ -162,22 +152,22 @@ def test_input_distance_sensor():
DistanceSensor(echo_pin, trig_pin, max_distance=-1) DistanceSensor(echo_pin, trig_pin, max_distance=-1)
# normal queue len is large (because the sensor is *really* jittery) but # normal queue len is large (because the sensor is *really* jittery) but
# we want quick tests and we've got precisely controlled pins :) # we want quick tests and we've got precisely controlled pins :)
sensor = DistanceSensor(echo_pin, trig_pin, queue_len=5, max_distance=1) with DistanceSensor(echo_pin, trig_pin, queue_len=5, max_distance=1) as sensor:
assert sensor.max_distance == 1 assert sensor.max_distance == 1
assert sensor.trigger is trig_pin assert sensor.trigger is trig_pin
assert sensor.echo is echo_pin assert sensor.echo is echo_pin
assert sensor.wait_for_out_of_range(1) assert sensor.wait_for_out_of_range(1)
assert not sensor.in_range assert not sensor.in_range
assert sensor.distance == 1.0 # should be waay before max-distance so this should work assert sensor.distance == 1.0 # should be waay before max-distance so this should work
trig_pin.echo_time = 0.0 trig_pin.echo_time = 0.0
assert sensor.wait_for_in_range(1) assert sensor.wait_for_in_range(1)
assert sensor.in_range assert sensor.in_range
assert sensor.distance < sensor.threshold_distance # depending on speed of machine, may not reach 0 here assert sensor.distance < sensor.threshold_distance # depending on speed of machine, may not reach 0 here
sensor.threshold_distance = 0.1 sensor.threshold_distance = 0.1
assert sensor.threshold_distance == 0.1 assert sensor.threshold_distance == 0.1
with pytest.raises(ValueError): with pytest.raises(ValueError):
sensor.max_distance = -1 sensor.max_distance = -1
sensor.max_distance = 20 sensor.max_distance = 20
assert sensor.max_distance == 20 assert sensor.max_distance == 20
assert sensor.threshold_distance == 0.1 assert sensor.threshold_distance == 0.1

View File

@@ -25,114 +25,112 @@ def teardown_function(function):
def test_output_initial_values(): def test_output_initial_values():
pin = MockPin(2) pin = MockPin(2)
device = OutputDevice(pin, initial_value=False) with OutputDevice(pin, initial_value=False) as device:
assert pin.function == 'output' assert pin.function == 'output'
assert not pin.state assert not pin.state
device.close() with OutputDevice(pin, initial_value=True) as device:
device = OutputDevice(pin, initial_value=True) assert pin.state
assert pin.state state = pin.state
device.close() with OutputDevice(pin, initial_value=None) as device:
state = pin.state assert state == pin.state
device = OutputDevice(pin, initial_value=None)
assert state == pin.state
def test_output_write_active_high(): def test_output_write_active_high():
pin = MockPin(2) pin = MockPin(2)
device = OutputDevice(pin) with OutputDevice(pin) as device:
device.on() device.on()
assert pin.state assert pin.state
device.off() device.off()
assert not pin.state assert not pin.state
def test_output_write_active_low(): def test_output_write_active_low():
pin = MockPin(2) pin = MockPin(2)
device = OutputDevice(pin, active_high=False) with OutputDevice(pin, active_high=False) as device:
device.on() device.on()
assert not pin.state assert not pin.state
device.off() device.off()
assert pin.state assert pin.state
def test_output_write_closed(): def test_output_write_closed():
device = OutputDevice(MockPin(2)) with OutputDevice(MockPin(2)) as device:
device.close() device.close()
with pytest.raises(GPIODeviceClosed): with pytest.raises(GPIODeviceClosed):
device.on() device.on()
def test_output_write_silly(): def test_output_write_silly():
pin = MockPin(2) pin = MockPin(2)
device = OutputDevice(pin) with OutputDevice(pin) as device:
pin.function = 'input' pin.function = 'input'
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
device.on() device.on()
def test_output_value(): def test_output_value():
pin = MockPin(2) pin = MockPin(2)
device = OutputDevice(pin) with OutputDevice(pin) as device:
assert not device.value assert not device.value
assert not pin.state assert not pin.state
device.on() device.on()
assert device.value assert device.value
assert pin.state assert pin.state
device.value = False device.value = False
assert not device.value assert not device.value
assert not pin.state assert not pin.state
def test_output_digital_toggle(): def test_output_digital_toggle():
pin = MockPin(2) pin = MockPin(2)
device = DigitalOutputDevice(pin) with DigitalOutputDevice(pin) as device:
assert not device.value assert not device.value
assert not pin.state assert not pin.state
device.toggle() device.toggle()
assert device.value assert device.value
assert pin.state assert pin.state
device.toggle() device.toggle()
assert not device.value assert not device.value
assert not pin.state assert not pin.state
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
def test_output_blink_background(): def test_output_blink_background():
pin = MockPin(2) pin = MockPin(2)
device = DigitalOutputDevice(pin) with DigitalOutputDevice(pin) as device:
device.blink(0.1, 0.1, n=2) device.blink(0.1, 0.1, n=2)
device._blink_thread.join() # naughty, but ensures no arbitrary waits in the test device._blink_thread.join() # naughty, but ensures no arbitrary waits in the test
pin.assert_states_and_times([ pin.assert_states_and_times([
(0.0, False), (0.0, False),
(0.0, True), (0.0, True),
(0.1, False), (0.1, False),
(0.1, True), (0.1, True),
(0.1, False) (0.1, False)
]) ])
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
def test_output_blink_foreground(): def test_output_blink_foreground():
pin = MockPin(2) pin = MockPin(2)
device = DigitalOutputDevice(pin) with DigitalOutputDevice(pin) as device:
device.blink(0.1, 0.1, n=2, background=False) device.blink(0.1, 0.1, n=2, background=False)
pin.assert_states_and_times([ pin.assert_states_and_times([
(0.0, False), (0.0, False),
(0.0, True), (0.0, True),
(0.1, False), (0.1, False),
(0.1, True), (0.1, True),
(0.1, False) (0.1, False)
]) ])
def test_output_blink_interrupt_on(): def test_output_blink_interrupt_on():
pin = MockPin(2) pin = MockPin(2)
device = DigitalOutputDevice(pin) with DigitalOutputDevice(pin) as device:
device.blink(1, 0.1) device.blink(1, 0.1)
sleep(0.2) sleep(0.2)
device.off() # should interrupt while on device.off() # should interrupt while on
pin.assert_states([False, True, False]) pin.assert_states([False, True, False])
def test_output_blink_interrupt_off(): def test_output_blink_interrupt_off():
pin = MockPin(2) pin = MockPin(2)
device = DigitalOutputDevice(pin) with DigitalOutputDevice(pin) as device:
device.blink(0.1, 1) device.blink(0.1, 1)
sleep(0.2) sleep(0.2)
device.off() # should interrupt while off device.off() # should interrupt while off
pin.assert_states([False, True, False]) pin.assert_states([False, True, False])
def test_output_pwm_bad_initial_value(): def test_output_pwm_bad_initial_value():
with pytest.raises(ValueError): with pytest.raises(ValueError):
@@ -144,50 +142,50 @@ def test_output_pwm_not_supported():
def test_output_pwm_states(): def test_output_pwm_states():
pin = MockPWMPin(2) pin = MockPWMPin(2)
device = PWMOutputDevice(pin) with PWMOutputDevice(pin) as device:
device.value = 0.1 device.value = 0.1
device.value = 0.2 device.value = 0.2
device.value = 0.0 device.value = 0.0
pin.assert_states([0.0, 0.1, 0.2, 0.0]) pin.assert_states([0.0, 0.1, 0.2, 0.0])
def test_output_pwm_read(): def test_output_pwm_read():
pin = MockPWMPin(2) pin = MockPWMPin(2)
device = PWMOutputDevice(pin, frequency=100) with PWMOutputDevice(pin, frequency=100) as device:
assert device.frequency == 100 assert device.frequency == 100
device.value = 0.1 device.value = 0.1
assert isclose(device.value, 0.1) assert isclose(device.value, 0.1)
assert isclose(pin.state, 0.1) assert isclose(pin.state, 0.1)
assert device.is_active assert device.is_active
device.frequency = None device.frequency = None
assert not device.value assert not device.value
assert not device.is_active assert not device.is_active
assert device.frequency is None assert device.frequency is None
def test_output_pwm_write(): def test_output_pwm_write():
pin = MockPWMPin(2) pin = MockPWMPin(2)
device = PWMOutputDevice(pin) with PWMOutputDevice(pin) as device:
device.on() device.on()
device.off() device.off()
pin.assert_states([False, True, False]) pin.assert_states([False, True, False])
def test_output_pwm_toggle(): def test_output_pwm_toggle():
pin = MockPWMPin(2) pin = MockPWMPin(2)
device = PWMOutputDevice(pin) with PWMOutputDevice(pin) as device:
device.toggle() device.toggle()
device.value = 0.5 device.value = 0.5
device.value = 0.1 device.value = 0.1
device.toggle() device.toggle()
device.off() device.off()
pin.assert_states([False, True, 0.5, 0.1, 0.9, False]) pin.assert_states([False, True, 0.5, 0.1, 0.9, False])
def test_output_pwm_active_high_read(): def test_output_pwm_active_high_read():
pin = MockPWMPin(2) pin = MockPWMPin(2)
device = PWMOutputDevice(pin, active_high=False) with PWMOutputDevice(pin, active_high=False) as device:
device.value = 0.1 device.value = 0.1
assert isclose(device.value, 0.1) assert isclose(device.value, 0.1)
assert isclose(pin.state, 0.9) assert isclose(pin.state, 0.9)
device.frequency = None device.frequency = None
assert device.value assert device.value
def test_output_pwm_bad_value(): def test_output_pwm_bad_value():
with pytest.raises(ValueError): with pytest.raises(ValueError):
@@ -201,108 +199,108 @@ def test_output_pwm_write_closed():
def test_output_pwm_write_silly(): def test_output_pwm_write_silly():
pin = MockPWMPin(2) pin = MockPWMPin(2)
device = PWMOutputDevice(pin) with PWMOutputDevice(pin) as device:
pin.function = 'input' pin.function = 'input'
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
device.off() device.off()
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
def test_output_pwm_blink_background(): def test_output_pwm_blink_background():
pin = MockPWMPin(2) pin = MockPWMPin(2)
device = PWMOutputDevice(pin) with PWMOutputDevice(pin) as device:
device.blink(0.1, 0.1, n=2) device.blink(0.1, 0.1, n=2)
device._blink_thread.join() device._blink_thread.join()
pin.assert_states_and_times([ pin.assert_states_and_times([
(0.0, 0), (0.0, 0),
(0.0, 1), (0.0, 1),
(0.1, 0), (0.1, 0),
(0.1, 1), (0.1, 1),
(0.1, 0) (0.1, 0)
]) ])
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
def test_output_pwm_blink_foreground(): def test_output_pwm_blink_foreground():
pin = MockPWMPin(2) pin = MockPWMPin(2)
device = PWMOutputDevice(pin) with PWMOutputDevice(pin) as device:
device.blink(0.1, 0.1, n=2, background=False) device.blink(0.1, 0.1, n=2, background=False)
pin.assert_states_and_times([ pin.assert_states_and_times([
(0.0, 0), (0.0, 0),
(0.0, 1), (0.0, 1),
(0.1, 0), (0.1, 0),
(0.1, 1), (0.1, 1),
(0.1, 0) (0.1, 0)
]) ])
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
def test_output_pwm_fade_background(): def test_output_pwm_fade_background():
pin = MockPWMPin(2) pin = MockPWMPin(2)
device = PWMOutputDevice(pin) with PWMOutputDevice(pin) as device:
device.blink(0, 0, 0.1, 0.1, n=2) device.blink(0, 0, 0.2, 0.2, n=2)
device._blink_thread.join() device._blink_thread.join()
pin.assert_states_and_times([ pin.assert_states_and_times([
(0.0, 0), (0.0, 0),
(0.02, 0.2), (0.04, 0.2),
(0.02, 0.4), (0.04, 0.4),
(0.02, 0.6), (0.04, 0.6),
(0.02, 0.8), (0.04, 0.8),
(0.02, 1), (0.04, 1),
(0.02, 0.8), (0.04, 0.8),
(0.02, 0.6), (0.04, 0.6),
(0.02, 0.4), (0.04, 0.4),
(0.02, 0.2), (0.04, 0.2),
(0.02, 0), (0.04, 0),
(0.02, 0.2), (0.04, 0.2),
(0.02, 0.4), (0.04, 0.4),
(0.02, 0.6), (0.04, 0.6),
(0.02, 0.8), (0.04, 0.8),
(0.02, 1), (0.04, 1),
(0.02, 0.8), (0.04, 0.8),
(0.02, 0.6), (0.04, 0.6),
(0.02, 0.4), (0.04, 0.4),
(0.02, 0.2), (0.04, 0.2),
(0.02, 0), (0.04, 0),
]) ])
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
def test_output_pwm_fade_foreground(): def test_output_pwm_fade_foreground():
pin = MockPWMPin(2) pin = MockPWMPin(2)
device = PWMOutputDevice(pin) with PWMOutputDevice(pin) as device:
device.blink(0, 0, 0.1, 0.1, n=2, background=False) device.blink(0, 0, 0.2, 0.2, n=2, background=False)
pin.assert_states_and_times([ pin.assert_states_and_times([
(0.0, 0), (0.0, 0),
(0.02, 0.2), (0.04, 0.2),
(0.02, 0.4), (0.04, 0.4),
(0.02, 0.6), (0.04, 0.6),
(0.02, 0.8), (0.04, 0.8),
(0.02, 1), (0.04, 1),
(0.02, 0.8), (0.04, 0.8),
(0.02, 0.6), (0.04, 0.6),
(0.02, 0.4), (0.04, 0.4),
(0.02, 0.2), (0.04, 0.2),
(0.02, 0), (0.04, 0),
(0.02, 0.2), (0.04, 0.2),
(0.02, 0.4), (0.04, 0.4),
(0.02, 0.6), (0.04, 0.6),
(0.02, 0.8), (0.04, 0.8),
(0.02, 1), (0.04, 1),
(0.02, 0.8), (0.04, 0.8),
(0.02, 0.6), (0.04, 0.6),
(0.02, 0.4), (0.04, 0.4),
(0.02, 0.2), (0.04, 0.2),
(0.02, 0), (0.04, 0),
]) ])
def test_output_pwm_blink_interrupt(): def test_output_pwm_blink_interrupt():
pin = MockPWMPin(2) pin = MockPWMPin(2)
device = PWMOutputDevice(pin) with PWMOutputDevice(pin) as device:
device.blink(1, 0.1) device.blink(1, 0.1)
sleep(0.2) sleep(0.2)
device.off() # should interrupt while on device.off() # should interrupt while on
pin.assert_states([0, 1, 0]) pin.assert_states([0, 1, 0])
def test_rgbled_missing_pins(): def test_rgbled_missing_pins():
with pytest.raises(ValueError): with pytest.raises(ValueError):
@@ -310,116 +308,116 @@ def test_rgbled_missing_pins():
def test_rgbled_initial_value(): def test_rgbled_initial_value():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
device = RGBLED(r, g, b, initial_value=(0.1, 0.2, 0)) with RGBLED(r, g, b, initial_value=(0.1, 0.2, 0)) as device:
assert r.frequency assert r.frequency
assert g.frequency assert g.frequency
assert b.frequency assert b.frequency
assert isclose(r.state, 0.1) assert isclose(r.state, 0.1)
assert isclose(g.state, 0.2) assert isclose(g.state, 0.2)
assert isclose(b.state, 0.0) assert isclose(b.state, 0.0)
def test_rgbled_value(): def test_rgbled_value():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
device = RGBLED(r, g, b) with RGBLED(r, g, b) as device:
assert not device.is_active assert not device.is_active
assert device.value == (0, 0, 0) assert device.value == (0, 0, 0)
device.on() device.on()
assert device.is_active assert device.is_active
assert device.value == (1, 1, 1) assert device.value == (1, 1, 1)
device.off() device.off()
assert not device.is_active assert not device.is_active
assert device.value == (0, 0, 0) assert device.value == (0, 0, 0)
def test_rgbled_toggle(): def test_rgbled_toggle():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
device = RGBLED(r, g, b) with RGBLED(r, g, b) as device:
assert not device.is_active assert not device.is_active
assert device.value == (0, 0, 0) assert device.value == (0, 0, 0)
device.toggle() device.toggle()
assert device.is_active assert device.is_active
assert device.value == (1, 1, 1) assert device.value == (1, 1, 1)
device.toggle() device.toggle()
assert not device.is_active assert not device.is_active
assert device.value == (0, 0, 0) assert device.value == (0, 0, 0)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
def test_rgbled_blink_background(): def test_rgbled_blink_background():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
device = RGBLED(r, g, b) with RGBLED(r, g, b) as device:
device.blink(0.1, 0.1, n=2) device.blink(0.1, 0.1, n=2)
device._blink_thread.join() device._blink_thread.join()
expected = [ expected = [
(0.0, 0), (0.0, 0),
(0.0, 1), (0.0, 1),
(0.1, 0), (0.1, 0),
(0.1, 1), (0.1, 1),
(0.1, 0) (0.1, 0)
] ]
r.assert_states_and_times(expected) r.assert_states_and_times(expected)
g.assert_states_and_times(expected) g.assert_states_and_times(expected)
b.assert_states_and_times(expected) b.assert_states_and_times(expected)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
def test_rgbled_blink_foreground(): def test_rgbled_blink_foreground():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
device = RGBLED(r, g, b) with RGBLED(r, g, b) as device:
device.blink(0.1, 0.1, n=2, background=False) device.blink(0.1, 0.1, n=2, background=False)
expected = [ expected = [
(0.0, 0), (0.0, 0),
(0.0, 1), (0.0, 1),
(0.1, 0), (0.1, 0),
(0.1, 1), (0.1, 1),
(0.1, 0) (0.1, 0)
] ]
r.assert_states_and_times(expected) r.assert_states_and_times(expected)
g.assert_states_and_times(expected) g.assert_states_and_times(expected)
b.assert_states_and_times(expected) b.assert_states_and_times(expected)
@pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'),
reason='timing is too random on pypy') reason='timing is too random on pypy')
def test_rgbled_fade_background(): def test_rgbled_fade_background():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
device = RGBLED(r, g, b) with RGBLED(r, g, b) as device:
device.blink(0, 0, 0.1, 0.1, n=2) device.blink(0, 0, 0.2, 0.2, n=2)
device._blink_thread.join() device._blink_thread.join()
expected = [ expected = [
(0.0, 0), (0.0, 0),
(0.02, 0.2), (0.04, 0.2),
(0.02, 0.4), (0.04, 0.4),
(0.02, 0.6), (0.04, 0.6),
(0.02, 0.8), (0.04, 0.8),
(0.02, 1), (0.04, 1),
(0.02, 0.8), (0.04, 0.8),
(0.02, 0.6), (0.04, 0.6),
(0.02, 0.4), (0.04, 0.4),
(0.02, 0.2), (0.04, 0.2),
(0.02, 0), (0.04, 0),
(0.02, 0.2), (0.04, 0.2),
(0.02, 0.4), (0.04, 0.4),
(0.02, 0.6), (0.04, 0.6),
(0.02, 0.8), (0.04, 0.8),
(0.02, 1), (0.04, 1),
(0.02, 0.8), (0.04, 0.8),
(0.02, 0.6), (0.04, 0.6),
(0.02, 0.4), (0.04, 0.4),
(0.02, 0.2), (0.04, 0.2),
(0.02, 0), (0.04, 0),
] ]
r.assert_states_and_times(expected) r.assert_states_and_times(expected)
g.assert_states_and_times(expected) g.assert_states_and_times(expected)
b.assert_states_and_times(expected) b.assert_states_and_times(expected)
def test_output_rgbled_blink_interrupt(): def test_output_rgbled_blink_interrupt():
r, g, b = (MockPWMPin(i) for i in (1, 2, 3)) r, g, b = (MockPWMPin(i) for i in (1, 2, 3))
device = RGBLED(r, g, b) with RGBLED(r, g, b) as device:
device.blink(1, 0.1) device.blink(1, 0.1)
sleep(0.2) sleep(0.2)
device.off() # should interrupt while on device.off() # should interrupt while on
r.assert_states([0, 1, 0]) r.assert_states([0, 1, 0])
g.assert_states([0, 1, 0]) g.assert_states([0, 1, 0])
b.assert_states([0, 1, 0]) b.assert_states([0, 1, 0])
def test_motor_missing_pins(): def test_motor_missing_pins():
with pytest.raises(ValueError): with pytest.raises(ValueError):
@@ -428,55 +426,55 @@ def test_motor_missing_pins():
def test_motor_pins(): def test_motor_pins():
f = MockPWMPin(1) f = MockPWMPin(1)
b = MockPWMPin(2) b = MockPWMPin(2)
device = Motor(f, b) with Motor(f, b) as device:
assert device.forward_device.pin is f assert device.forward_device.pin is f
assert device.backward_device.pin is b assert device.backward_device.pin is b
def test_motor_close(): def test_motor_close():
f = MockPWMPin(1) f = MockPWMPin(1)
b = MockPWMPin(2) b = MockPWMPin(2)
device = Motor(f, b) with Motor(f, b) as device:
device.close() device.close()
assert device.closed assert device.closed
assert device.forward_device.pin is None assert device.forward_device.pin is None
assert device.backward_device.pin is None assert device.backward_device.pin is None
def test_motor_value(): def test_motor_value():
f = MockPWMPin(1) f = MockPWMPin(1)
b = MockPWMPin(2) b = MockPWMPin(2)
device = Motor(f, b) with Motor(f, b) as device:
device.value = -1 device.value = -1
assert device.is_active assert device.is_active
assert device.value == -1 assert device.value == -1
assert b.state == 1 and f.state == 0 assert b.state == 1 and f.state == 0
device.value = 1 device.value = 1
assert device.is_active assert device.is_active
assert device.value == 1 assert device.value == 1
assert b.state == 0 and f.state == 1 assert b.state == 0 and f.state == 1
device.value = 0.5 device.value = 0.5
assert device.is_active assert device.is_active
assert device.value == 0.5 assert device.value == 0.5
assert b.state == 0 and f.state == 0.5 assert b.state == 0 and f.state == 0.5
device.value = 0 device.value = 0
assert not device.is_active assert not device.is_active
assert not device.value assert not device.value
assert b.state == 0 and f.state == 0 assert b.state == 0 and f.state == 0
def test_motor_bad_value(): def test_motor_bad_value():
f = MockPWMPin(1) f = MockPWMPin(1)
b = MockPWMPin(2) b = MockPWMPin(2)
device = Motor(f, b) with Motor(f, b) as device:
with pytest.raises(ValueError): with pytest.raises(ValueError):
device.value = 2 device.value = 2
def test_motor_reverse(): def test_motor_reverse():
f = MockPWMPin(1) f = MockPWMPin(1)
b = MockPWMPin(2) b = MockPWMPin(2)
device = Motor(f, b) with Motor(f, b) as device:
device.forward() device.forward()
assert device.value == 1 assert device.value == 1
assert b.state == 0 and f.state == 1 assert b.state == 0 and f.state == 1
device.reverse() device.reverse()
assert device.value == -1 assert device.value == -1
assert b.state == 1 and f.state == 0 assert b.state == 1 and f.state == 0

View File

@@ -11,7 +11,7 @@ import pytest
from math import sin, cos, radians from math import sin, cos, radians
from time import time from time import time
from gpiozero import * from gpiozero.tools import *
try: try:
from math import isclose from math import isclose
except ImportError: except ImportError: