mirror of
https://github.com/KevinMidboe/python-gpiozero.git
synced 2025-10-29 17:50:37 +00:00
@@ -32,8 +32,14 @@ class OutputDevice(SourceMixin, GPIODevice):
|
|||||||
If ``True`` (the default), the :meth:`on` method will set the GPIO to
|
If ``True`` (the default), the :meth:`on` method will set the GPIO to
|
||||||
HIGH. If ``False``, the :meth:`on` method will set the GPIO to LOW (the
|
HIGH. If ``False``, the :meth:`on` method will set the GPIO to LOW (the
|
||||||
:meth:`off` method always does the opposite).
|
:meth:`off` method always does the opposite).
|
||||||
|
|
||||||
|
:param bool initial_value:
|
||||||
|
If ``False`` (the default), the device will be off initially. If
|
||||||
|
``None``, the device will be left in whatever state the pin is found in
|
||||||
|
when configured for output (warning: this can be on). If ``True``, the
|
||||||
|
device will be switched on initially.
|
||||||
"""
|
"""
|
||||||
def __init__(self, pin=None, active_high=True):
|
def __init__(self, pin=None, active_high=True, initial_value=False):
|
||||||
self._active_high = active_high
|
self._active_high = active_high
|
||||||
super(OutputDevice, self).__init__(pin)
|
super(OutputDevice, self).__init__(pin)
|
||||||
self._active_state = GPIO.HIGH if active_high else GPIO.LOW
|
self._active_state = GPIO.HIGH if active_high else GPIO.LOW
|
||||||
@@ -42,6 +48,12 @@ class OutputDevice(SourceMixin, GPIODevice):
|
|||||||
# NOTE: catch_warnings isn't thread-safe but hopefully no-one's
|
# NOTE: catch_warnings isn't thread-safe but hopefully no-one's
|
||||||
# messing around with GPIO init within background threads...
|
# messing around with GPIO init within background threads...
|
||||||
with warnings.catch_warnings(record=True) as w:
|
with warnings.catch_warnings(record=True) as w:
|
||||||
|
# This is horrid, but we can't specify initial=None with setup
|
||||||
|
if initial_value is None:
|
||||||
|
GPIO.setup(pin, GPIO.OUT)
|
||||||
|
else:
|
||||||
|
GPIO.setup(pin, GPIO.OUT, initial=
|
||||||
|
[self._inactive_state, self._active_state][bool(initial_value)])
|
||||||
GPIO.setup(pin, GPIO.OUT)
|
GPIO.setup(pin, GPIO.OUT)
|
||||||
# The only warning we want to squash is a RuntimeWarning that is
|
# The only warning we want to squash is a RuntimeWarning that is
|
||||||
# thrown when setting pins 2 or 3. Anything else should be replayed
|
# thrown when setting pins 2 or 3. Anything else should be replayed
|
||||||
@@ -56,6 +68,8 @@ class OutputDevice(SourceMixin, GPIODevice):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
def _write(self, value):
|
def _write(self, value):
|
||||||
|
if not self.active_high:
|
||||||
|
value = not value
|
||||||
try:
|
try:
|
||||||
GPIO.output(self.pin, bool(value))
|
GPIO.output(self.pin, bool(value))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@@ -66,13 +80,13 @@ class OutputDevice(SourceMixin, GPIODevice):
|
|||||||
"""
|
"""
|
||||||
Turns the device on.
|
Turns the device on.
|
||||||
"""
|
"""
|
||||||
self._write(self._active_state)
|
self._write(True)
|
||||||
|
|
||||||
def off(self):
|
def off(self):
|
||||||
"""
|
"""
|
||||||
Turns the device off.
|
Turns the device off.
|
||||||
"""
|
"""
|
||||||
self._write(self._inactive_state)
|
self._write(False)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def value(self):
|
def value(self):
|
||||||
@@ -103,9 +117,9 @@ class DigitalOutputDevice(OutputDevice):
|
|||||||
which uses an optional background thread to handle toggling the device
|
which uses an optional background thread to handle toggling the device
|
||||||
state without further interaction.
|
state without further interaction.
|
||||||
"""
|
"""
|
||||||
def __init__(self, pin=None, active_high=True):
|
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)
|
super(DigitalOutputDevice, self).__init__(pin, active_high, initial_value)
|
||||||
self._lock = Lock()
|
self._lock = Lock()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
@@ -114,11 +128,11 @@ class DigitalOutputDevice(OutputDevice):
|
|||||||
|
|
||||||
def on(self):
|
def on(self):
|
||||||
self._stop_blink()
|
self._stop_blink()
|
||||||
self._write(self._active_state)
|
self._write(True)
|
||||||
|
|
||||||
def off(self):
|
def off(self):
|
||||||
self._stop_blink()
|
self._stop_blink()
|
||||||
self._write(self._inactive_state)
|
self._write(False)
|
||||||
|
|
||||||
def toggle(self):
|
def toggle(self):
|
||||||
"""
|
"""
|
||||||
@@ -167,10 +181,10 @@ class DigitalOutputDevice(OutputDevice):
|
|||||||
def _blink_led(self, on_time, off_time, n):
|
def _blink_led(self, on_time, off_time, n):
|
||||||
iterable = repeat(0) if n is None else repeat(0, n)
|
iterable = repeat(0) if n is None else repeat(0, n)
|
||||||
for i in iterable:
|
for i in iterable:
|
||||||
self._write(self._active_state)
|
self._write(True)
|
||||||
if self._blink_thread.stopping.wait(on_time):
|
if self._blink_thread.stopping.wait(on_time):
|
||||||
break
|
break
|
||||||
self._write(self._inactive_state)
|
self._write(False)
|
||||||
if self._blink_thread.stopping.wait(off_time):
|
if self._blink_thread.stopping.wait(off_time):
|
||||||
break
|
break
|
||||||
|
|
||||||
@@ -241,19 +255,34 @@ class PWMOutputDevice(OutputDevice):
|
|||||||
The GPIO pin which the device is attached to. See :doc:`notes` for
|
The GPIO pin which the device is attached to. See :doc:`notes` for
|
||||||
valid pin numbers.
|
valid pin numbers.
|
||||||
|
|
||||||
|
:param bool active_high:
|
||||||
|
If ``True`` (the default), the :meth:`on` method will set the GPIO to
|
||||||
|
HIGH. If ``False``, the :meth:`on` method will set the GPIO to LOW (the
|
||||||
|
:meth:`off` method always does the opposite).
|
||||||
|
|
||||||
|
:param bool initial_value:
|
||||||
|
If ``0`` (the default), the device's duty cycle will be 0 initially.
|
||||||
|
Other values between 0 and 1 can be specified as an initial duty cycle.
|
||||||
|
Note that ``None`` cannot be specified (unlike the parent class) as
|
||||||
|
there is no way to tell PWM not to alter the state of the pin.
|
||||||
|
|
||||||
:param int frequency:
|
:param int frequency:
|
||||||
The frequency (in Hz) of pulses emitted to drive the device. Defaults
|
The frequency (in Hz) of pulses emitted to drive the device. Defaults
|
||||||
to 100Hz.
|
to 100Hz.
|
||||||
"""
|
"""
|
||||||
def __init__(self, pin=None, active_high=True, frequency=100):
|
def __init__(self, pin=None, active_high=True, initial_value=0, frequency=100):
|
||||||
self._pwm = None
|
self._pwm = None
|
||||||
self._blink_thread = None
|
self._blink_thread = None
|
||||||
|
if not 0 <= initial_value <= 1:
|
||||||
|
raise OutputDeviceError("initial_value must be between 0 and 1")
|
||||||
super(PWMOutputDevice, self).__init__(pin, active_high)
|
super(PWMOutputDevice, self).__init__(pin, active_high)
|
||||||
try:
|
try:
|
||||||
self._pwm = GPIO.PWM(self.pin, frequency)
|
self._pwm = GPIO.PWM(self.pin, frequency)
|
||||||
self._pwm.start(0.0)
|
self._value = initial_value
|
||||||
|
if not active_high:
|
||||||
|
initial_value = 1 - initial_value
|
||||||
|
self._pwm.start(100 * initial_value)
|
||||||
self._frequency = frequency
|
self._frequency = frequency
|
||||||
self._value = 0.0
|
|
||||||
except:
|
except:
|
||||||
self.close()
|
self.close()
|
||||||
raise
|
raise
|
||||||
@@ -271,9 +300,14 @@ class PWMOutputDevice(OutputDevice):
|
|||||||
|
|
||||||
def _read(self):
|
def _read(self):
|
||||||
self._check_open()
|
self._check_open()
|
||||||
return self._value
|
if self.active_high:
|
||||||
|
return self._value
|
||||||
|
else:
|
||||||
|
return 1 - self._value
|
||||||
|
|
||||||
def _write(self, value):
|
def _write(self, value):
|
||||||
|
if not self.active_high:
|
||||||
|
value = 1 - value
|
||||||
if not 0 <= value <= 1:
|
if not 0 <= value <= 1:
|
||||||
raise OutputDeviceError("PWM value must be between 0 and 1")
|
raise OutputDeviceError("PWM value must be between 0 and 1")
|
||||||
try:
|
try:
|
||||||
@@ -289,26 +323,20 @@ class PWMOutputDevice(OutputDevice):
|
|||||||
The duty cycle of the PWM device. 0.0 is off, 1.0 is fully on. Values
|
The duty cycle of the PWM device. 0.0 is off, 1.0 is fully on. Values
|
||||||
in between may be specified for varying levels of power in the device.
|
in between may be specified for varying levels of power in the device.
|
||||||
"""
|
"""
|
||||||
if self.active_high:
|
return self._read()
|
||||||
return self._read()
|
|
||||||
else:
|
|
||||||
return 1 - self._read()
|
|
||||||
|
|
||||||
@value.setter
|
@value.setter
|
||||||
def value(self, value):
|
def value(self, value):
|
||||||
self._stop_blink()
|
self._stop_blink()
|
||||||
if self._active_high:
|
self._write(value)
|
||||||
self._write(value)
|
|
||||||
else:
|
|
||||||
self._write(1 - value)
|
|
||||||
|
|
||||||
def on(self):
|
def on(self):
|
||||||
self._stop_blink()
|
self._stop_blink()
|
||||||
self._write(self._active_state)
|
self._write(1)
|
||||||
|
|
||||||
def off(self):
|
def off(self):
|
||||||
self._stop_blink()
|
self._stop_blink()
|
||||||
self._write(self._inactive_state)
|
self._write(0)
|
||||||
|
|
||||||
def toggle(self):
|
def toggle(self):
|
||||||
"""
|
"""
|
||||||
@@ -386,20 +414,18 @@ class PWMOutputDevice(OutputDevice):
|
|||||||
def _blink_led(
|
def _blink_led(
|
||||||
self, on_time, off_time, fade_in_time, fade_out_time, n, fps=50):
|
self, on_time, off_time, fade_in_time, fade_out_time, n, fps=50):
|
||||||
sequence = []
|
sequence = []
|
||||||
if fade_in_time > 0.0:
|
if fade_in_time > 0:
|
||||||
sequence += [
|
sequence += [
|
||||||
(i * (1 / fps) / fade_in_time, 1 / fps)
|
(i * (1 / fps) / fade_in_time, 1 / fps)
|
||||||
for i in range(int(fps * fade_in_time))
|
for i in range(int(fps * fade_in_time))
|
||||||
]
|
]
|
||||||
sequence.append((1.0, on_time))
|
sequence.append((1, on_time))
|
||||||
if fade_out_time > 0.0:
|
if fade_out_time > 0:
|
||||||
sequence += [
|
sequence += [
|
||||||
(1 - (i * (1 / fps) / fade_out_time), 1 / fps)
|
(1 - (i * (1 / fps) / fade_out_time), 1 / fps)
|
||||||
for i in range(int(fps * fade_out_time))
|
for i in range(int(fps * fade_out_time))
|
||||||
]
|
]
|
||||||
sequence.append((0.0, off_time))
|
sequence.append((0, off_time))
|
||||||
if not self.active_high:
|
|
||||||
sequence = [(1 - value, delay) for (value, delay) in sequence]
|
|
||||||
sequence = (
|
sequence = (
|
||||||
cycle(sequence) if n is None else
|
cycle(sequence) if n is None else
|
||||||
chain.from_iterable(repeat(sequence, n))
|
chain.from_iterable(repeat(sequence, n))
|
||||||
|
|||||||
Reference in New Issue
Block a user