From a0d784082d59fbfa2e19226dfb083ced6cc20b91 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 14 Jul 2017 15:11:59 +0100 Subject: [PATCH] Fix #565 Add mock pins docs and tidy up some other bits of the pins docs --- docs/api_pins.rst | 104 +++++++++++++++++++++++-------------- docs/api_utils.rst | 20 +++++++ docs/examples/mock_demo.py | 28 ++++++++++ docs/index.rst | 1 + gpiozero/pins/__init__.py | 15 ++---- gpiozero/pins/mock.py | 22 +++++++- gpiozero/pins/native.py | 3 ++ gpiozero/pins/pigpio.py | 18 +++++++ gpiozero/pins/rpigpio.py | 6 +++ gpiozero/pins/rpio.py | 6 +++ 10 files changed, 171 insertions(+), 52 deletions(-) create mode 100644 docs/api_utils.rst create mode 100644 docs/examples/mock_demo.py diff --git a/docs/api_pins.rst b/docs/api_pins.rst index e79e020..2342e60 100644 --- a/docs/api_pins.rst +++ b/docs/api_pins.rst @@ -135,36 +135,22 @@ Like the ``GPIOZERO_PIN_FACTORY`` value, these can be exported from your Sensible uses of multiple pin factories are given in :doc:`remote_gpio`. -RPi.GPIO -======== +Mock pins +========= -.. autoclass:: gpiozero.pins.rpigpio.RPiGPIOFactory +There's also a :class:`gpiozero.pins.mock.MockFactory` which generates entirely +fake pins. This was originally intended for GPIO Zero developers who wish to +write tests for devices without having to have the physical device wired in to +their Pi. However, they have also proven relatively useful in developing GPIO +Zero scripts without having a Pi to hand. This pin factory will never be loaded +by default; it must be explicitly specified. For example: -.. autoclass:: gpiozero.pins.rpigpio.RPiGPIOPin +.. literalinclude:: examples/mock_demo.py - -RPIO -==== - -.. autoclass:: gpiozero.pins.rpio.RPIOFactory - -.. autoclass:: gpiozero.pins.rpio.RPIOPin - - -PiGPIO -====== - -.. autoclass:: gpiozero.pins.pigpio.PiGPIOFactory - -.. autoclass:: gpiozero.pins.pigpio.PiGPIOPin - - -Native -====== - -.. autoclass:: gpiozero.pins.native.NativeFactory - -.. autoclass:: gpiozero.pins.native.NativePin +Several sub-classes of mock pins exist for emulating various other things +(pins that do/don't support PWM, pins that are connected together, pins that +drive high after a delay, etc). Interested users are invited to read the GPIO +Zero test suite for further examples of usage. Base classes @@ -196,22 +182,62 @@ Base classes :members: -Utilities -========= +RPi.GPIO +======== -The pins module also contains a database of information about the various -revisions of Raspberry Pi. This is used internally to raise warnings when -non-physical pins are used, or to raise exceptions when pull-downs are -requested on pins with physical pull-up resistors attached. The following -functions and classes can be used to query this database: +.. currentmodule:: gpiozero.pins.rpigpio -.. currentmodule:: gpiozero +.. autoclass:: gpiozero.pins.rpigpio.RPiGPIOFactory -.. autofunction:: pi_info +.. autoclass:: gpiozero.pins.rpigpio.RPiGPIOPin -.. autoclass:: PiBoardInfo -.. autoclass:: HeaderInfo +RPIO +==== -.. autoclass:: PinInfo +.. currentmodule:: gpiozero.pins.rpio + +.. autoclass:: gpiozero.pins.rpio.RPIOFactory + +.. autoclass:: gpiozero.pins.rpio.RPIOPin + + +PiGPIO +====== + +.. currentmodule:: gpiozero.pins.pigpio + +.. autoclass:: gpiozero.pins.pigpio.PiGPIOFactory + +.. autoclass:: gpiozero.pins.pigpio.PiGPIOPin + + +Native +====== + +.. currentmodule:: gpiozero.pins.native + +.. autoclass:: gpiozero.pins.native.NativeFactory + +.. autoclass:: gpiozero.pins.native.NativePin + + +Mock +==== + +.. currentmodule:: gpiozero.pins.mock + +.. autoclass:: gpiozero.pins.mock.MockFactory + :members: + +.. autoclass:: gpiozero.pins.mock.MockPin + :members: + +.. autoclass:: gpiozero.pins.mock.MockPWMPin + +.. autoclass:: gpiozero.pins.mock.MockConnectedPin + +.. autoclass:: gpiozero.pins.mock.MockChargingPin + +.. autoclass:: gpiozero.pins.mock.MockTriggerPin diff --git a/docs/api_utils.rst b/docs/api_utils.rst new file mode 100644 index 0000000..6c22b1f --- /dev/null +++ b/docs/api_utils.rst @@ -0,0 +1,20 @@ +========= +Utilities +========= + +.. currentmodule:: gpiozero + +The GPIO Zero library also contains a database of information about the various +revisions of Raspberry Pi. This is used internally to raise warnings when +non-physical pins are used, or to raise exceptions when pull-downs are +requested on pins with physical pull-up resistors attached. The following +functions and classes can be used to query this database: + +.. autofunction:: pi_info + +.. autoclass:: PiBoardInfo + +.. autoclass:: HeaderInfo + +.. autoclass:: PinInfo + diff --git a/docs/examples/mock_demo.py b/docs/examples/mock_demo.py new file mode 100644 index 0000000..d0878e2 --- /dev/null +++ b/docs/examples/mock_demo.py @@ -0,0 +1,28 @@ +from gpiozero.pins.mock import MockFactory +from gpiozero import Device, Button, LED +from time import sleep + +# Set the default pin factory to a mock factory +Device.pin_factory = MockFactory() + +# Construct a couple of devices attached to mock pins 16 and 17, and link the +# devices +led = LED(17) +btn = Button(16) +led.source = btn.values + +# Here the button isn't "pushed" so the LED's value should be False +print(led.value) + +# Get a reference to mock pin 16 (used by the button) +btn_pin = Device.pin_factory.pin(16) + +# Drive the pin low (this is what would happen eletrically when the button is +# pushed) +btn_pin.drive_low() +sleep(0.1) # give source some time to re-read the button state +print(led.value) + +btn_pin.drive_high() +sleep(0.1) +print(led.value) diff --git a/docs/index.rst b/docs/index.rst index 1ded9f9..ad2fa6e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -17,6 +17,7 @@ Table of Contents api_generic api_tools api_pins + api_utils api_exc cli_tools source_values diff --git a/gpiozero/pins/__init__.py b/gpiozero/pins/__init__.py index 83ebc0c..70febc1 100644 --- a/gpiozero/pins/__init__.py +++ b/gpiozero/pins/__init__.py @@ -30,15 +30,9 @@ from ..exc import ( class Factory(object): """ - Generates pins, SPI, and I2C interfaces for devices. This is an abstract - base class for pin factories. Descendents *must* override the following - methods: - - * :meth:`_get_address` - * :meth:`pin_address` - - Descendents *may* additionally override the following methods, if - applicable: + Generates pins and SPI interfaces for devices. This is an abstract + base class for pin factories. Descendents *may* override the following + methods, if applicable: * :meth:`close` * :meth:`reserve_pins` @@ -129,9 +123,6 @@ class Factory(object): """ raise PinSPIUnsupported('SPI not supported by this pin factory') - def _get_address(self): - raise NotImplementedError - def _get_pi_info(self): return None diff --git a/gpiozero/pins/mock.py b/gpiozero/pins/mock.py index 742e01a..bc1b7a1 100644 --- a/gpiozero/pins/mock.py +++ b/gpiozero/pins/mock.py @@ -216,7 +216,7 @@ class MockChargingPin(MockPin): class MockTriggerPin(MockPin): """ This derivative of :class:`MockPin` is intended to be used with another - :class:`MockPin` to emulate a distance sensor. Set :attr:`echo_pin` to the + :class:`MockPin` to emulate a distance sensor. Set *echo_pin* to the corresponding pin instance. When this pin is driven high it will trigger the echo pin to drive high for the echo time. """ @@ -410,6 +410,14 @@ class MockSPIDevice(object): class MockFactory(LocalPiFactory): + """ + Factory for generating mock pins. The *revision* parameter specifies what + revision of Pi the mock factory pretends to be (this affects the result of + the :attr:`pi_info` attribute as well as where pull-ups are assumed to be). + The *pin_class* attribute specifies which mock pin class will be generated + by the :meth:`pin` method by default. This can be changed after + construction by modifying the :attr:`pin_class` attribute. + """ def __init__( self, revision=os.getenv('GPIOZERO_MOCK_REVISION', 'a02082'), pin_class=os.getenv('GPIOZERO_MOCK_PIN_CLASS', MockPin)): @@ -427,10 +435,22 @@ class MockFactory(LocalPiFactory): return self._revision def reset(self): + """ + Clears the pins and reservations sets. This is primarily useful in + test suites to ensure the pin factory is back in a "clean" state before + the next set of tests are run. + """ self.pins.clear() self._reservations.clear() def pin(self, spec, pin_class=None, **kwargs): + """ + The pin method for :class:`MockFactory` additionally takes a *pin_class* + attribute which can be used to override the class' :attr:`pin_class` + attribute. Any additional keyword arguments will be passed along to the + pin constructor (useful with things like :class:`MockConnectedPin` which + expect to be constructed with another pin). + """ if pin_class is None: pin_class = self.pin_class n = self._to_gpio(spec) diff --git a/gpiozero/pins/native.py b/gpiozero/pins/native.py index cdfd84d..399fdfc 100644 --- a/gpiozero/pins/native.py +++ b/gpiozero/pins/native.py @@ -178,6 +178,9 @@ class NativeFactory(LocalPiFactory): class NativePin(LocalPiPin): + """ + Native pin implementation. See :class:`NativeFactory` for more information. + """ GPIO_FUNCTIONS = { 'input': 0b000, 'output': 0b001, diff --git a/gpiozero/pins/pigpio.py b/gpiozero/pins/pigpio.py index dc46ed3..bc466b9 100644 --- a/gpiozero/pins/pigpio.py +++ b/gpiozero/pins/pigpio.py @@ -133,6 +133,12 @@ class PiGPIOFactory(PiFactory): class PiGPIOPin(PiPin): + """ + Pin implementation for the `pigpio`_ library. See :class:`PiGPIOFactory` + for more information. + + .. _pigpio: http://abyz.co.uk/rpi/pigpio/ + """ _CONNECTIONS = {} # maps (host, port) to (connection, pi_info) GPIO_FUNCTIONS = { 'input': pigpio.INPUT, @@ -290,6 +296,12 @@ class PiGPIOPin(PiPin): class PiGPIOHardwareSPI(SPI, Device): + """ + Hardware SPI implementation for the `pigpio`_ library. Uses the ``spi_*`` + functions from the pigpio API. + + .. _pigpio: http://abyz.co.uk/rpi/pigpio/ + """ def __init__(self, factory, port, device): self._port = port self._device = device @@ -386,6 +398,12 @@ class PiGPIOHardwareSPI(SPI, Device): class PiGPIOSoftwareSPI(SPI, Device): + """ + Software SPI implementation for the `pigpio`_ library. Uses the ``bb_spi_*`` + functions from the pigpio API. + + .. _pigpio: http://abyz.co.uk/rpi/pigpio/ + """ def __init__(self, factory, clock_pin, mosi_pin, miso_pin, select_pin): self._closed = True self._select_pin = select_pin diff --git a/gpiozero/pins/rpigpio.py b/gpiozero/pins/rpigpio.py index 332c1c2..6a35727 100644 --- a/gpiozero/pins/rpigpio.py +++ b/gpiozero/pins/rpigpio.py @@ -58,6 +58,12 @@ class RPiGPIOFactory(LocalPiFactory): class RPiGPIOPin(LocalPiPin): + """ + Pin implementation for the `RPi.GPIO`_ library. See :class:`RPiGPIOFactory` + for more information. + + .. _RPi.GPIO: https://pypi.python.org/pypi/RPi.GPIO + """ GPIO_FUNCTIONS = { 'input': GPIO.IN, 'output': GPIO.OUT, diff --git a/gpiozero/pins/rpio.py b/gpiozero/pins/rpio.py index 553916b..c97c56d 100644 --- a/gpiozero/pins/rpio.py +++ b/gpiozero/pins/rpio.py @@ -64,6 +64,12 @@ class RPIOFactory(LocalPiFactory): class RPIOPin(LocalPiPin): + """ + Pin implementation for the `RPIO`_ library. See :class:`RPIOFactory` for + more information. + + .. _RPIO: https://pythonhosted.org/RPIO/ + """ GPIO_FUNCTIONS = { 'input': RPIO.IN, 'output': RPIO.OUT,