mirror of
				https://github.com/KevinMidboe/python-gpiozero.git
				synced 2025-10-29 17:50:37 +00:00 
			
		
		
		
	Fix #204 and start readying the release
Also re-numbers energenie sockets 1-4 (as noted by @bennuttall in comments to #239), and adds several "real pins" tests and board tests. The bad-PWM stuff is currently disabled as it causes segfaults when running the tests and I can't seem to trace the cause at the moment. Finally, I've tweaked the deb config to suggest gpiozero, removed spidev as a mandatory dep (which'll fix installs on wheezy for py3), and there's some more miscellaneous last-minute stuff here that I can't recall...
This commit is contained in:
		
							
								
								
									
										6
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							| @@ -11,7 +11,8 @@ X-Python3-Version: >= 3.2 | |||||||
| Package: python-gpiozero | Package: python-gpiozero | ||||||
| Architecture: all | Architecture: all | ||||||
| Section: python | Section: python | ||||||
| Depends: ${misc:Depends}, ${python:Depends}, python-rpi.gpio, python-spidev | Depends: ${misc:Depends}, ${python:Depends}, python-rpi.gpio | ||||||
|  | Suggests: python-spidev, python-gpiozero-docs | ||||||
| Description: Simple API for controlling devices attached to the GPIO pins. | Description: Simple API for controlling devices attached to the GPIO pins. | ||||||
|  gpiozero builds on RPi.GPIO to provide a set of classes designed to simplify |  gpiozero builds on RPi.GPIO to provide a set of classes designed to simplify | ||||||
|  interaction with devices connected to the GPIO pins, from simple buttons and |  interaction with devices connected to the GPIO pins, from simple buttons and | ||||||
| @@ -23,7 +24,8 @@ Description: Simple API for controlling devices attached to the GPIO pins. | |||||||
| Package: python3-gpiozero | Package: python3-gpiozero | ||||||
| Architecture: all | Architecture: all | ||||||
| Section: python | Section: python | ||||||
| Depends: ${misc:Depends}, ${python3:Depends}, python3-rpi.gpio, python3-spidev | Depends: ${misc:Depends}, ${python3:Depends}, python3-rpi.gpio | ||||||
|  | Suggests: python3-spidev, python-gpiozero-docs | ||||||
| Description: Simple API for controlling devices attached to the GPIO pins. | Description: Simple API for controlling devices attached to the GPIO pins. | ||||||
|  gpiozero builds on RPi.GPIO to provide a set of classes designed to simplify |  gpiozero builds on RPi.GPIO to provide a set of classes designed to simplify | ||||||
|  interaction with devices connected to the GPIO pins, from simple buttons and |  interaction with devices connected to the GPIO pins, from simple buttons and | ||||||
|   | |||||||
| @@ -99,3 +99,10 @@ CamJam #3 Kit Robot | |||||||
|     :inherited-members: |     :inherited-members: | ||||||
|     :members: |     :members: | ||||||
|  |  | ||||||
|  | Energenie | ||||||
|  | ========= | ||||||
|  |  | ||||||
|  | .. autoclass:: Energenie | ||||||
|  |     :inherited-members: | ||||||
|  |     :members: | ||||||
|  |  | ||||||
|   | |||||||
| @@ -70,6 +70,14 @@ to utilize pins that are part of IO extender chips. For example:: | |||||||
|     It is potentially subject to change in future versions. We welcome any |     It is potentially subject to change in future versions. We welcome any | ||||||
|     comments from testers! |     comments from testers! | ||||||
|  |  | ||||||
|  | .. warning:: | ||||||
|  |  | ||||||
|  |     The astute and mischievious reader may note that it is possible to mix pin | ||||||
|  |     implementations, e.g. using ``RPiGPIOPin`` for one pin, and ``NativePin`` | ||||||
|  |     for another. This is unsupported, and if it results in your script | ||||||
|  |     crashing, your components failing, or your Raspberry Pi turning into an | ||||||
|  |     actual raspberry pie, you have only yourself to blame. | ||||||
|  |  | ||||||
|  |  | ||||||
| RPiGPIOPin | RPiGPIOPin | ||||||
| ========== | ========== | ||||||
|   | |||||||
| @@ -5,6 +5,50 @@ Changelog | |||||||
| .. currentmodule:: gpiozero | .. currentmodule:: gpiozero | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Release 1.2.0 (2016-04-??) | ||||||
|  | ========================== | ||||||
|  |  | ||||||
|  | * Added :class:`Energenie` class for controlling Energenie plugs (`#69`_) | ||||||
|  | * Added :class:`LineSensor` class for single line-sensors (`#109`_) | ||||||
|  | * Added :class:`DistanceSensor` class for HC-SR04 ultra-sonic sensors (`#114`_) | ||||||
|  | * Added :class:`SnowPi` class for the Ryanteck Snow-pi board (`#130`_) | ||||||
|  | * Fixed issues with installing GPIO Zero for python 3 on Raspbian Wheezy | ||||||
|  |   releases (`#140`_) | ||||||
|  | * Added support for lots of ADC chips (MCP3xxx family) (`#162`_) - many thanks | ||||||
|  |   to pcopa and lurch! | ||||||
|  | * Added support for pigpiod as a pin implementation with | ||||||
|  |   :class:`~gpiozero.pins.pigpiod.PiGPIOPin` (`#180`_) | ||||||
|  | * Many refinements to the base classes mean more consistency in composite | ||||||
|  |   devices and several bugs squashed (`#164`_, `#175`_, `#182`_, `#189`_, | ||||||
|  |   `#193`_, `#229`_) | ||||||
|  | * GPIO Zero is now aware of what sort of Pi it's running on via :func:`pi_info` | ||||||
|  |   and has a fairly extensive database of Pi information which it uses to | ||||||
|  |   determine when users request impossible things (like pull-down on a pin with | ||||||
|  |   a physical pull-up resistor) (`#222`_) | ||||||
|  | * The source/values system was enhanced to ensure normal usage doesn't stress | ||||||
|  |   the CPU and lots of utilities were added (`#181`_, `#251`_) | ||||||
|  |  | ||||||
|  | And I'll just add a note of thanks to the many people in the community who | ||||||
|  | contributed to this release: we've had some great PRs, suggestions, and bug | ||||||
|  | reports in this version - keep 'em coming! | ||||||
|  |  | ||||||
|  | .. _#69: https://github.com/RPi-Distro/python-gpiozero/issues/69 | ||||||
|  | .. _#109: https://github.com/RPi-Distro/python-gpiozero/issues/109 | ||||||
|  | .. _#114: https://github.com/RPi-Distro/python-gpiozero/issues/114 | ||||||
|  | .. _#130: https://github.com/RPi-Distro/python-gpiozero/issues/130 | ||||||
|  | .. _#140: https://github.com/RPi-Distro/python-gpiozero/issues/140 | ||||||
|  | .. _#162: https://github.com/RPi-Distro/python-gpiozero/issues/162 | ||||||
|  | .. _#164: https://github.com/RPi-Distro/python-gpiozero/issues/164 | ||||||
|  | .. _#175: https://github.com/RPi-Distro/python-gpiozero/issues/175 | ||||||
|  | .. _#180: https://github.com/RPi-Distro/python-gpiozero/issues/180 | ||||||
|  | .. _#181: https://github.com/RPi-Distro/python-gpiozero/issues/181 | ||||||
|  | .. _#182: https://github.com/RPi-Distro/python-gpiozero/issues/182 | ||||||
|  | .. _#189: https://github.com/RPi-Distro/python-gpiozero/issues/189 | ||||||
|  | .. _#193: https://github.com/RPi-Distro/python-gpiozero/issues/193 | ||||||
|  | .. _#222: https://github.com/RPi-Distro/python-gpiozero/issues/222 | ||||||
|  | .. _#229: https://github.com/RPi-Distro/python-gpiozero/issues/229 | ||||||
|  | .. _#251: https://github.com/RPi-Distro/python-gpiozero/issues/251 | ||||||
|  |  | ||||||
| Release 1.1.0 (2016-02-08) | Release 1.1.0 (2016-02-08) | ||||||
| ========================== | ========================== | ||||||
|  |  | ||||||
|   | |||||||
| @@ -539,13 +539,15 @@ class SnowPi(LEDBoard): | |||||||
|                     _order=('top', 'middle', 'bottom')), |                     _order=('top', 'middle', 'bottom')), | ||||||
|                 right=LEDBoard( |                 right=LEDBoard( | ||||||
|                     top=7, middle=8, bottom=9, pwm=pwm, |                     top=7, middle=8, bottom=9, pwm=pwm, | ||||||
|                     _order=('top', 'middle', 'bottom')) |                     _order=('top', 'middle', 'bottom')), | ||||||
|  |                 _order=('left', 'right') | ||||||
|                 ), |                 ), | ||||||
|             eyes=LEDBoard( |             eyes=LEDBoard( | ||||||
|                 left=23, right=24, pwm=pwm, |                 left=23, right=24, pwm=pwm, | ||||||
|                 _order=('left', 'right') |                 _order=('left', 'right') | ||||||
|                 ), |                 ), | ||||||
|             nose=25, pwm=pwm |             nose=25, pwm=pwm, | ||||||
|  |             _order=('eyes', 'nose', 'arms') | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -629,9 +631,6 @@ class TrafficHat(TrafficLightsBuzzer): | |||||||
|         ) |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
| RobotTuple = namedtuple('RobotTuple', ('left', 'right')) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class Robot(SourceMixin, CompositeDevice): | class Robot(SourceMixin, CompositeDevice): | ||||||
|     """ |     """ | ||||||
|     Extends :class:`CompositeDevice` to represent a generic dual-motor robot. |     Extends :class:`CompositeDevice` to represent a generic dual-motor robot. | ||||||
| @@ -657,48 +656,10 @@ class Robot(SourceMixin, CompositeDevice): | |||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     def __init__(self, left=None, right=None): |     def __init__(self, left=None, right=None): | ||||||
|         if not all([left, right]): |         super(Robot, self).__init__( | ||||||
|             raise GPIOPinMissing( |                 left_motor=Motor(*left), | ||||||
|                 'left and right motor pins must be provided' |                 right_motor=Motor(*right), | ||||||
|             ) |                 _order=('left_motor', 'right_motor')) | ||||||
|         super(Robot, self).__init__() |  | ||||||
|         self._left = Motor(*left) |  | ||||||
|         self._right = Motor(*right) |  | ||||||
|  |  | ||||||
|     def close(self): |  | ||||||
|         self._left.close() |  | ||||||
|         self._right.close() |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def closed(self): |  | ||||||
|         return self._left.closed and self._right.closed |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def left_motor(self): |  | ||||||
|         """ |  | ||||||
|         Returns the `Motor` device representing the robot's left motor. |  | ||||||
|         """ |  | ||||||
|         return self._left |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def right_motor(self): |  | ||||||
|         """ |  | ||||||
|         Returns the `Motor` device representing the robot's right motor. |  | ||||||
|         """ |  | ||||||
|         return self._right |  | ||||||
|  |  | ||||||
|     @property |  | ||||||
|     def value(self): |  | ||||||
|         """ |  | ||||||
|         Returns a tuple of two floating point values (-1 to 1) representing the |  | ||||||
|         speeds of the robot's two motors (left and right). This property can |  | ||||||
|         also be set to alter the speed of both motors. |  | ||||||
|         """ |  | ||||||
|         return RobotTuple(self._left.value, self._right.value) |  | ||||||
|  |  | ||||||
|     @value.setter |  | ||||||
|     def value(self, value): |  | ||||||
|         self._left.value, self._right.value = value |  | ||||||
|  |  | ||||||
|     def forward(self, speed=1): |     def forward(self, speed=1): | ||||||
|         """ |         """ | ||||||
| @@ -708,8 +669,8 @@ class Robot(SourceMixin, CompositeDevice): | |||||||
|             Speed at which to drive the motors, as a value between 0 (stopped) |             Speed at which to drive the motors, as a value between 0 (stopped) | ||||||
|             and 1 (full speed). The default is 1. |             and 1 (full speed). The default is 1. | ||||||
|         """ |         """ | ||||||
|         self._left.forward(speed) |         self.left_motor.forward(speed) | ||||||
|         self._right.forward(speed) |         self.right_motor.forward(speed) | ||||||
|  |  | ||||||
|     def backward(self, speed=1): |     def backward(self, speed=1): | ||||||
|         """ |         """ | ||||||
| @@ -719,8 +680,8 @@ class Robot(SourceMixin, CompositeDevice): | |||||||
|             Speed at which to drive the motors, as a value between 0 (stopped) |             Speed at which to drive the motors, as a value between 0 (stopped) | ||||||
|             and 1 (full speed). The default is 1. |             and 1 (full speed). The default is 1. | ||||||
|         """ |         """ | ||||||
|         self._left.backward(speed) |         self.left_motor.backward(speed) | ||||||
|         self._right.backward(speed) |         self.right_motor.backward(speed) | ||||||
|  |  | ||||||
|     def left(self, speed=1): |     def left(self, speed=1): | ||||||
|         """ |         """ | ||||||
| @@ -731,8 +692,8 @@ class Robot(SourceMixin, CompositeDevice): | |||||||
|             Speed at which to drive the motors, as a value between 0 (stopped) |             Speed at which to drive the motors, as a value between 0 (stopped) | ||||||
|             and 1 (full speed). The default is 1. |             and 1 (full speed). The default is 1. | ||||||
|         """ |         """ | ||||||
|         self._right.forward(speed) |         self.right_motor.forward(speed) | ||||||
|         self._left.backward(speed) |         self.left_motor.backward(speed) | ||||||
|  |  | ||||||
|     def right(self, speed=1): |     def right(self, speed=1): | ||||||
|         """ |         """ | ||||||
| @@ -743,8 +704,8 @@ class Robot(SourceMixin, CompositeDevice): | |||||||
|             Speed at which to drive the motors, as a value between 0 (stopped) |             Speed at which to drive the motors, as a value between 0 (stopped) | ||||||
|             and 1 (full speed). The default is 1. |             and 1 (full speed). The default is 1. | ||||||
|         """ |         """ | ||||||
|         self._left.forward(speed) |         self.left_motor.forward(speed) | ||||||
|         self._right.backward(speed) |         self.right_motor.backward(speed) | ||||||
|  |  | ||||||
|     def reverse(self): |     def reverse(self): | ||||||
|         """ |         """ | ||||||
| @@ -753,15 +714,15 @@ class Robot(SourceMixin, CompositeDevice): | |||||||
|         robot is turning left at half-speed, it will turn right at half-speed. |         robot is turning left at half-speed, it will turn right at half-speed. | ||||||
|         If the robot is currently stopped it will remain stopped. |         If the robot is currently stopped it will remain stopped. | ||||||
|         """ |         """ | ||||||
|         self._left.value = -self._left.value |         self.left_motor.reverse() | ||||||
|         self._right.value = -self._right.value |         self.right_motor.reverse() | ||||||
|  |  | ||||||
|     def stop(self): |     def stop(self): | ||||||
|         """ |         """ | ||||||
|         Stop the robot. |         Stop the robot. | ||||||
|         """ |         """ | ||||||
|         self._left.stop() |         self.left_motor.stop() | ||||||
|         self._right.stop() |         self.right_motor.stop() | ||||||
|  |  | ||||||
|  |  | ||||||
| class RyanteckRobot(Robot): | class RyanteckRobot(Robot): | ||||||
| @@ -779,7 +740,7 @@ class RyanteckRobot(Robot): | |||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         super(RyanteckRobot, self).__init__(left=(17, 18), right=(22, 23)) |         super(RyanteckRobot, self).__init__((17, 18), (22, 23)) | ||||||
|  |  | ||||||
|  |  | ||||||
| class CamJamKitRobot(Robot): | class CamJamKitRobot(Robot): | ||||||
| @@ -799,7 +760,7 @@ class CamJamKitRobot(Robot): | |||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     def __init__(self): |     def __init__(self): | ||||||
|         super(CamJamKitRobot, self).__init__(left=(9, 10), right=(7, 8)) |         super(CamJamKitRobot, self).__init__((9, 10), (7, 8)) | ||||||
|  |  | ||||||
|  |  | ||||||
| class _EnergenieMaster(SharedMixin, CompositeOutputDevice): | class _EnergenieMaster(SharedMixin, CompositeOutputDevice): | ||||||
| @@ -807,7 +768,8 @@ class _EnergenieMaster(SharedMixin, CompositeOutputDevice): | |||||||
|         self._lock = Lock() |         self._lock = Lock() | ||||||
|         super(_EnergenieMaster, self).__init__( |         super(_EnergenieMaster, self).__init__( | ||||||
|                 *(OutputDevice(pin) for pin in (17, 22, 23, 27)), |                 *(OutputDevice(pin) for pin in (17, 22, 23, 27)), | ||||||
|                 mode=OutputDevice(24), enable=OutputDevice(25)) |                 mode=OutputDevice(24), enable=OutputDevice(25), | ||||||
|  |                 _order=('mode', 'enable')) | ||||||
|  |  | ||||||
|     def close(self): |     def close(self): | ||||||
|         if self._lock: |         if self._lock: | ||||||
| @@ -823,7 +785,7 @@ class _EnergenieMaster(SharedMixin, CompositeOutputDevice): | |||||||
|     def transmit(self, socket, enable): |     def transmit(self, socket, enable): | ||||||
|         with self._lock: |         with self._lock: | ||||||
|             try: |             try: | ||||||
|                 code = (8 * bool(enable)) + (7 - socket) |                 code = (8 * bool(enable)) + (8 - socket) | ||||||
|                 for bit in self.all[:4]: |                 for bit in self.all[:4]: | ||||||
|                     bit.value = (code & 1) |                     bit.value = (code & 1) | ||||||
|                     code >>= 1 |                     code >>= 1 | ||||||
| @@ -844,12 +806,12 @@ class Energenie(SourceMixin, Device): | |||||||
|  |  | ||||||
|         from gpiozero import Energenie |         from gpiozero import Energenie | ||||||
|  |  | ||||||
|         lamp = Energenie(0) |         lamp = Energenie(1) | ||||||
|         lamp.on() |         lamp.on() | ||||||
|  |  | ||||||
|     :param int socket: |     :param int socket: | ||||||
|         Which socket this instance should control. This is an integer number |         Which socket this instance should control. This is an integer number | ||||||
|         between 0 and 3. |         between 1 and 4. | ||||||
|  |  | ||||||
|     :param bool initial_value: |     :param bool initial_value: | ||||||
|         The initial state of the socket. As Energenie sockets provide no |         The initial state of the socket. As Energenie sockets provide no | ||||||
| @@ -863,8 +825,8 @@ class Energenie(SourceMixin, Device): | |||||||
|     def __init__(self, socket=None, initial_value=False): |     def __init__(self, socket=None, initial_value=False): | ||||||
|         if socket is None: |         if socket is None: | ||||||
|             raise EnergenieSocketMissing('socket number must be provided') |             raise EnergenieSocketMissing('socket number must be provided') | ||||||
|         if not (0 <= socket < 4): |         if not (1 <= socket <= 4): | ||||||
|             raise EnergenieBadSocket('socket number must be between 0 and 3') |             raise EnergenieBadSocket('socket number must be between 1 and 4') | ||||||
|         super(Energenie, self).__init__() |         super(Energenie, self).__init__() | ||||||
|         self._socket = socket |         self._socket = socket | ||||||
|         self._master = _EnergenieMaster() |         self._master = _EnergenieMaster() | ||||||
|   | |||||||
| @@ -41,6 +41,7 @@ class OutputDevice(SourceMixin, GPIODevice): | |||||||
|     """ |     """ | ||||||
|     def __init__(self, pin=None, active_high=True, initial_value=False): |     def __init__(self, pin=None, active_high=True, initial_value=False): | ||||||
|         super(OutputDevice, self).__init__(pin) |         super(OutputDevice, self).__init__(pin) | ||||||
|  |         self._lock = Lock() | ||||||
|         self.active_high = active_high |         self.active_high = active_high | ||||||
|         if initial_value is None: |         if initial_value is None: | ||||||
|             self.pin.function = 'output' |             self.pin.function = 'output' | ||||||
| @@ -70,6 +71,17 @@ class OutputDevice(SourceMixin, GPIODevice): | |||||||
|         """ |         """ | ||||||
|         self._write(False) |         self._write(False) | ||||||
|  |  | ||||||
|  |     def toggle(self): | ||||||
|  |         """ | ||||||
|  |         Reverse the state of the device. If it's on, turn it off; if it's off, | ||||||
|  |         turn it on. | ||||||
|  |         """ | ||||||
|  |         with self._lock: | ||||||
|  |             if self.is_active: | ||||||
|  |                 self.off() | ||||||
|  |             else: | ||||||
|  |                 self.on() | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def value(self): |     def value(self): | ||||||
|         """ |         """ | ||||||
| @@ -121,7 +133,6 @@ class DigitalOutputDevice(OutputDevice): | |||||||
|     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 | ||||||
|         super(DigitalOutputDevice, self).__init__(pin, active_high, initial_value) |         super(DigitalOutputDevice, self).__init__(pin, active_high, initial_value) | ||||||
|         self._lock = Lock() |  | ||||||
|         self._controller = None |         self._controller = None | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
| @@ -145,17 +156,6 @@ class DigitalOutputDevice(OutputDevice): | |||||||
|         self._stop_blink() |         self._stop_blink() | ||||||
|         self._write(False) |         self._write(False) | ||||||
|  |  | ||||||
|     def toggle(self): |  | ||||||
|         """ |  | ||||||
|         Reverse the state of the device. If it's on, turn it off; if it's off, |  | ||||||
|         turn it on. |  | ||||||
|         """ |  | ||||||
|         with self._lock: |  | ||||||
|             if self.is_active: |  | ||||||
|                 self.off() |  | ||||||
|             else: |  | ||||||
|                 self.on() |  | ||||||
|  |  | ||||||
|     def blink(self, on_time=1, off_time=1, n=None, background=True): |     def blink(self, on_time=1, off_time=1, n=None, background=True): | ||||||
|         """ |         """ | ||||||
|         Make the device turn on and off repeatedly. |         Make the device turn on and off repeatedly. | ||||||
| @@ -757,7 +757,8 @@ class Motor(SourceMixin, CompositeDevice): | |||||||
|             ) |             ) | ||||||
|         super(Motor, self).__init__( |         super(Motor, self).__init__( | ||||||
|                 forward_device=PWMOutputDevice(forward), |                 forward_device=PWMOutputDevice(forward), | ||||||
|                 backward_device=PWMOutputDevice(backward)) |                 backward_device=PWMOutputDevice(backward), | ||||||
|  |                 _order=('forward_device', 'backward_device')) | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def value(self): |     def value(self): | ||||||
|   | |||||||
| @@ -7,14 +7,450 @@ from __future__ import ( | |||||||
| str = type('') | str = type('') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | import sys | ||||||
| import pytest | import pytest | ||||||
|  | from time import sleep | ||||||
|  |  | ||||||
| from gpiozero.pins.mock import MockPin | from gpiozero.pins.mock import MockPin, MockPWMPin | ||||||
| from gpiozero import * | from gpiozero import * | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def setup_function(function): | ||||||
|  |     import gpiozero.devices | ||||||
|  |     # dirty, but it does the job | ||||||
|  |     if function.__name__ in ('test_robot', 'test_ryanteck_robot', 'test_camjam_kit_robot'): | ||||||
|  |         gpiozero.devices.DefaultPin = MockPWMPin | ||||||
|  |     else: | ||||||
|  |         gpiozero.devices.DefaultPin = MockPin | ||||||
|  |  | ||||||
| def teardown_function(function): | def teardown_function(function): | ||||||
|     MockPin.clear_pins() |     MockPin.clear_pins() | ||||||
|  |  | ||||||
| # TODO boards tests! |  | ||||||
|  | def test_composite_output_on_off(): | ||||||
|  |     pin1 = MockPin(2) | ||||||
|  |     pin2 = MockPin(3) | ||||||
|  |     pin3 = MockPin(4) | ||||||
|  |     device = CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) | ||||||
|  |     device.on() | ||||||
|  |     assert all((pin1.state, pin2.state, pin3.state)) | ||||||
|  |     device.off() | ||||||
|  |     assert not any((pin1.state, pin2.state, pin3.state)) | ||||||
|  |  | ||||||
|  | def test_composite_output_toggle(): | ||||||
|  |     pin1 = MockPin(2) | ||||||
|  |     pin2 = MockPin(3) | ||||||
|  |     pin3 = MockPin(4) | ||||||
|  |     device = CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) | ||||||
|  |     device.toggle() | ||||||
|  |     assert all((pin1.state, pin2.state, pin3.state)) | ||||||
|  |     device[0].off() | ||||||
|  |     device.toggle() | ||||||
|  |     assert pin1.state | ||||||
|  |     assert not pin2.state | ||||||
|  |     assert not pin3.state | ||||||
|  |  | ||||||
|  | def test_composite_output_value(): | ||||||
|  |     pin1 = MockPin(2) | ||||||
|  |     pin2 = MockPin(3) | ||||||
|  |     pin3 = MockPin(4) | ||||||
|  |     device = CompositeOutputDevice(OutputDevice(pin1), OutputDevice(pin2), foo=OutputDevice(pin3)) | ||||||
|  |     assert device.value == (0, 0, 0) | ||||||
|  |     device.toggle() | ||||||
|  |     assert device.value == (1, 1, 1) | ||||||
|  |     device.value = (1, 0, 1) | ||||||
|  |     assert device[0].is_active | ||||||
|  |     assert not device[1].is_active | ||||||
|  |     assert device[2].is_active | ||||||
|  |  | ||||||
|  | def test_led_board_on_off(): | ||||||
|  |     pin1 = MockPin(2) | ||||||
|  |     pin2 = MockPin(3) | ||||||
|  |     pin3 = MockPin(4) | ||||||
|  |     board = LEDBoard(pin1, pin2, foo=pin3) | ||||||
|  |     assert isinstance(board[0], LED) | ||||||
|  |     assert isinstance(board[1], LED) | ||||||
|  |     assert isinstance(board[2], LED) | ||||||
|  |     board.on() | ||||||
|  |     assert all((pin1.state, pin2.state, pin3.state)) | ||||||
|  |     board.off() | ||||||
|  |     assert not any((pin1.state, pin2.state, pin3.state)) | ||||||
|  |     board[0].on() | ||||||
|  |     assert board.value == (1, 0, 0) | ||||||
|  |     assert pin1.state | ||||||
|  |     assert not pin2.state | ||||||
|  |     assert not pin3.state | ||||||
|  |     board.toggle() | ||||||
|  |     assert board.value == (0, 1, 1) | ||||||
|  |     assert not pin1.state | ||||||
|  |     assert pin2.state | ||||||
|  |     assert pin3.state | ||||||
|  |  | ||||||
|  | def test_led_board_nested(): | ||||||
|  |     pin1 = MockPin(2) | ||||||
|  |     pin2 = MockPin(3) | ||||||
|  |     pin3 = MockPin(4) | ||||||
|  |     board = LEDBoard(pin1, LEDBoard(pin2, pin3)) | ||||||
|  |     assert list(led.pin for led in board.leds) == [pin1, pin2, pin3] | ||||||
|  |     assert board.value == (0, (0, 0)) | ||||||
|  |     board.value = (1, (0, 1)) | ||||||
|  |     assert pin1.state | ||||||
|  |     assert not pin2.state | ||||||
|  |     assert pin3.state | ||||||
|  |  | ||||||
|  | def test_led_board_bad_blink(): | ||||||
|  |     pin1 = MockPin(2) | ||||||
|  |     pin2 = MockPin(3) | ||||||
|  |     pin3 = MockPin(4) | ||||||
|  |     board = LEDBoard(pin1, LEDBoard(pin2, pin3)) | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         board.blink(fade_in_time=1, fade_out_time=1) | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         board.blink(fade_out_time=1) | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         board.pulse() | ||||||
|  |  | ||||||
|  | @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), | ||||||
|  |                     reason='timing is too random on pypy') | ||||||
|  | def test_led_board_blink_background(): | ||||||
|  |     pin1 = MockPin(2) | ||||||
|  |     pin2 = MockPin(3) | ||||||
|  |     pin3 = MockPin(4) | ||||||
|  |     board = LEDBoard(pin1, LEDBoard(pin2, pin3)) | ||||||
|  |     board.blink(0.1, 0.1, n=2) | ||||||
|  |     board._blink_thread.join() # naughty, but ensures no arbitrary waits in the test | ||||||
|  |     test = [ | ||||||
|  |         (0.0, False), | ||||||
|  |         (0.0, True), | ||||||
|  |         (0.1, False), | ||||||
|  |         (0.1, True), | ||||||
|  |         (0.1, False) | ||||||
|  |         ] | ||||||
|  |     pin1.assert_states_and_times(test) | ||||||
|  |     pin2.assert_states_and_times(test) | ||||||
|  |     pin3.assert_states_and_times(test) | ||||||
|  |  | ||||||
|  | @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), | ||||||
|  |                     reason='timing is too random on pypy') | ||||||
|  | def test_led_board_blink_foreground(): | ||||||
|  |     pin1 = MockPin(2) | ||||||
|  |     pin2 = MockPin(3) | ||||||
|  |     pin3 = MockPin(4) | ||||||
|  |     board = LEDBoard(pin1, LEDBoard(pin2, pin3)) | ||||||
|  |     board.blink(0.1, 0.1, n=2, background=False) | ||||||
|  |     test = [ | ||||||
|  |         (0.0, False), | ||||||
|  |         (0.0, True), | ||||||
|  |         (0.1, False), | ||||||
|  |         (0.1, True), | ||||||
|  |         (0.1, False) | ||||||
|  |         ] | ||||||
|  |     pin1.assert_states_and_times(test) | ||||||
|  |     pin2.assert_states_and_times(test) | ||||||
|  |     pin3.assert_states_and_times(test) | ||||||
|  |  | ||||||
|  | @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), | ||||||
|  |                     reason='timing is too random on pypy') | ||||||
|  | def test_led_board_blink_control(): | ||||||
|  |     pin1 = MockPin(2) | ||||||
|  |     pin2 = MockPin(3) | ||||||
|  |     pin3 = MockPin(4) | ||||||
|  |     board = LEDBoard(pin1, LEDBoard(pin2, pin3)) | ||||||
|  |     board.blink(0.1, 0.1, n=2) | ||||||
|  |     # make sure the blink thread's started | ||||||
|  |     while not board._blink_leds: | ||||||
|  |         sleep(0.00001) | ||||||
|  |     board[1][0].off() # immediately take over the second LED | ||||||
|  |     board._blink_thread.join() # naughty, but ensures no arbitrary waits in the test | ||||||
|  |     test = [ | ||||||
|  |         (0.0, False), | ||||||
|  |         (0.0, True), | ||||||
|  |         (0.1, False), | ||||||
|  |         (0.1, True), | ||||||
|  |         (0.1, False) | ||||||
|  |         ] | ||||||
|  |     pin1.assert_states_and_times(test) | ||||||
|  |     pin3.assert_states_and_times(test) | ||||||
|  |     print(pin2.states) | ||||||
|  |     pin2.assert_states_and_times([(0.0, False), (0.0, True), (0.0, False)]) | ||||||
|  |  | ||||||
|  | @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), | ||||||
|  |                     reason='timing is too random on pypy') | ||||||
|  | def test_led_board_blink_take_over(): | ||||||
|  |     pin1 = MockPin(2) | ||||||
|  |     pin2 = MockPin(3) | ||||||
|  |     pin3 = MockPin(4) | ||||||
|  |     board = LEDBoard(pin1, LEDBoard(pin2, pin3)) | ||||||
|  |     board[1].blink(0.1, 0.1, n=2) | ||||||
|  |     board.blink(0.1, 0.1, n=2) # immediately take over blinking | ||||||
|  |     board[1]._blink_thread.join() | ||||||
|  |     board._blink_thread.join() | ||||||
|  |     test = [ | ||||||
|  |         (0.0, False), | ||||||
|  |         (0.0, True), | ||||||
|  |         (0.1, False), | ||||||
|  |         (0.1, True), | ||||||
|  |         (0.1, False) | ||||||
|  |         ] | ||||||
|  |     pin1.assert_states_and_times(test) | ||||||
|  |     pin2.assert_states_and_times(test) | ||||||
|  |     pin3.assert_states_and_times(test) | ||||||
|  |  | ||||||
|  | def test_led_board_blink_control_all(): | ||||||
|  |     pin1 = MockPin(2) | ||||||
|  |     pin2 = MockPin(3) | ||||||
|  |     pin3 = MockPin(4) | ||||||
|  |     board = LEDBoard(pin1, LEDBoard(pin2, pin3)) | ||||||
|  |     board.blink(0.1, 0.1, n=2) | ||||||
|  |     # make sure the blink thread's started | ||||||
|  |     while not board._blink_leds: | ||||||
|  |         sleep(0.00001) | ||||||
|  |     board[0].off() # immediately take over all LEDs | ||||||
|  |     board[1][0].off() | ||||||
|  |     board[1][1].off() | ||||||
|  |     board._blink_thread.join() # blink should terminate here anyway | ||||||
|  |     test = [ | ||||||
|  |         (0.0, False), | ||||||
|  |         (0.0, True), | ||||||
|  |         (0.0, False), | ||||||
|  |         ] | ||||||
|  |     pin1.assert_states_and_times(test) | ||||||
|  |     pin2.assert_states_and_times(test) | ||||||
|  |     pin3.assert_states_and_times(test) | ||||||
|  |  | ||||||
|  | def test_led_board_blink_interrupt_on(): | ||||||
|  |     pin1 = MockPin(2) | ||||||
|  |     pin2 = MockPin(3) | ||||||
|  |     pin3 = MockPin(4) | ||||||
|  |     board = LEDBoard(pin1, LEDBoard(pin2, pin3)) | ||||||
|  |     board.blink(1, 0.1) | ||||||
|  |     sleep(0.2) | ||||||
|  |     board.off() # should interrupt while on | ||||||
|  |     pin1.assert_states([False, True, False]) | ||||||
|  |     pin2.assert_states([False, True, False]) | ||||||
|  |     pin3.assert_states([False, True, False]) | ||||||
|  |  | ||||||
|  | def test_led_board_blink_interrupt_off(): | ||||||
|  |     pin1 = MockPin(2) | ||||||
|  |     pin2 = MockPin(3) | ||||||
|  |     pin3 = MockPin(4) | ||||||
|  |     board = LEDBoard(pin1, LEDBoard(pin2, pin3)) | ||||||
|  |     board.blink(0.1, 1) | ||||||
|  |     sleep(0.2) | ||||||
|  |     board.off() # should interrupt while off | ||||||
|  |     pin1.assert_states([False, True, False]) | ||||||
|  |     pin2.assert_states([False, True, False]) | ||||||
|  |     pin3.assert_states([False, True, False]) | ||||||
|  |  | ||||||
|  | @pytest.mark.skipif(hasattr(sys, 'pypy_version_info'), | ||||||
|  |                     reason='timing is too random on pypy') | ||||||
|  | def test_led_board_fade_background(): | ||||||
|  |     pin1 = MockPWMPin(2) | ||||||
|  |     pin2 = MockPWMPin(3) | ||||||
|  |     pin3 = MockPWMPin(4) | ||||||
|  |     board = LEDBoard(pin1, LEDBoard(pin2, pin3, pwm=True), pwm=True) | ||||||
|  |     board.blink(0, 0, 0.1, 0.1, n=2) | ||||||
|  |     board._blink_thread.join() | ||||||
|  |     test = [ | ||||||
|  |         (0.0, 0), | ||||||
|  |         (0.02, 0.2), | ||||||
|  |         (0.02, 0.4), | ||||||
|  |         (0.02, 0.6), | ||||||
|  |         (0.02, 0.8), | ||||||
|  |         (0.02, 1), | ||||||
|  |         (0.02, 0.8), | ||||||
|  |         (0.02, 0.6), | ||||||
|  |         (0.02, 0.4), | ||||||
|  |         (0.02, 0.2), | ||||||
|  |         (0.02, 0), | ||||||
|  |         (0.02, 0.2), | ||||||
|  |         (0.02, 0.4), | ||||||
|  |         (0.02, 0.6), | ||||||
|  |         (0.02, 0.8), | ||||||
|  |         (0.02, 1), | ||||||
|  |         (0.02, 0.8), | ||||||
|  |         (0.02, 0.6), | ||||||
|  |         (0.02, 0.4), | ||||||
|  |         (0.02, 0.2), | ||||||
|  |         (0.02, 0), | ||||||
|  |         ] | ||||||
|  |     pin1.assert_states_and_times(test) | ||||||
|  |     pin2.assert_states_and_times(test) | ||||||
|  |     pin3.assert_states_and_times(test) | ||||||
|  |  | ||||||
|  | def test_led_bar_graph_value(): | ||||||
|  |     pin1 = MockPin(2) | ||||||
|  |     pin2 = MockPin(3) | ||||||
|  |     pin3 = MockPin(4) | ||||||
|  |     graph = LEDBarGraph(pin1, pin2, pin3) | ||||||
|  |     graph.value = 0 | ||||||
|  |     assert not any((pin1.state, pin2.state, pin3.state)) | ||||||
|  |     graph.value = 1 | ||||||
|  |     assert all((pin1.state, pin2.state, pin3.state)) | ||||||
|  |     graph.value = 1/3 | ||||||
|  |     assert pin1.state and not (pin2.state or pin3.state) | ||||||
|  |     graph.value = -1/3 | ||||||
|  |     assert pin3.state and not (pin1.state or pin2.state) | ||||||
|  |     pin1.state = True | ||||||
|  |     pin2.state = True | ||||||
|  |     assert graph.value == 1 | ||||||
|  |     pin3.state = False | ||||||
|  |     assert graph.value == 2/3 | ||||||
|  |     pin3.state = True | ||||||
|  |     pin1.state = False | ||||||
|  |     assert graph.value == -2/3 | ||||||
|  |  | ||||||
|  | def test_led_bar_graph_pwm_value(): | ||||||
|  |     pin1 = MockPWMPin(2) | ||||||
|  |     pin2 = MockPWMPin(3) | ||||||
|  |     pin3 = MockPWMPin(4) | ||||||
|  |     graph = LEDBarGraph(pin1, pin2, pin3, pwm=True) | ||||||
|  |     graph.value = 0 | ||||||
|  |     assert not any((pin1.state, pin2.state, pin3.state)) | ||||||
|  |     graph.value = 1 | ||||||
|  |     assert all((pin1.state, pin2.state, pin3.state)) | ||||||
|  |     graph.value = 1/3 | ||||||
|  |     assert pin1.state and not (pin2.state or pin3.state) | ||||||
|  |     graph.value = -1/3 | ||||||
|  |     assert pin3.state and not (pin1.state or pin2.state) | ||||||
|  |     graph.value = 1/2 | ||||||
|  |     assert (pin1.state, pin2.state, pin3.state) == (1, 0.5, 0) | ||||||
|  |     pin1.state = 0 | ||||||
|  |     pin3.state = 1 | ||||||
|  |     assert graph.value == -1/2 | ||||||
|  |  | ||||||
|  | def test_led_bar_graph_bad_init(): | ||||||
|  |     pin1 = MockPin(2) | ||||||
|  |     pin2 = MockPin(3) | ||||||
|  |     pin3 = MockPin(4) | ||||||
|  |     with pytest.raises(TypeError): | ||||||
|  |         LEDBarGraph(pin1, pin2, foo=pin3) | ||||||
|  |  | ||||||
|  | def test_pi_liter(): | ||||||
|  |     pins = [MockPin(n) for n in (4, 17, 27, 18, 22, 23, 24, 25)] | ||||||
|  |     board = PiLiter() | ||||||
|  |     assert [device.pin for device in board] == pins | ||||||
|  |  | ||||||
|  | def test_pi_liter_graph(): | ||||||
|  |     pins = [MockPin(n) for n in (4, 17, 27, 18, 22, 23, 24, 25)] | ||||||
|  |     board = PiLiterBarGraph() | ||||||
|  |     board.value = 0.5 | ||||||
|  |     assert [pin.state for pin in pins] == [1, 1, 1, 1, 0, 0, 0, 0] | ||||||
|  |     pins[4].state = 1 | ||||||
|  |     assert board.value == 5/8 | ||||||
|  |  | ||||||
|  | def test_traffic_lights(): | ||||||
|  |     red_pin = MockPin(2) | ||||||
|  |     amber_pin = MockPin(3) | ||||||
|  |     green_pin = MockPin(4) | ||||||
|  |     board = TrafficLights(red_pin, amber_pin, green_pin) | ||||||
|  |     board.red.on() | ||||||
|  |     assert red_pin.state | ||||||
|  |     assert not amber_pin.state | ||||||
|  |     assert not green_pin.state | ||||||
|  |  | ||||||
|  | def test_traffic_lights_bad_init(): | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         TrafficLights() | ||||||
|  |  | ||||||
|  | def test_pi_traffic(): | ||||||
|  |     pins = [MockPin(n) for n in (9, 10, 11)] | ||||||
|  |     board = PiTraffic() | ||||||
|  |     assert [device.pin for device in board] == pins | ||||||
|  |  | ||||||
|  | def test_snow_pi(): | ||||||
|  |     pins = [MockPin(n) for n in (23, 24, 25, 17, 18, 22, 7, 8, 9)] | ||||||
|  |     board = SnowPi() | ||||||
|  |     assert [device.pin for device in board.leds] == pins | ||||||
|  |  | ||||||
|  | def test_traffic_lights_buzzer(): | ||||||
|  |     red_pin = MockPin(2) | ||||||
|  |     amber_pin = MockPin(3) | ||||||
|  |     green_pin = MockPin(4) | ||||||
|  |     buzzer_pin = MockPin(5) | ||||||
|  |     button_pin = MockPin(6) | ||||||
|  |     board = TrafficLightsBuzzer( | ||||||
|  |             TrafficLights(red_pin, amber_pin, green_pin), | ||||||
|  |             Buzzer(buzzer_pin), | ||||||
|  |             Button(button_pin)) | ||||||
|  |     board.lights.red.on() | ||||||
|  |     board.buzzer.on() | ||||||
|  |     assert red_pin.state | ||||||
|  |     assert not amber_pin.state | ||||||
|  |     assert not green_pin.state | ||||||
|  |     assert buzzer_pin.state | ||||||
|  |     button_pin.drive_low() | ||||||
|  |     assert board.button.is_active | ||||||
|  |  | ||||||
|  | def test_fish_dish(): | ||||||
|  |     pins = [MockPin(n) for n in (9, 22, 4, 8, 7)] | ||||||
|  |     board = FishDish() | ||||||
|  |     assert [led.pin for led in board.lights] + [board.buzzer.pin, board.button.pin] == pins | ||||||
|  |  | ||||||
|  | def test_traffic_hat(): | ||||||
|  |     pins = [MockPin(n) for n in (24, 23, 22, 5, 25)] | ||||||
|  |     board = TrafficHat() | ||||||
|  |     assert [led.pin for led in board.lights] + [board.buzzer.pin, board.button.pin] == pins | ||||||
|  |  | ||||||
|  | def test_robot(): | ||||||
|  |     pins = [MockPWMPin(n) for n in (2, 3, 4, 5)] | ||||||
|  |     robot = Robot((2, 3), (4, 5)) | ||||||
|  |     assert ( | ||||||
|  |         [device.pin for device in robot.left_motor] + | ||||||
|  |         [device.pin for device in robot.right_motor]) == pins | ||||||
|  |     robot.forward() | ||||||
|  |     assert [pin.state for pin in pins] == [1, 0, 1, 0] | ||||||
|  |     robot.backward() | ||||||
|  |     assert [pin.state for pin in pins] == [0, 1, 0, 1] | ||||||
|  |     robot.forward(0.5) | ||||||
|  |     assert [pin.state for pin in pins] == [0.5, 0, 0.5, 0] | ||||||
|  |     robot.left() | ||||||
|  |     assert [pin.state for pin in pins] == [0, 1, 1, 0] | ||||||
|  |     robot.right() | ||||||
|  |     assert [pin.state for pin in pins] == [1, 0, 0, 1] | ||||||
|  |     robot.reverse() | ||||||
|  |     assert [pin.state for pin in pins] == [0, 1, 1, 0] | ||||||
|  |     robot.stop() | ||||||
|  |     assert [pin.state for pin in pins] == [0, 0, 0, 0] | ||||||
|  |  | ||||||
|  | def test_ryanteck_robot(): | ||||||
|  |     pins = [MockPWMPin(n) for n in (17, 18, 22, 23)] | ||||||
|  |     board = RyanteckRobot() | ||||||
|  |     assert [device.pin for motor in board for device in motor] == pins | ||||||
|  |  | ||||||
|  | def test_camjam_kit_robot(): | ||||||
|  |     pins = [MockPWMPin(n) for n in (9, 10, 7, 8)] | ||||||
|  |     board = CamJamKitRobot() | ||||||
|  |     assert [device.pin for motor in board for device in motor] == pins | ||||||
|  |  | ||||||
|  | def test_energenie_bad_init(): | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         Energenie() | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         Energenie(0) | ||||||
|  |  | ||||||
|  | def test_energenie(): | ||||||
|  |     pins = [MockPin(n) for n in (17, 22, 23, 27, 24, 25)] | ||||||
|  |     device1 = Energenie(1, initial_value=True) | ||||||
|  |     device2 = Energenie(2, initial_value=False) | ||||||
|  |     assert device1.value | ||||||
|  |     assert not device2.value | ||||||
|  |     [pin.clear_states() for pin in pins] | ||||||
|  |     device1.on() | ||||||
|  |     assert device1.value | ||||||
|  |     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[2].assert_states_and_times([(0.0, True), (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[5].assert_states_and_times([(0.0, False), (0.1, True), (0.25, False)]) | ||||||
|  |     [pin.clear_states() for pin in pins] | ||||||
|  |     device2.on() | ||||||
|  |     assert device2.value | ||||||
|  |     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[2].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[5].assert_states_and_times([(0.0, False), (0.1, True), (0.25, False)]) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,7 +5,10 @@ from __future__ import ( | |||||||
|     division, |     division, | ||||||
|     ) |     ) | ||||||
| str = type('') | str = type('') | ||||||
|  | try: | ||||||
|  |     range = xrange | ||||||
|  | except NameError: | ||||||
|  |     pass | ||||||
|  |  | ||||||
| import io | import io | ||||||
| import subprocess | import subprocess | ||||||
| @@ -13,6 +16,10 @@ import subprocess | |||||||
| import pytest | import pytest | ||||||
|  |  | ||||||
| from gpiozero import PinFixedPull, PinInvalidPull, PinInvalidFunction | from gpiozero import PinFixedPull, PinInvalidPull, PinInvalidFunction | ||||||
|  | try: | ||||||
|  |     from math import isclose | ||||||
|  | except ImportError: | ||||||
|  |     from gpiozero.compat import isclose | ||||||
|  |  | ||||||
|  |  | ||||||
| # This module assumes you've wired the following GPIO pins together | # This module assumes you've wired the following GPIO pins together | ||||||
| @@ -56,7 +63,6 @@ try: | |||||||
| except ImportError: | except ImportError: | ||||||
|     NativePin = None |     NativePin = None | ||||||
|  |  | ||||||
|  |  | ||||||
| @pytest.fixture(scope='module', params=PIN_CLASSES) | @pytest.fixture(scope='module', params=PIN_CLASSES) | ||||||
| def pin_class(request): | def pin_class(request): | ||||||
|     # pigpiod needs to be running for PiGPIOPin |     # pigpiod needs to be running for PiGPIOPin | ||||||
| @@ -70,13 +76,13 @@ def pin_class(request): | |||||||
|         request.addfinalizer(kill_pigpiod) |         request.addfinalizer(kill_pigpiod) | ||||||
|     return request.param |     return request.param | ||||||
|  |  | ||||||
| @pytest.fixture | @pytest.fixture(scope='function') | ||||||
| def pins(request, pin_class): | def pins(request, pin_class): | ||||||
|     # Why return both pins in a single fixture? If we defined one fixture for |     # Why return both pins in a single fixture? If we defined one fixture for | ||||||
|     # each pin then pytest will (correctly) test RPiGPIOPin(22) against |     # each pin then pytest will (correctly) test RPiGPIOPin(22) against | ||||||
|     # NativePin(27) and so on. This isn't supported, so we don't test it |     # NativePin(27) and so on. This isn't supported, so we don't test it | ||||||
|     test_pin = pin_class(22) |     test_pin = pin_class(TEST_PIN) | ||||||
|     input_pin = pin_class(27) |     input_pin = pin_class(INPUT_PIN) | ||||||
|     input_pin.function = 'input' |     input_pin.function = 'input' | ||||||
|     input_pin.pull = 'down' |     input_pin.pull = 'down' | ||||||
|     def fin(): |     def fin(): | ||||||
| @@ -88,8 +94,8 @@ def pins(request, pin_class): | |||||||
|  |  | ||||||
| def test_pin_numbers(pins): | def test_pin_numbers(pins): | ||||||
|     test_pin, input_pin = pins |     test_pin, input_pin = pins | ||||||
|     assert test_pin.number == 22 |     assert test_pin.number == TEST_PIN | ||||||
|     assert input_pin.number == 27 |     assert input_pin.number == INPUT_PIN | ||||||
|  |  | ||||||
| def test_function_bad(pins): | def test_function_bad(pins): | ||||||
|     test_pin, input_pin = pins |     test_pin, input_pin = pins | ||||||
| @@ -125,12 +131,18 @@ def test_pull_bad(pins): | |||||||
|     test_pin.function = 'input' |     test_pin.function = 'input' | ||||||
|     with pytest.raises(PinInvalidPull): |     with pytest.raises(PinInvalidPull): | ||||||
|         test_pin.pull = 'foo' |         test_pin.pull = 'foo' | ||||||
|  |     with pytest.raises(PinInvalidPull): | ||||||
|  |         test_pin.input_with_pull('foo') | ||||||
|  |  | ||||||
| def test_pull_down_warning(pin_class): | def test_pull_down_warning(pin_class): | ||||||
|  |     # XXX This assumes we're on a vaguely modern Pi and not a compute module | ||||||
|  |     # Might want to refine this with the pi-info database | ||||||
|     pin = pin_class(2) |     pin = pin_class(2) | ||||||
|     try: |     try: | ||||||
|         with pytest.raises(PinFixedPull): |         with pytest.raises(PinFixedPull): | ||||||
|             pin.pull = 'down' |             pin.pull = 'down' | ||||||
|  |         with pytest.raises(PinFixedPull): | ||||||
|  |             pin.input_with_pull('down') | ||||||
|     finally: |     finally: | ||||||
|         pin.close() |         pin.close() | ||||||
|  |  | ||||||
| @@ -141,3 +153,25 @@ def test_input_with_pull(pins): | |||||||
|     test_pin.input_with_pull('down') |     test_pin.input_with_pull('down') | ||||||
|     assert input_pin.state == 0 |     assert input_pin.state == 0 | ||||||
|  |  | ||||||
|  | @pytest.mark.skipif(True, reason='causes segfaults') | ||||||
|  | def test_bad_duty_cycle(pins): | ||||||
|  |     test_pin, input_pin = pins | ||||||
|  |     if test_pin.__class__.__name__ == 'NativePin': | ||||||
|  |         pytest.skip("native pin doesn't support PWM") | ||||||
|  |     test_pin.function = 'output' | ||||||
|  |     test_pin.frequency = 100 | ||||||
|  |     with pytest.raises(ValueError): | ||||||
|  |         test_pin.state = 1.1 | ||||||
|  |  | ||||||
|  | def test_duty_cycles(pins): | ||||||
|  |     test_pin, input_pin = pins | ||||||
|  |     if test_pin.__class__.__name__ == 'NativePin': | ||||||
|  |         pytest.skip("native pin doesn't support PWM") | ||||||
|  |     test_pin.function = 'output' | ||||||
|  |     test_pin.frequency = 100 | ||||||
|  |     for duty_cycle in (0.0, 0.1, 0.5, 1.0): | ||||||
|  |         test_pin.state = duty_cycle | ||||||
|  |         assert test_pin.state == duty_cycle | ||||||
|  |         total = sum(input_pin.state for i in range(20000)) | ||||||
|  |         assert isclose(total / 20000, duty_cycle, rel_tol=0.1, abs_tol=0.1) | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user