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
with warnings.catch_warnings(record=True) as w: # messing around with GPIO init within background threads...
GPIO.setup(pin, GPIO.IN, pull) with warnings.catch_warnings(record=True) as w:
# The only warning we want to squash is a RuntimeWarning that is thrown GPIO.setup(pin, GPIO.IN, pull)
# when setting pins 2 or 3. Anything else should be replayed # The only warning we want to squash is a RuntimeWarning that is
for warning in w: # thrown when setting pins 2 or 3. Anything else should be replayed
if warning.category != RuntimeWarning or pin not in (2, 3): for warning in w:
warnings.showwarning( if warning.category != RuntimeWarning or pin not in (2, 3):
warning.message, warning.category, warning.filename, warnings.showwarning(
warning.lineno, warning.file, warning.line warning.message, warning.category, warning.filename,
) warning.lineno, warning.file, warning.line
)
except:
self.close()
raise
@property @property
def pull_up(self): def pull_up(self):
@@ -238,13 +242,17 @@ 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)
# Yes, that's really the default bouncetime in RPi.GPIO... try:
GPIO.add_event_detect( # Yes, that's really the default bouncetime in RPi.GPIO...
self.pin, GPIO.BOTH, callback=self._fire_events, GPIO.add_event_detect(
bouncetime=-666 if bounce_time is None else int(bounce_time * 1000) self.pin, GPIO.BOTH, callback=self._fire_events,
) bouncetime=-666 if bounce_time is None else int(bounce_time * 1000)
# Call _fire_events once to set initial state of events )
super(DigitalInputDevice, self)._fire_events() # Call _fire_events once to set initial state of 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)
self._queue = GPIOQueue(self, queue_len, sample_wait, partial) try:
self.threshold = float(threshold) self._queue = GPIOQueue(self, queue_len, sample_wait, partial)
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
) )
self._queue.start() try:
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
) )
self._charge_time_limit = charge_time_limit try:
self._charged = Event() self._charge_time_limit = charge_time_limit
GPIO.add_event_detect( self._charged = Event()
self.pin, GPIO.RISING, lambda channel: self._charged.set() GPIO.add_event_detect(
) 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
with warnings.catch_warnings(record=True) as w: # messing around with GPIO init within background threads...
GPIO.setup(pin, GPIO.OUT) with warnings.catch_warnings(record=True) as w:
# The only warning we want to squash is a RuntimeWarning that is thrown GPIO.setup(pin, GPIO.OUT)
# when setting pins 2 or 3. Anything else should be replayed # The only warning we want to squash is a RuntimeWarning that is
for warning in w: # thrown when setting pins 2 or 3. Anything else should be replayed
if warning.category != RuntimeWarning or pin not in (2, 3): for warning in w:
warnings.showwarning( if warning.category != RuntimeWarning or pin not in (2, 3):
warning.message, warning.category, warning.filename, warnings.showwarning(
warning.lineno, warning.file, warning.line warning.message, warning.category, warning.filename,
) 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)
self._frequency = 100 try:
self._pwm = GPIO.PWM(self._pin, self._frequency) self._frequency = 100
self._pwm.start(0) self._pwm = GPIO.PWM(self._pin, self._frequency)
self._min_pwm = 0 self._pwm.start(0)
self._max_pwm = 1 self._min_pwm = 0
self.value = 0 self._max_pwm = 1
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