Source code for gpiozero.pins.rpigpio

from __future__ import (
    unicode_literals,
    absolute_import,
    print_function,
    division,
    )
str = type('')

from RPi import GPIO

from . import Pin
from .exc import (
    PinInvalidFunction,
    PinSetInput,
    PinFixedPull,
    )


[docs]class RPiGPIOPin(Pin): """ Uses the `RPi.GPIO`_ library to interface to the Pi's GPIO pins. This is the default pin implementation if the RPi.GPIO library is installed. Supports all features including PWM (via software). .. _RPi.GPIO: https://pypi.python.org/pypi/RPi.GPIO """ _PINS = {} GPIO_FUNCTIONS = { 'input': GPIO.IN, 'output': GPIO.OUT, 'i2c': GPIO.I2C, 'spi': GPIO.SPI, 'pwm': GPIO.PWM, 'serial': GPIO.SERIAL, 'unknown': GPIO.UNKNOWN, } GPIO_PULL_UPS = { 'up': GPIO.PUD_UP, 'down': GPIO.PUD_DOWN, 'floating': GPIO.PUD_OFF, } GPIO_EDGES = { 'both': GPIO.BOTH, 'rising': GPIO.RISING, 'falling': GPIO.FALLING, } GPIO_FUNCTION_NAMES = {v: k for (k, v) in GPIO_FUNCTIONS.items()} GPIO_PULL_UP_NAMES = {v: k for (k, v) in GPIO_PULL_UPS.items()} GPIO_EDGES_NAMES = {v: k for (k, v) in GPIO_EDGES.items()} def __new__(cls, number): if not cls._PINS: GPIO.setmode(GPIO.BCM) GPIO.setwarnings(False) try: return cls._PINS[number] except KeyError: self = super(RPiGPIOPin, cls).__new__(cls) cls._PINS[number] = self self._number = number self._pull = 'up' if number in (2, 3) else 'floating' self._pwm = None self._frequency = None self._duty_cycle = None self._bounce = -666 self._when_changed = None self._edges = GPIO.BOTH GPIO.setup(self._number, GPIO.IN, self.GPIO_PULL_UPS[self._pull]) return self def __repr__(self): return "GPIO%d" % self._number @property def number(self): return self._number def close(self): self.frequency = None self.when_changed = None GPIO.cleanup(self._number) def output_with_state(self, state): self._pull = 'floating' GPIO.setup(self._number, GPIO.OUT, initial=state) def input_with_pull(self, pull): if pull != 'up' and self._number in (2, 3): raise PinFixedPull('%r has a physical pull-up resistor' % self) try: GPIO.setup(self._number, GPIO.IN, self.GPIO_PULL_UPS[pull]) self._pull = pull except KeyError: raise PinInvalidPull('invalid pull "%s" for pin %r' % (pull, self)) def _get_function(self): return self.GPIO_FUNCTION_NAMES[GPIO.gpio_function(self._number)] def _set_function(self, value): if value != 'input': self._pull = 'floating' try: GPIO.setup(self._number, self.GPIO_FUNCTIONS[value], self.GPIO_PULL_UPS[self._pull]) except KeyError: raise PinInvalidFunction('invalid function "%s" for pin %r' % (value, self)) def _get_state(self): if self._pwm: return self._duty_cycle else: return GPIO.input(self._number) def _set_state(self, value): if self._pwm: try: self._pwm.ChangeDutyCycle(value * 100) except ValueError: raise PinInvalidValue('invalid state "%s" for pin %r' % (value, self)) self._duty_cycle = value else: try: GPIO.output(self._number, value) except ValueError: raise PinInvalidState('invalid state "%s" for pin %r' % (value, self)) except RuntimeError: raise PinSetInput('cannot set state of pin %r' % self) def _get_pull(self): return self._pull def _set_pull(self, value): if self.function != 'input': raise PinFixedPull('cannot set pull on non-input pin %r' % self) if value != 'up' and self._number in (2, 3): raise PinFixedPull('%r has a physical pull-up resistor' % self) try: GPIO.setup(self._number, GPIO.IN, self.GPIO_PULL_UPS[value]) self._pull = value except KeyError: raise PinInvalidPull('invalid pull "%s" for pin %r' % (value, self)) def _get_frequency(self): return self._frequency def _set_frequency(self, value): if self._frequency is None and value is not None: try: self._pwm = GPIO.PWM(self._number, value) except RuntimeError: raise PinPWMFixedValue('cannot start PWM on pin %r' % self) self._pwm.start(0) self._duty_cycle = 0 self._frequency = value elif self._frequency is not None and value is not None: self._pwm.ChangeFrequency(value) self._frequency = value elif self._frequency is not None and value is None: self._pwm.stop() self._pwm = None self._duty_cycle = None self._frequency = None def _get_bounce(self): return None if self._bounce == -666 else (self._bounce / 1000) def _set_bounce(self, value): f = self.when_changed self.when_changed = None try: self._bounce = -666 if value is None else (value * 1000) finally: self.when_changed = f def _get_edges(self): return self.GPIO_EDGES_NAMES[self._edges] def _set_edges(self, value): f = self.when_changed self.when_changed = None try: self._edges = self.GPIO_EDGES[value] finally: self.when_changed = f def _get_when_changed(self): return self._when_changed def _set_when_changed(self, value): if self._when_changed is None and value is not None: self._when_changed = value GPIO.add_event_detect( self._number, self._edges, callback=lambda channel: self._when_changed(), bouncetime=self._bounce) elif self._when_changed is not None and value is None: GPIO.remove_event_detect(self._number) self._when_changed = None else: self._when_changed = value