mirror of
				https://github.com/KevinMidboe/python-gpiozero.git
				synced 2025-10-29 17:50:37 +00:00 
			
		
		
		
	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...
		
			
				
	
	
		
			178 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			178 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| from __future__ import (
 | |
|     unicode_literals,
 | |
|     absolute_import,
 | |
|     print_function,
 | |
|     division,
 | |
|     )
 | |
| str = type('')
 | |
| try:
 | |
|     range = xrange
 | |
| except NameError:
 | |
|     pass
 | |
| 
 | |
| import io
 | |
| import subprocess
 | |
| 
 | |
| import pytest
 | |
| 
 | |
| 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
 | |
| TEST_PIN = 22
 | |
| INPUT_PIN = 27
 | |
| 
 | |
| 
 | |
| # Skip the entire module if we're not on a Pi
 | |
| def is_a_pi():
 | |
|     with io.open('/proc/cpuinfo', 'r') as cpuinfo:
 | |
|         for line in cpuinfo:
 | |
|             if line.startswith('Hardware'):
 | |
|                 hardware, colon, soc = line.strip().split(None, 2)
 | |
|                 return soc in ('BCM2708', 'BCM2709', 'BCM2835', 'BCM2836')
 | |
|         else:
 | |
|             return False
 | |
| pytestmark = pytest.mark.skipif(not is_a_pi(), reason='tests cannot run on non-Pi platforms')
 | |
| del is_a_pi
 | |
| 
 | |
| 
 | |
| # Try and import as many pin libraries as possible
 | |
| PIN_CLASSES = []
 | |
| try:
 | |
|     from gpiozero.pins.rpigpio import RPiGPIOPin
 | |
|     PIN_CLASSES.append(RPiGPIOPin)
 | |
| except ImportError:
 | |
|     RPiGPIOPin = None
 | |
| try:
 | |
|     from gpiozero.pins.rpio import RPIOPin
 | |
|     PIN_CLASSES.append(RPIOPin)
 | |
| except ImportError:
 | |
|     RPIOPin = None
 | |
| try:
 | |
|     from gpiozero.pins.pigpiod import PiGPIOPin
 | |
|     PIN_CLASSES.append(PiGPIOPin)
 | |
| except ImportError:
 | |
|     PiGPIOPin = None
 | |
| try:
 | |
|     from gpiozero.pins.native import NativePin
 | |
|     PIN_CLASSES.append(NativePin)
 | |
| except ImportError:
 | |
|     NativePin = None
 | |
| 
 | |
| @pytest.fixture(scope='module', params=PIN_CLASSES)
 | |
| def pin_class(request):
 | |
|     # pigpiod needs to be running for PiGPIOPin
 | |
|     if request.param.__name__ == 'PiGPIOPin':
 | |
|         subprocess.check_call(['sudo', 'pigpiod'])
 | |
|         # Unfortunately, pigpiod provides no option for running in the
 | |
|         # foreground, so we have to use the sledgehammer of killall to get shot
 | |
|         # of it
 | |
|         def kill_pigpiod():
 | |
|             subprocess.check_call(['sudo', 'killall', 'pigpiod'])
 | |
|         request.addfinalizer(kill_pigpiod)
 | |
|     return request.param
 | |
| 
 | |
| @pytest.fixture(scope='function')
 | |
| def pins(request, pin_class):
 | |
|     # Why return both pins in a single fixture? If we defined one fixture for
 | |
|     # 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
 | |
|     test_pin = pin_class(TEST_PIN)
 | |
|     input_pin = pin_class(INPUT_PIN)
 | |
|     input_pin.function = 'input'
 | |
|     input_pin.pull = 'down'
 | |
|     def fin():
 | |
|         test_pin.close()
 | |
|         input_pin.close()
 | |
|     request.addfinalizer(fin)
 | |
|     return test_pin, input_pin
 | |
| 
 | |
| 
 | |
| def test_pin_numbers(pins):
 | |
|     test_pin, input_pin = pins
 | |
|     assert test_pin.number == TEST_PIN
 | |
|     assert input_pin.number == INPUT_PIN
 | |
| 
 | |
| def test_function_bad(pins):
 | |
|     test_pin, input_pin = pins
 | |
|     with pytest.raises(PinInvalidFunction):
 | |
|         test_pin.function = 'foo'
 | |
| 
 | |
| def test_output(pins):
 | |
|     test_pin, input_pin = pins
 | |
|     test_pin.function = 'output'
 | |
|     test_pin.state = 0
 | |
|     assert input_pin.state == 0
 | |
|     test_pin.state = 1
 | |
|     assert input_pin.state == 1
 | |
| 
 | |
| def test_output_with_state(pins):
 | |
|     test_pin, input_pin = pins
 | |
|     test_pin.output_with_state(0)
 | |
|     assert input_pin.state == 0
 | |
|     test_pin.output_with_state(1)
 | |
|     assert input_pin.state == 1
 | |
| 
 | |
| def test_pull(pins):
 | |
|     test_pin, input_pin = pins
 | |
|     test_pin.function = 'input'
 | |
|     test_pin.pull = 'up'
 | |
|     assert input_pin.state == 1
 | |
|     test_pin.pull = 'down'
 | |
|     test_pin, input_pin = pins
 | |
|     assert input_pin.state == 0
 | |
| 
 | |
| def test_pull_bad(pins):
 | |
|     test_pin, input_pin = pins
 | |
|     test_pin.function = 'input'
 | |
|     with pytest.raises(PinInvalidPull):
 | |
|         test_pin.pull = 'foo'
 | |
|     with pytest.raises(PinInvalidPull):
 | |
|         test_pin.input_with_pull('foo')
 | |
| 
 | |
| 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)
 | |
|     try:
 | |
|         with pytest.raises(PinFixedPull):
 | |
|             pin.pull = 'down'
 | |
|         with pytest.raises(PinFixedPull):
 | |
|             pin.input_with_pull('down')
 | |
|     finally:
 | |
|         pin.close()
 | |
| 
 | |
| def test_input_with_pull(pins):
 | |
|     test_pin, input_pin = pins
 | |
|     test_pin.input_with_pull('up')
 | |
|     assert input_pin.state == 1
 | |
|     test_pin.input_with_pull('down')
 | |
|     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)
 | |
| 
 |