Merge pull request #60 from waveform80/safe-fail-init

Fix #50
This commit is contained in:
Ben Nuttall
2015-10-12 14:52:11 +01:00
2 changed files with 79 additions and 51 deletions

View File

@@ -63,18 +63,22 @@ class InputDevice(GPIODevice):
self._inactive_state = GPIO.HIGH if pull_up else GPIO.LOW self._inactive_state = GPIO.HIGH if pull_up else GPIO.LOW
pull = GPIO.PUD_UP if pull_up else GPIO.PUD_DOWN pull = GPIO.PUD_UP if pull_up else GPIO.PUD_DOWN
# NOTE: catch_warnings isn't thread-safe but hopefully no-one's messing try:
# around with GPIO init within background threads... # NOTE: catch_warnings isn't thread-safe but hopefully no-one's
# messing around with GPIO init within background threads...
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:
GPIO.setup(pin, GPIO.IN, pull) GPIO.setup(pin, GPIO.IN, pull)
# The only warning we want to squash is a RuntimeWarning that is thrown # The only warning we want to squash is a RuntimeWarning that is
# when setting pins 2 or 3. Anything else should be replayed # thrown when setting pins 2 or 3. Anything else should be replayed
for warning in w: for warning in w:
if warning.category != RuntimeWarning or pin not in (2, 3): if warning.category != RuntimeWarning or pin not in (2, 3):
warnings.showwarning( warnings.showwarning(
warning.message, warning.category, warning.filename, warning.message, warning.category, warning.filename,
warning.lineno, warning.file, warning.line warning.lineno, warning.file, warning.line
) )
except:
self.close()
raise
@property @property
def pull_up(self): def pull_up(self):
@@ -238,6 +242,7 @@ class DigitalInputDevice(WaitableInputDevice):
""" """
def __init__(self, pin=None, pull_up=False, bounce_time=None): def __init__(self, pin=None, pull_up=False, bounce_time=None):
super(DigitalInputDevice, self).__init__(pin, pull_up) super(DigitalInputDevice, self).__init__(pin, pull_up)
try:
# Yes, that's really the default bouncetime in RPi.GPIO... # Yes, that's really the default bouncetime in RPi.GPIO...
GPIO.add_event_detect( GPIO.add_event_detect(
self.pin, GPIO.BOTH, callback=self._fire_events, self.pin, GPIO.BOTH, callback=self._fire_events,
@@ -245,6 +250,9 @@ class DigitalInputDevice(WaitableInputDevice):
) )
# Call _fire_events once to set initial state of events # Call _fire_events once to set initial state of events
super(DigitalInputDevice, self)._fire_events() super(DigitalInputDevice, self)._fire_events()
except:
self.close()
raise
def _fire_events(self, channel): def _fire_events(self, channel):
super(DigitalInputDevice, self)._fire_events() super(DigitalInputDevice, self)._fire_events()
@@ -287,13 +295,19 @@ class SmoothedInputDevice(WaitableInputDevice):
queue_len=5, sample_wait=0.0, partial=False): queue_len=5, sample_wait=0.0, partial=False):
self._queue = None self._queue = None
super(SmoothedInputDevice, self).__init__(pin, pull_up) super(SmoothedInputDevice, self).__init__(pin, pull_up)
try:
self._queue = GPIOQueue(self, queue_len, sample_wait, partial) self._queue = GPIOQueue(self, queue_len, sample_wait, partial)
self.threshold = float(threshold) self.threshold = float(threshold)
except:
self.close()
raise
def close(self): def close(self):
try: try:
self._queue.stop() self._queue.stop()
except AttributeError: except AttributeError:
# If the queue isn't initialized (it's None) ignore the error
# because we're trying to close anyway
if self._queue is not None: if self._queue is not None:
raise raise
except RuntimeError: except RuntimeError:
@@ -398,7 +412,11 @@ class MotionSensor(SmoothedInputDevice):
pin, pull_up=False, threshold=threshold, pin, pull_up=False, threshold=threshold,
queue_len=queue_len, sample_wait=1 / sample_rate, partial=partial queue_len=queue_len, sample_wait=1 / sample_rate, partial=partial
) )
try:
self._queue.start() self._queue.start()
except:
self.close()
raise
motion_detected = _alias('is_active') motion_detected = _alias('is_active')
@@ -425,12 +443,16 @@ class LightSensor(SmoothedInputDevice):
pin, pull_up=False, threshold=threshold, pin, pull_up=False, threshold=threshold,
queue_len=queue_len, sample_wait=0.0, partial=partial queue_len=queue_len, sample_wait=0.0, partial=partial
) )
try:
self._charge_time_limit = charge_time_limit self._charge_time_limit = charge_time_limit
self._charged = Event() self._charged = Event()
GPIO.add_event_detect( GPIO.add_event_detect(
self.pin, GPIO.RISING, lambda channel: self._charged.set() self.pin, GPIO.RISING, lambda channel: self._charged.set()
) )
self._queue.start() self._queue.start()
except:
self.close()
raise
@property @property
def charge_time_limit(self): def charge_time_limit(self):

View File

@@ -22,18 +22,22 @@ class OutputDevice(GPIODevice):
""" """
def __init__(self, pin=None): def __init__(self, pin=None):
super(OutputDevice, self).__init__(pin) super(OutputDevice, self).__init__(pin)
# NOTE: catch_warnings isn't thread-safe but hopefully no-one's messing try:
# around with GPIO init within background threads... # NOTE: catch_warnings isn't thread-safe but hopefully no-one's
# messing around with GPIO init within background threads...
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:
GPIO.setup(pin, GPIO.OUT) GPIO.setup(pin, GPIO.OUT)
# The only warning we want to squash is a RuntimeWarning that is thrown # The only warning we want to squash is a RuntimeWarning that is
# when setting pins 2 or 3. Anything else should be replayed # thrown when setting pins 2 or 3. Anything else should be replayed
for warning in w: for warning in w:
if warning.category != RuntimeWarning or pin not in (2, 3): if warning.category != RuntimeWarning or pin not in (2, 3):
warnings.showwarning( warnings.showwarning(
warning.message, warning.category, warning.filename, warning.message, warning.category, warning.filename,
warning.lineno, warning.file, warning.line warning.lineno, warning.file, warning.line
) )
except:
self.close()
raise
def on(self): def on(self):
""" """
@@ -158,12 +162,16 @@ class PWMOutputDevice(DigitalOutputDevice):
""" """
def __init__(self, pin=None): def __init__(self, pin=None):
super(PWMOutputDevice, self).__init__(pin) super(PWMOutputDevice, self).__init__(pin)
try:
self._frequency = 100 self._frequency = 100
self._pwm = GPIO.PWM(self._pin, self._frequency) self._pwm = GPIO.PWM(self._pin, self._frequency)
self._pwm.start(0) self._pwm.start(0)
self._min_pwm = 0 self._min_pwm = 0
self._max_pwm = 1 self._max_pwm = 1
self.value = 0 self.value = 0
except:
self.close()
raise
def on(self): def on(self):
""" """
@@ -195,13 +203,11 @@ class PWMOutputDevice(DigitalOutputDevice):
def value(self, n): def value(self, n):
_min = self._min_pwm _min = self._min_pwm
_max = self._max_pwm _max = self._max_pwm
if _min <= n <= _max: if not _min <= n <= _max:
dc = n * 100 raise OutputDeviceError(
else:
raise GPIODeviceError(
"Value must be between %s and %s" % (_min, _max) "Value must be between %s and %s" % (_min, _max)
) )
self._pwm.ChangeDutyCycle(dc) self._pwm.ChangeDutyCycle(n * 100)
self._value = n self._value = n