Merge pull request #152 from waveform80/pwm-heritage

Fix #121
This commit is contained in:
Dave Jones
2016-01-31 13:48:07 +00:00
5 changed files with 141 additions and 65 deletions

View File

@@ -17,7 +17,7 @@ digraph classes {
DigitalOutputDevice->OutputDevice;
LED->DigitalOutputDevice;
Buzzer->DigitalOutputDevice;
PWMOutputDevice->DigitalOutputDevice;
PWMOutputDevice->OutputDevice;
PWMLED->PWMOutputDevice;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

@@ -4,105 +4,105 @@
<!-- Generated by graphviz version 2.36.0 (20140111.2315)
-->
<!-- Title: classes Pages: 1 -->
<svg width="569pt" height="332pt"
viewBox="0.00 0.00 569.00 332.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="563pt" height="332pt"
viewBox="0.00 0.00 563.00 332.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 328)">
<title>classes</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-328 565,-328 565,4 -4,4"/>
<polygon fill="white" stroke="none" points="-4,4 -4,-328 559,-328 559,4 -4,4"/>
<!-- InputDevice -->
<g id="node1" class="node"><title>InputDevice</title>
<polygon fill="#2980b9" stroke="#2980b9" points="338.5,-252 265.5,-252 265.5,-216 338.5,-216 338.5,-252"/>
<text text-anchor="middle" x="302" y="-231.5" font-family="Sans" font-size="10.00" fill="#ffffff">InputDevice</text>
<polygon fill="#2980b9" stroke="#2980b9" points="346.5,-252 273.5,-252 273.5,-216 346.5,-216 346.5,-252"/>
<text text-anchor="middle" x="310" y="-231.5" font-family="Sans" font-size="10.00" fill="#ffffff">InputDevice</text>
</g>
<!-- GPIODevice -->
<g id="node2" class="node"><title>GPIODevice</title>
<polygon fill="#2980b9" stroke="#2980b9" points="274,-324 202,-324 202,-288 274,-288 274,-324"/>
<text text-anchor="middle" x="238" y="-303.5" font-family="Sans" font-size="10.00" fill="#ffffff">GPIODevice</text>
<polygon fill="#2980b9" stroke="#2980b9" points="290,-324 218,-324 218,-288 290,-288 290,-324"/>
<text text-anchor="middle" x="254" y="-303.5" font-family="Sans" font-size="10.00" fill="#ffffff">GPIODevice</text>
</g>
<!-- InputDevice&#45;&gt;GPIODevice -->
<g id="edge1" class="edge"><title>InputDevice&#45;&gt;GPIODevice</title>
<path fill="none" stroke="black" d="M286.18,-252.303C278.43,-260.78 268.961,-271.136 260.476,-280.417"/>
<polygon fill="black" stroke="black" points="257.803,-278.154 253.638,-287.896 262.969,-282.877 257.803,-278.154"/>
<path fill="none" stroke="black" d="M296.157,-252.303C289.511,-260.611 281.422,-270.723 274.113,-279.859"/>
<polygon fill="black" stroke="black" points="271.197,-277.901 267.683,-287.896 276.664,-282.273 271.197,-277.901"/>
</g>
<!-- WaitableInputDevice -->
<g id="node3" class="node"><title>WaitableInputDevice</title>
<polygon fill="#2980b9" stroke="#2980b9" points="374.5,-180 261.5,-180 261.5,-144 374.5,-144 374.5,-180"/>
<text text-anchor="middle" x="318" y="-159.5" font-family="Sans" font-size="10.00" fill="#ffffff">WaitableInputDevice</text>
<polygon fill="#2980b9" stroke="#2980b9" points="382.5,-180 269.5,-180 269.5,-144 382.5,-144 382.5,-180"/>
<text text-anchor="middle" x="326" y="-159.5" font-family="Sans" font-size="10.00" fill="#ffffff">WaitableInputDevice</text>
</g>
<!-- WaitableInputDevice&#45;&gt;InputDevice -->
<g id="edge2" class="edge"><title>WaitableInputDevice&#45;&gt;InputDevice</title>
<path fill="none" stroke="black" d="M314.045,-180.303C312.282,-188.017 310.163,-197.288 308.197,-205.888"/>
<polygon fill="black" stroke="black" points="304.726,-205.367 305.91,-215.896 311.55,-206.927 304.726,-205.367"/>
<path fill="none" stroke="black" d="M322.045,-180.303C320.282,-188.017 318.163,-197.288 316.197,-205.888"/>
<polygon fill="black" stroke="black" points="312.726,-205.367 313.91,-215.896 319.55,-206.927 312.726,-205.367"/>
</g>
<!-- DigitalInputDevice -->
<g id="node4" class="node"><title>DigitalInputDevice</title>
<polygon fill="#2980b9" stroke="#2980b9" points="369.5,-108 266.5,-108 266.5,-72 369.5,-72 369.5,-108"/>
<text text-anchor="middle" x="318" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">DigitalInputDevice</text>
<polygon fill="#2980b9" stroke="#2980b9" points="363.5,-108 260.5,-108 260.5,-72 363.5,-72 363.5,-108"/>
<text text-anchor="middle" x="312" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">DigitalInputDevice</text>
</g>
<!-- DigitalInputDevice&#45;&gt;WaitableInputDevice -->
<g id="edge3" class="edge"><title>DigitalInputDevice&#45;&gt;WaitableInputDevice</title>
<path fill="none" stroke="black" d="M318,-108.303C318,-116.017 318,-125.288 318,-133.888"/>
<polygon fill="black" stroke="black" points="314.5,-133.896 318,-143.896 321.5,-133.896 314.5,-133.896"/>
<path fill="none" stroke="black" d="M315.461,-108.303C317.003,-116.017 318.858,-125.288 320.578,-133.888"/>
<polygon fill="black" stroke="black" points="317.186,-134.776 322.579,-143.896 324.05,-133.403 317.186,-134.776"/>
</g>
<!-- SmoothedInputDevice -->
<g id="node5" class="node"><title>SmoothedInputDevice</title>
<polygon fill="#2980b9" stroke="#2980b9" points="510.5,-108 387.5,-108 387.5,-72 510.5,-72 510.5,-108"/>
<text text-anchor="middle" x="449" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">SmoothedInputDevice</text>
<polygon fill="#2980b9" stroke="#2980b9" points="504.5,-108 381.5,-108 381.5,-72 504.5,-72 504.5,-108"/>
<text text-anchor="middle" x="443" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">SmoothedInputDevice</text>
</g>
<!-- SmoothedInputDevice&#45;&gt;WaitableInputDevice -->
<g id="edge4" class="edge"><title>SmoothedInputDevice&#45;&gt;WaitableInputDevice</title>
<path fill="none" stroke="black" d="M416.954,-108.124C399.508,-117.446 377.735,-129.081 359.057,-139.061"/>
<polygon fill="black" stroke="black" points="357.34,-136.01 350.169,-143.81 360.639,-142.184 357.34,-136.01"/>
<path fill="none" stroke="black" d="M414.379,-108.124C399.081,-117.276 380.057,-128.658 363.582,-138.515"/>
<polygon fill="black" stroke="black" points="361.516,-135.673 354.731,-143.81 365.11,-141.68 361.516,-135.673"/>
</g>
<!-- Button -->
<g id="node6" class="node"><title>Button</title>
<polygon fill="#2980b9" stroke="#2980b9" points="345,-36 291,-36 291,-0 345,-0 345,-36"/>
<text text-anchor="middle" x="318" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">Button</text>
<polygon fill="#2980b9" stroke="#2980b9" points="339,-36 285,-36 285,-0 339,-0 339,-36"/>
<text text-anchor="middle" x="312" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">Button</text>
</g>
<!-- Button&#45;&gt;DigitalInputDevice -->
<g id="edge5" class="edge"><title>Button&#45;&gt;DigitalInputDevice</title>
<path fill="none" stroke="black" d="M318,-36.3034C318,-44.0173 318,-53.2875 318,-61.8876"/>
<polygon fill="black" stroke="black" points="314.5,-61.8956 318,-71.8957 321.5,-61.8957 314.5,-61.8956"/>
<path fill="none" stroke="black" d="M312,-36.3034C312,-44.0173 312,-53.2875 312,-61.8876"/>
<polygon fill="black" stroke="black" points="308.5,-61.8956 312,-71.8957 315.5,-61.8957 308.5,-61.8956"/>
</g>
<!-- MotionSensor -->
<g id="node7" class="node"><title>MotionSensor</title>
<polygon fill="#2980b9" stroke="#2980b9" points="468.5,-36 385.5,-36 385.5,-0 468.5,-0 468.5,-36"/>
<text text-anchor="middle" x="427" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">MotionSensor</text>
<polygon fill="#2980b9" stroke="#2980b9" points="462.5,-36 379.5,-36 379.5,-0 462.5,-0 462.5,-36"/>
<text text-anchor="middle" x="421" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">MotionSensor</text>
</g>
<!-- MotionSensor&#45;&gt;SmoothedInputDevice -->
<g id="edge6" class="edge"><title>MotionSensor&#45;&gt;SmoothedInputDevice</title>
<path fill="none" stroke="black" d="M432.438,-36.3034C434.889,-44.1021 437.84,-53.4915 440.568,-62.1708"/>
<polygon fill="black" stroke="black" points="437.287,-63.4051 443.624,-71.8957 443.965,-61.3063 437.287,-63.4051"/>
<path fill="none" stroke="black" d="M426.438,-36.3034C428.889,-44.1021 431.84,-53.4915 434.568,-62.1708"/>
<polygon fill="black" stroke="black" points="431.287,-63.4051 437.624,-71.8957 437.965,-61.3063 431.287,-63.4051"/>
</g>
<!-- LightSensor -->
<g id="node8" class="node"><title>LightSensor</title>
<polygon fill="#2980b9" stroke="#2980b9" points="561,-36 487,-36 487,-0 561,-0 561,-36"/>
<text text-anchor="middle" x="524" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">LightSensor</text>
<polygon fill="#2980b9" stroke="#2980b9" points="555,-36 481,-36 481,-0 555,-0 555,-36"/>
<text text-anchor="middle" x="518" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">LightSensor</text>
</g>
<!-- LightSensor&#45;&gt;SmoothedInputDevice -->
<g id="edge7" class="edge"><title>LightSensor&#45;&gt;SmoothedInputDevice</title>
<path fill="none" stroke="black" d="M505.461,-36.3034C496.197,-44.9497 484.838,-55.5514 474.743,-64.973"/>
<polygon fill="black" stroke="black" points="472.249,-62.5137 467.326,-71.8957 477.025,-67.6312 472.249,-62.5137"/>
<path fill="none" stroke="black" d="M499.461,-36.3034C490.197,-44.9497 478.838,-55.5514 468.743,-64.973"/>
<polygon fill="black" stroke="black" points="466.249,-62.5137 461.326,-71.8957 471.025,-67.6312 466.249,-62.5137"/>
</g>
<!-- OutputDevice -->
<g id="node9" class="node"><title>OutputDevice</title>
<polygon fill="#2980b9" stroke="#2980b9" points="216,-252 134,-252 134,-216 216,-216 216,-252"/>
<text text-anchor="middle" x="175" y="-231.5" font-family="Sans" font-size="10.00" fill="#ffffff">OutputDevice</text>
<polygon fill="#2980b9" stroke="#2980b9" points="240,-252 158,-252 158,-216 240,-216 240,-252"/>
<text text-anchor="middle" x="199" y="-231.5" font-family="Sans" font-size="10.00" fill="#ffffff">OutputDevice</text>
</g>
<!-- OutputDevice&#45;&gt;GPIODevice -->
<g id="edge8" class="edge"><title>OutputDevice&#45;&gt;GPIODevice</title>
<path fill="none" stroke="black" d="M190.573,-252.303C198.202,-260.78 207.523,-271.136 215.876,-280.417"/>
<polygon fill="black" stroke="black" points="213.315,-282.804 222.606,-287.896 218.518,-278.121 213.315,-282.804"/>
<path fill="none" stroke="black" d="M212.596,-252.303C219.123,-260.611 227.068,-270.723 234.247,-279.859"/>
<polygon fill="black" stroke="black" points="231.631,-282.195 240.561,-287.896 237.135,-277.87 231.631,-282.195"/>
</g>
<!-- DigitalOutputDevice -->
<g id="node10" class="node"><title>DigitalOutputDevice</title>
<polygon fill="#2980b9" stroke="#2980b9" points="170,-180 58,-180 58,-144 170,-144 170,-180"/>
<text text-anchor="middle" x="114" y="-159.5" font-family="Sans" font-size="10.00" fill="#ffffff">DigitalOutputDevice</text>
<polygon fill="#2980b9" stroke="#2980b9" points="129,-180 17,-180 17,-144 129,-144 129,-180"/>
<text text-anchor="middle" x="73" y="-159.5" font-family="Sans" font-size="10.00" fill="#ffffff">DigitalOutputDevice</text>
</g>
<!-- DigitalOutputDevice&#45;&gt;OutputDevice -->
<g id="edge9" class="edge"><title>DigitalOutputDevice&#45;&gt;OutputDevice</title>
<path fill="none" stroke="black" d="M129.079,-180.303C136.392,-188.695 145.31,-198.93 153.335,-208.139"/>
<polygon fill="black" stroke="black" points="150.886,-210.656 160.095,-215.896 156.164,-206.057 150.886,-210.656"/>
<path fill="none" stroke="black" d="M103.823,-180.124C120.45,-189.361 141.165,-200.869 159.019,-210.788"/>
<polygon fill="black" stroke="black" points="157.617,-214.013 168.058,-215.81 161.017,-207.894 157.617,-214.013"/>
</g>
<!-- LED -->
<g id="node11" class="node"><title>LED</title>
@@ -111,8 +111,8 @@
</g>
<!-- LED&#45;&gt;DigitalOutputDevice -->
<g id="edge10" class="edge"><title>LED&#45;&gt;DigitalOutputDevice</title>
<path fill="none" stroke="black" d="M48.5056,-108.303C59.4625,-117.119 72.9459,-127.968 84.8249,-137.526"/>
<polygon fill="black" stroke="black" points="82.7565,-140.354 92.7418,-143.896 87.1446,-134.9 82.7565,-140.354"/>
<path fill="none" stroke="black" d="M38.3708,-108.303C43.7185,-116.441 50.2043,-126.311 56.1106,-135.299"/>
<polygon fill="black" stroke="black" points="53.3432,-137.461 61.76,-143.896 59.1932,-133.616 53.3432,-137.461"/>
</g>
<!-- Buzzer -->
<g id="node12" class="node"><title>Buzzer</title>
@@ -121,28 +121,28 @@
</g>
<!-- Buzzer&#45;&gt;DigitalOutputDevice -->
<g id="edge11" class="edge"><title>Buzzer&#45;&gt;DigitalOutputDevice</title>
<path fill="none" stroke="black" d="M102.708,-108.303C104.361,-116.017 106.347,-125.288 108.19,-133.888"/>
<polygon fill="black" stroke="black" points="104.817,-134.851 110.335,-143.896 111.662,-133.384 104.817,-134.851"/>
<path fill="none" stroke="black" d="M92.573,-108.303C89.6449,-116.187 86.113,-125.696 82.8601,-134.454"/>
<polygon fill="black" stroke="black" points="79.554,-133.303 79.353,-143.896 86.116,-135.74 79.554,-133.303"/>
</g>
<!-- PWMOutputDevice -->
<g id="node13" class="node"><title>PWMOutputDevice</title>
<polygon fill="#2980b9" stroke="#2980b9" points="248,-108 144,-108 144,-72 248,-72 248,-108"/>
<text text-anchor="middle" x="196" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">PWMOutputDevice</text>
<polygon fill="#2980b9" stroke="#2980b9" points="251,-180 147,-180 147,-144 251,-144 251,-180"/>
<text text-anchor="middle" x="199" y="-159.5" font-family="Sans" font-size="10.00" fill="#ffffff">PWMOutputDevice</text>
</g>
<!-- PWMOutputDevice&#45;&gt;DigitalOutputDevice -->
<g id="edge12" class="edge"><title>PWMOutputDevice&#45;&gt;DigitalOutputDevice</title>
<path fill="none" stroke="black" d="M175.73,-108.303C165.502,-117.035 152.939,-127.76 141.822,-137.25"/>
<polygon fill="black" stroke="black" points="139.37,-134.741 134.037,-143.896 143.915,-140.065 139.37,-134.741"/>
<!-- PWMOutputDevice&#45;&gt;OutputDevice -->
<g id="edge12" class="edge"><title>PWMOutputDevice&#45;&gt;OutputDevice</title>
<path fill="none" stroke="black" d="M199,-180.303C199,-188.017 199,-197.288 199,-205.888"/>
<polygon fill="black" stroke="black" points="195.5,-205.896 199,-215.896 202.5,-205.896 195.5,-205.896"/>
</g>
<!-- PWMLED -->
<g id="node14" class="node"><title>PWMLED</title>
<polygon fill="#2980b9" stroke="#2980b9" points="225,-36 167,-36 167,-0 225,-0 225,-36"/>
<text text-anchor="middle" x="196" y="-15.5" font-family="Sans" font-size="10.00" fill="#ffffff">PWMLED</text>
<polygon fill="#2980b9" stroke="#2980b9" points="228,-108 170,-108 170,-72 228,-72 228,-108"/>
<text text-anchor="middle" x="199" y="-87.5" font-family="Sans" font-size="10.00" fill="#ffffff">PWMLED</text>
</g>
<!-- PWMLED&#45;&gt;PWMOutputDevice -->
<g id="edge13" class="edge"><title>PWMLED&#45;&gt;PWMOutputDevice</title>
<path fill="none" stroke="black" d="M196,-36.3034C196,-44.0173 196,-53.2875 196,-61.8876"/>
<polygon fill="black" stroke="black" points="192.5,-61.8956 196,-71.8957 199.5,-61.8957 192.5,-61.8956"/>
<path fill="none" stroke="black" d="M199,-108.303C199,-116.017 199,-125.288 199,-133.888"/>
<polygon fill="black" stroke="black" points="195.5,-133.896 199,-143.896 202.5,-133.896 195.5,-133.896"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@@ -8,7 +8,7 @@ from __future__ import (
import warnings
from time import sleep
from threading import Lock
from itertools import repeat
from itertools import repeat, cycle, chain
from RPi import GPIO
@@ -136,19 +136,19 @@ class DigitalOutputDevice(OutputDevice):
Make the device turn on and off repeatedly.
:param float on_time:
Number of seconds on
Number of seconds on. Defaults to 1 second.
:param float off_time:
Number of seconds off
Number of seconds off. Defaults to 1 second.
:param int n:
Number of times to blink; ``None`` means forever
Number of times to blink; ``None`` (the default) means forever.
:param bool background:
If ``True``, start a background thread to continue blinking and
return immediately. If ``False``, only return when the blink is
finished (warning: the default value of *n* will result in this
method never returning).
If ``True`` (the default), start a background thread to continue
blinking and return immediately. If ``False``, only return when the
blink is finished (warning: the default value of *n* will result in
this method never returning).
"""
self._stop_blink()
self._blink_thread = GPIOThread(
@@ -233,7 +233,7 @@ class Buzzer(DigitalOutputDevice):
Buzzer.beep = Buzzer.blink
class PWMOutputDevice(DigitalOutputDevice):
class PWMOutputDevice(OutputDevice):
"""
Generic output device configured for pulse-width modulation (PWM).
@@ -247,6 +247,7 @@ class PWMOutputDevice(DigitalOutputDevice):
"""
def __init__(self, pin=None, frequency=100):
self._pwm = None
self._blink_thread = None
super(PWMOutputDevice, self).__init__(pin)
try:
self._pwm = GPIO.PWM(self.pin, frequency)
@@ -295,6 +296,14 @@ class PWMOutputDevice(DigitalOutputDevice):
self._stop_blink()
self._write(value)
def on(self):
self._stop_blink()
self._write(self._active_state)
def off(self):
self._stop_blink()
self._write(self._inactive_state)
def toggle(self):
"""
Toggle the state of the device. If the device is currently off
@@ -302,6 +311,7 @@ class PWMOutputDevice(DigitalOutputDevice):
1.0). If the device has a duty cycle (:attr:`value`) of 0.1, this will
toggle it to 0.9, and so on.
"""
self._stop_blink()
self.value = 1.0 - self.value
@property
@@ -325,6 +335,72 @@ class PWMOutputDevice(DigitalOutputDevice):
self._pwm.ChangeFrequency(value)
self._frequency = value
def blink(
self, on_time=1, off_time=1, fade_in_time=0, fade_out_time=0,
n=None, background=True):
"""
Make the device turn on and off repeatedly.
:param float on_time:
Number of seconds on. Defaults to 1 second.
:param float off_time:
Number of seconds off. Defaults to 1 second.
:param float fade_in_time:
Number of seconds to spend fading in. Defaults to 0.
:param float fade_out_time:
Number of seconds to spend fading out. Defaults to 0.
:param int n:
Number of times to blink; ``None`` (the default) means forever.
:param bool background:
If ``True`` (the default), start a background thread to continue
blinking and return immediately. If ``False``, only return when the
blink is finished (warning: the default value of *n* will result in
this method never returning).
"""
self._stop_blink()
self._blink_thread = GPIOThread(
target=self._blink_led,
args=(on_time, off_time, fade_in_time, fade_out_time, n)
)
self._blink_thread.start()
if not background:
self._blink_thread.join()
self._blink_thread = None
def _stop_blink(self):
if self._blink_thread:
self._blink_thread.stop()
self._blink_thread = None
def _blink_led(
self, on_time, off_time, fade_in_time, fade_out_time, n, fps=50):
sequence = []
if fade_in_time > 0.0:
sequence += [
(i * (1 / fps) / fade_in_time, 1 / fps)
for i in range(int(50 * fade_in_time))
]
sequence.append((1.0, on_time))
if fade_out_time > 0.0:
sequence += [
(1 - (i * (1 / fps) / fade_out_time), 1 / fps)
for i in range(int(50 * fade_out_time))
]
sequence.append((0.0, off_time))
sequence = (
cycle(sequence) if n is None else
chain.from_iterable(repeat(sequence, n))
)
for value, delay in sequence:
self._write(value)
if self._blink_thread.stopping.wait(delay):
break
class PWMLED(PWMOutputDevice):
"""