diff --git a/gpiozero/boards.py b/gpiozero/boards.py index 43f1309..21fa833 100644 --- a/gpiozero/boards.py +++ b/gpiozero/boards.py @@ -31,6 +31,10 @@ class LEDBoard(SourceMixin, CompositeDevice): for led in self.leds: led.close() + @property + def closed(self): + return all(led.closed for led in self.leds) + @property def leds(self): """ @@ -188,6 +192,10 @@ class TrafficLightsBuzzer(SourceMixin, CompositeDevice): self.buzzer.close() self.button.close() + @property + def closed(self): + return all(o.closed for o in self.all) + @property def all(self): """ @@ -305,6 +313,24 @@ class Robot(SourceMixin, CompositeDevice): self._left.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 def value(self): """ diff --git a/gpiozero/devices.py b/gpiozero/devices.py index 75b759a..529a339 100644 --- a/gpiozero/devices.py +++ b/gpiozero/devices.py @@ -82,8 +82,20 @@ class GPIOBase(object): # safely called from subclasses without worrying whether super-class' # have it (which in turn is useful in conjunction with the SourceMixin # class). + """ + Shut down the device and release all associated resources. + """ 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): return self @@ -150,7 +162,8 @@ class CompositeDevice(ValuesMixin, GPIOBase): Represents a device composed of multiple GPIO devices like simple HATs, H-bridge motor controllers, robots composed of multiple motors, etc. """ - pass + def __repr__(self): + return "" % (self.__class__.__name__) class GPIODevice(ValuesMixin, GPIOBase): @@ -199,15 +212,6 @@ class GPIODevice(ValuesMixin, GPIOBase): raise GPIODeviceClosed( '%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): """ Shut down the device and release all associated resources. @@ -254,6 +258,10 @@ class GPIODevice(ValuesMixin, GPIOBase): GPIO.remove_event_detect(pin) GPIO.cleanup(pin) + @property + def closed(self): + return self._pin is None + @property def pin(self): """ diff --git a/gpiozero/output_devices.py b/gpiozero/output_devices.py index 920298a..1417ecc 100644 --- a/gpiozero/output_devices.py +++ b/gpiozero/output_devices.py @@ -62,7 +62,11 @@ class OutputDevice(SourceMixin, GPIODevice): raise 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): """ @@ -236,12 +240,17 @@ class PWMOutputDevice(DigitalOutputDevice): super(PWMOutputDevice, self).close() def _read(self): + self._check_open() return self._value def _write(self, value): if not 0 <= value <= 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 @property @@ -385,6 +394,30 @@ class Motor(SourceMixin, CompositeDevice): self._forward = PWMOutputDevice(forward) 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 def value(self): """