Add forward_device and backward_device to Motor, left_motor and
right_motor to Robot, and ensure all CompositeDevice descendents have a
proper close() method and closed property. Also, add a few more
_check_open calls around the place to make sure GPIODeviceClosed is
properly raised in response to read and writing values.
This commit is contained in:
Dave Jones
2015-11-15 17:05:31 +00:00
parent 382d6e45fc
commit c929b9a53b
3 changed files with 79 additions and 12 deletions

View File

@@ -31,6 +31,10 @@ class LEDBoard(SourceMixin, CompositeDevice):
for led in self.leds: for led in self.leds:
led.close() led.close()
@property
def closed(self):
return all(led.closed for led in self.leds)
@property @property
def leds(self): def leds(self):
""" """
@@ -188,6 +192,10 @@ class TrafficLightsBuzzer(SourceMixin, CompositeDevice):
self.buzzer.close() self.buzzer.close()
self.button.close() self.button.close()
@property
def closed(self):
return all(o.closed for o in self.all)
@property @property
def all(self): def all(self):
""" """
@@ -305,6 +313,24 @@ class Robot(SourceMixin, CompositeDevice):
self._left.close() self._left.close()
self._right.close() self._right.close()
@property
def closed(self):
return self._left.closed and self._right.closed
@property
def left_motor(self):
"""
Returns the `Motor` device representing the robot's left motor.
"""
return self._left
@property
def right_motor(self):
"""
Returns the `Motor` device representing the robot's right motor.
"""
return self._right
@property @property
def value(self): def value(self):
""" """

View File

@@ -82,8 +82,20 @@ class GPIOBase(object):
# safely called from subclasses without worrying whether super-class' # safely called from subclasses without worrying whether super-class'
# have it (which in turn is useful in conjunction with the SourceMixin # have it (which in turn is useful in conjunction with the SourceMixin
# class). # class).
"""
Shut down the device and release all associated resources.
"""
pass pass
@property
def closed(self):
"""
Returns `True` if the device is closed (see the `close` method). Once a
device is closed you can no longer use any other methods or properties
to control or query the device.
"""
return False
def __enter__(self): def __enter__(self):
return self return self
@@ -150,7 +162,8 @@ class CompositeDevice(ValuesMixin, GPIOBase):
Represents a device composed of multiple GPIO devices like simple HATs, Represents a device composed of multiple GPIO devices like simple HATs,
H-bridge motor controllers, robots composed of multiple motors, etc. H-bridge motor controllers, robots composed of multiple motors, etc.
""" """
pass def __repr__(self):
return "<gpiozero.%s object>" % (self.__class__.__name__)
class GPIODevice(ValuesMixin, GPIOBase): class GPIODevice(ValuesMixin, GPIOBase):
@@ -199,15 +212,6 @@ class GPIODevice(ValuesMixin, GPIOBase):
raise GPIODeviceClosed( raise GPIODeviceClosed(
'%s is closed or uninitialized' % self.__class__.__name__) '%s is closed or uninitialized' % self.__class__.__name__)
@property
def closed(self):
"""
Returns `True` if the device is closed (see the `close` method). Once a
device is closed you can no longer use any other methods or properties
to control or query the device.
"""
return self._pin is None
def close(self): def close(self):
""" """
Shut down the device and release all associated resources. Shut down the device and release all associated resources.
@@ -254,6 +258,10 @@ class GPIODevice(ValuesMixin, GPIOBase):
GPIO.remove_event_detect(pin) GPIO.remove_event_detect(pin)
GPIO.cleanup(pin) GPIO.cleanup(pin)
@property
def closed(self):
return self._pin is None
@property @property
def pin(self): def pin(self):
""" """

View File

@@ -62,7 +62,11 @@ class OutputDevice(SourceMixin, GPIODevice):
raise raise
def _write(self, value): def _write(self, value):
GPIO.output(self.pin, bool(value)) try:
GPIO.output(self.pin, bool(value))
except ValueError:
self._check_open()
raise
def on(self): def on(self):
""" """
@@ -236,12 +240,17 @@ class PWMOutputDevice(DigitalOutputDevice):
super(PWMOutputDevice, self).close() super(PWMOutputDevice, self).close()
def _read(self): def _read(self):
self._check_open()
return self._value return self._value
def _write(self, value): def _write(self, 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")
self._pwm.ChangeDutyCycle(value * 100) try:
self._pwm.ChangeDutyCycle(value * 100)
except AttributeError:
self._check_open()
raise
self._value = value self._value = value
@property @property
@@ -385,6 +394,30 @@ class Motor(SourceMixin, CompositeDevice):
self._forward = PWMOutputDevice(forward) self._forward = PWMOutputDevice(forward)
self._backward = PWMOutputDevice(backward) self._backward = PWMOutputDevice(backward)
def close(self):
self._forward.close()
self._backward.close()
@property
def closed(self):
return self._forward.closed and self._backward.closed
@property
def forward_device(self):
"""
Returns the `PWMOutputDevice` representing the forward pin of the motor
controller.
"""
return self._forward
@property
def backward_device(self):
"""
Returns the `PWMOutputDevice` representing the backward pin of the
motor controller.
"""
return self._backward
@property @property
def value(self): def value(self):
""" """