From 924850ccdee3771f3e304aade8f8e04acb94b544 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Wed, 14 Oct 2015 09:38:16 +0100 Subject: [PATCH] Fix #66 This PR adds the `active_high` parameter (defaulted to `True`) to the `OutputDevice` class. This permits flipping the logic of an output device in a similar manner to `pull_up` on `InputDevice`. It also adds a `Relay` class derived from `DigitalOutputDevice` which uses this parameter to flip the logic (as this is typically required with relays). --- gpiozero/output_devices.py | 51 +++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/gpiozero/output_devices.py b/gpiozero/output_devices.py index cd13ff8..6163ba6 100644 --- a/gpiozero/output_devices.py +++ b/gpiozero/output_devices.py @@ -19,9 +19,17 @@ class OutputDevice(GPIODevice): This class extends `GPIODevice` to add facilities common to GPIO output devices: an `on` method to switch the device on, and a corresponding `off` method. + + active_high: `True` + If `True` (the default), the `on` method will set the GPIO to HIGH. If + `False`, the `on` method will set the GPIO to LOW (the `off` method + always does the opposite). """ - def __init__(self, pin=None): + def __init__(self, pin=None, active_high=True): + self._active_high = active_high super(OutputDevice, self).__init__(pin) + self._active_state = GPIO.HIGH if active_high else GPIO.LOW + self._inactive_state = GPIO.LOW if active_high else GPIO.HIGH try: # NOTE: catch_warnings isn't thread-safe but hopefully no-one's # messing around with GPIO init within background threads... @@ -46,13 +54,24 @@ class OutputDevice(GPIODevice): """ Turns the device on. """ - self._write(1) + self._write(self._active_state) def off(self): """ Turns the device off. """ - self._write(0) + self._write(self._inactive_state) + + @property + def active_high(self): + return self._active_high + + def __repr__(self): + try: + return '' % ( + self.__class__.__name__, self.pin, self.active_high, self.is_active) + except: + return super(OutputDevice, self).__repr__() class DigitalOutputDevice(OutputDevice): @@ -64,8 +83,8 @@ class DigitalOutputDevice(OutputDevice): optional background thread to handle toggling the device state without further interaction. """ - def __init__(self, pin=None): - super(DigitalOutputDevice, self).__init__(pin) + def __init__(self, pin=None, active_high=True): + super(DigitalOutputDevice, self).__init__(pin, active_high) self._blink_thread = None self._lock = Lock() @@ -74,14 +93,14 @@ class DigitalOutputDevice(OutputDevice): Turns the device on. """ self._stop_blink() - self._write(1) + self._write(self._active_state) def off(self): """ Turns the device off. """ self._stop_blink() - self._write(0) + self._write(self._inactive_state) def toggle(self): """ @@ -130,10 +149,10 @@ class DigitalOutputDevice(OutputDevice): def _blink_led(self, on_time, off_time, n): iterable = repeat(0) if n is None else repeat(0, n) for i in iterable: - self._write(1) + self._write(self._active_state) if self._blink_thread.stopping.wait(on_time): break - self._write(0) + self._write(self._inactive_state) if self._blink_thread.stopping.wait(off_time): break @@ -149,6 +168,20 @@ class LED(DigitalOutputDevice): pass +class Relay(DigitalOutputDevice): + """ + A relay (electro-mechanical switching) component. + + A typical configuration of such a device is to wire the circuit to the NO + (Normally Open) pins of the relay rather than the NC (Normally Closed) pins + for safety. Most relays operate with reversed logic so the `active_high` + parameter defaults to `False` in this class (see OutputDevice for more + information). + """ + def __init__(self, pin=None, active_high=False): + super(Relay, self).__init__(pin, active_high) + + class Buzzer(DigitalOutputDevice): """ A digital Buzzer component.