From 6d29aaa5903c39ad617d31db9f387c1d2c35e662 Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Mon, 21 Sep 2015 15:28:01 +0100 Subject: [PATCH 01/12] Implement common add-on boards, re: #17 --- gpiozero/boards.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 gpiozero/boards.py diff --git a/gpiozero/boards.py b/gpiozero/boards.py new file mode 100644 index 0000000..ebdd7ae --- /dev/null +++ b/gpiozero/boards.py @@ -0,0 +1,61 @@ +from .input_devices import Button +from .output_devices import LED +from .devices import GPIODeviceError + + +class TrafficLights(object): + def __init__(self, red=None, amber=None, green=None): + if not all([red, amber, green]): + raise GPIODeviceError('Red, Amber and Green pins must be provided') + + self.red = LED(red) + self.amber = LED(amber) + self.green = LED(green) + self.lights = [self.red, self.amber, self.green] + + def lights_on(self): + for led in self.lights: + led.on() + + def lights_off(self): + for led in self.lights: + led.off() + + +class PiTraffic(TrafficLights): + def __init__(self): + self.red = LED(9) + self.amber = LED(10) + self.green = LED(11) + self.lights = [self.red, self.amber, self.green] + + +class FishDish(TrafficLights): + def __init__(self): + red, amber, green = (9, 22, 4) + super(FishDish, self).__init__(red, amber, green) + self.buzzer = Buzzer(8) + self.button = Button(7) + self.all = self.lights + [self.buzzer] + + def on(self): + for led in self.all: + led.on() + + def off(self): + for led in self.all: + led.off() + + +class PiLiter(object): + def __init__(self): + leds = [4, 17, 27, 18, 22, 23, 24, 25] + self.leds = [LED(led) for led in leds] + + def on(self): + for led in self.leds: + led.on() + + def off(self): + for led in self.leds: + led.off() From 5669a98b420c87eedeaf7597604ccadea32ad025 Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Mon, 21 Sep 2015 15:29:54 +0100 Subject: [PATCH 02/12] Expose add-on board classes to the module --- gpiozero/__init__.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/gpiozero/__init__.py b/gpiozero/__init__.py index e1ed84a..950823e 100644 --- a/gpiozero/__init__.py +++ b/gpiozero/__init__.py @@ -8,7 +8,7 @@ from .devices import ( _gpio_threads_shutdown, GPIODeviceError, GPIODevice, - ) +) from .input_devices import ( InputDeviceError, InputDevice, @@ -23,6 +23,12 @@ from .output_devices import ( Buzzer, Motor, ) +from .boards import ( + TrafficLights + PiTraffic, + FishDish, + PiLiter, +) def gpiozero_shutdown(): From 9019452973001e4c7e10459abb86ef1c15e13294 Mon Sep 17 00:00:00 2001 From: Philip Howard Date: Mon, 21 Sep 2015 17:00:09 +0100 Subject: [PATCH 03/12] Update __init__.py Added rogue missing comma! --- gpiozero/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gpiozero/__init__.py b/gpiozero/__init__.py index 950823e..e2a3336 100644 --- a/gpiozero/__init__.py +++ b/gpiozero/__init__.py @@ -24,7 +24,7 @@ from .output_devices import ( Motor, ) from .boards import ( - TrafficLights + TrafficLights, PiTraffic, FishDish, PiLiter, From d5f3e849a473f3b46b71d57850d7bdc59c43dd0b Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Mon, 21 Sep 2015 17:14:33 +0100 Subject: [PATCH 04/12] Prefix lights and all properties and convert lists to tuples --- gpiozero/boards.py | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/gpiozero/boards.py b/gpiozero/boards.py index ebdd7ae..79759b1 100644 --- a/gpiozero/boards.py +++ b/gpiozero/boards.py @@ -11,14 +11,14 @@ class TrafficLights(object): self.red = LED(red) self.amber = LED(amber) self.green = LED(green) - self.lights = [self.red, self.amber, self.green] + self._lights = (self.red, self.amber, self.green) - def lights_on(self): - for led in self.lights: + def on(self): + for led in self._lights: led.on() - def lights_off(self): - for led in self.lights: + def off(self): + for led in self._lights: led.off() @@ -27,7 +27,7 @@ class PiTraffic(TrafficLights): self.red = LED(9) self.amber = LED(10) self.green = LED(11) - self.lights = [self.red, self.amber, self.green] + self._lights = (self.red, self.amber, self.green) class FishDish(TrafficLights): @@ -36,21 +36,27 @@ class FishDish(TrafficLights): super(FishDish, self).__init__(red, amber, green) self.buzzer = Buzzer(8) self.button = Button(7) - self.all = self.lights + [self.buzzer] + self._all = tuple(list(self._lights) + [self.buzzer]) def on(self): - for led in self.all: - led.on() + for thing in self._all: + thing.on() def off(self): - for led in self.all: - led.off() + for thing in self._all: + thing.off() + + def lights_on(self): + super.on() + + def lights_off(self): + super.off() class PiLiter(object): def __init__(self): leds = [4, 17, 27, 18, 22, 23, 24, 25] - self.leds = [LED(led) for led in leds] + self.leds = tuple([LED(led) for led in leds]) def on(self): for led in self.leds: From 8223e5616294fd1dd4848f120bc8d94ca3860eb4 Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Mon, 21 Sep 2015 17:18:20 +0100 Subject: [PATCH 05/12] Make FishDish Button pull down --- gpiozero/boards.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gpiozero/boards.py b/gpiozero/boards.py index 79759b1..1ab267e 100644 --- a/gpiozero/boards.py +++ b/gpiozero/boards.py @@ -35,7 +35,7 @@ class FishDish(TrafficLights): red, amber, green = (9, 22, 4) super(FishDish, self).__init__(red, amber, green) self.buzzer = Buzzer(8) - self.button = Button(7) + self.button = Button(pin=7, pull_up=False) self._all = tuple(list(self._lights) + [self.buzzer]) def on(self): From 4403348917bd9e27f0656e97ddc63a2346548990 Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Mon, 21 Sep 2015 17:30:11 +0100 Subject: [PATCH 06/12] Use super over re-implentation for PiTraffic --- gpiozero/boards.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/gpiozero/boards.py b/gpiozero/boards.py index 1ab267e..915d153 100644 --- a/gpiozero/boards.py +++ b/gpiozero/boards.py @@ -24,10 +24,8 @@ class TrafficLights(object): class PiTraffic(TrafficLights): def __init__(self): - self.red = LED(9) - self.amber = LED(10) - self.green = LED(11) - self._lights = (self.red, self.amber, self.green) + red, amber, green = (9, 10, 11) + super(FishDish, self).__init__(red, amber, green) class FishDish(TrafficLights): From 2172ed78db3aa35e9a49a90eb590a7e0e87a2aa0 Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Mon, 21 Sep 2015 17:44:45 +0100 Subject: [PATCH 07/12] Add missing Buzzer import --- gpiozero/boards.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gpiozero/boards.py b/gpiozero/boards.py index 915d153..7fedf43 100644 --- a/gpiozero/boards.py +++ b/gpiozero/boards.py @@ -1,5 +1,5 @@ from .input_devices import Button -from .output_devices import LED +from .output_devices import LED, Buzzer from .devices import GPIODeviceError From be48a96e3eea00b2885bb08fb0543882f0f3c7d7 Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Mon, 21 Sep 2015 17:55:19 +0100 Subject: [PATCH 08/12] Blink defaults to 1 second on/off --- gpiozero/output_devices.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gpiozero/output_devices.py b/gpiozero/output_devices.py index d219c62..72a5160 100644 --- a/gpiozero/output_devices.py +++ b/gpiozero/output_devices.py @@ -24,7 +24,7 @@ class LED(OutputDevice): super(LED, self).__init__(pin) self._blink_thread = None - def blink(self, on_time, off_time): + def blink(self, on_time=1, off_time=1): self._stop_blink() self._blink_thread = GPIOThread(target=self._blink_led, args=(on_time, off_time)) self._blink_thread.start() From 840953fd8177e191933e17620a09c9a2f981e367 Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Mon, 21 Sep 2015 18:22:49 +0100 Subject: [PATCH 09/12] Refactor and add blink method to all boards --- gpiozero/boards.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/gpiozero/boards.py b/gpiozero/boards.py index 7fedf43..a1768ca 100644 --- a/gpiozero/boards.py +++ b/gpiozero/boards.py @@ -11,16 +11,20 @@ class TrafficLights(object): self.red = LED(red) self.amber = LED(amber) self.green = LED(green) - self._lights = (self.red, self.amber, self.green) + self._leds = (self.red, self.amber, self.green) def on(self): - for led in self._lights: + for led in self._leds: led.on() def off(self): - for led in self._lights: + for led in self._leds: led.off() + def blink(self, on_time=1, off_time=1): + for led in self._leds: + led.blink(on_time, off_time) + class PiTraffic(TrafficLights): def __init__(self): @@ -34,7 +38,7 @@ class FishDish(TrafficLights): super(FishDish, self).__init__(red, amber, green) self.buzzer = Buzzer(8) self.button = Button(pin=7, pull_up=False) - self._all = tuple(list(self._lights) + [self.buzzer]) + self._all = tuple(list(self._leds) + [self.buzzer]) def on(self): for thing in self._all: @@ -53,13 +57,17 @@ class FishDish(TrafficLights): class PiLiter(object): def __init__(self): - leds = [4, 17, 27, 18, 22, 23, 24, 25] - self.leds = tuple([LED(led) for led in leds]) + leds = (4, 17, 27, 18, 22, 23, 24, 25) + self._leds = tuple([LED(led) for led in leds]) def on(self): - for led in self.leds: + for led in self._leds: led.on() def off(self): - for led in self.leds: + for led in self._leds: led.off() + + def blink(self, on_time=1, off_time=1): + for led in self._leds: + led.blink(on_time, off_time) From e4742150c4c717ed3a206b17942a6021ad5b12be Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Mon, 21 Sep 2015 18:40:06 +0100 Subject: [PATCH 10/12] Add Ryanteck TrafficHat based on FishDish (untested) --- gpiozero/boards.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/gpiozero/boards.py b/gpiozero/boards.py index a1768ca..a2c34f7 100644 --- a/gpiozero/boards.py +++ b/gpiozero/boards.py @@ -26,12 +26,6 @@ class TrafficLights(object): led.blink(on_time, off_time) -class PiTraffic(TrafficLights): - def __init__(self): - red, amber, green = (9, 10, 11) - super(FishDish, self).__init__(red, amber, green) - - class FishDish(TrafficLights): def __init__(self): red, amber, green = (9, 22, 4) @@ -55,6 +49,15 @@ class FishDish(TrafficLights): super.off() +class TrafficHat(FishDish): + def __init__(self): + red, amber, green = (24, 23, 22) + super(PiTraffic, self).__init__(red, amber, green) + self.buzzer = Buzzer(5) + self.button = Button(25) + self._all = tuple(list(self._leds) + [self.buzzer]) + + class PiLiter(object): def __init__(self): leds = (4, 17, 27, 18, 22, 23, 24, 25) From 41c1bfb18f743285ff69c4f888cb90259799c848 Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Mon, 21 Sep 2015 21:11:56 +0100 Subject: [PATCH 11/12] Initial commit of basic Robot class --- gpiozero/output_devices.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/gpiozero/output_devices.py b/gpiozero/output_devices.py index 72a5160..0bdd42a 100644 --- a/gpiozero/output_devices.py +++ b/gpiozero/output_devices.py @@ -1,4 +1,5 @@ from RPi import GPIO +from time import sleep from .devices import GPIODeviceError, GPIODevice, GPIOThread @@ -58,3 +59,37 @@ class Buzzer(OutputDevice): class Motor(OutputDevice): pass + + +class Robot(object): + def __init__(self, left=None, right=None): + if not all([left, right]): + raise GPIODeviceError( + 'left and right pins must be provided' + ) + + self._left = Motor(left) + self._right = Motor(right) + + def left(self, seconds=None): + self._left.on() + if seconds is not None: + sleep(seconds) + self._left.off() + + def right(self, seconds=None): + self._right.on() + if seconds is not None: + sleep(seconds) + self._right.off() + + def forwards(self, seconds=None): + self.left() + self.right() + if seconds is not None: + sleep(seconds) + self.stop() + + def stop(self): + self._left.off() + self._right.off() From ae1c31e313acd003efd343a50926712de151e025 Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Tue, 22 Sep 2015 09:36:25 +0100 Subject: [PATCH 12/12] pep8 cleanup --- gpiozero/devices.py | 3 ++- gpiozero/input_devices.py | 38 ++++++++++++++++++++++++++------------ gpiozero/output_devices.py | 8 ++++---- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/gpiozero/devices.py b/gpiozero/devices.py index 22d4048..67c90c8 100644 --- a/gpiozero/devices.py +++ b/gpiozero/devices.py @@ -25,6 +25,8 @@ class GPIODevice(object): _GPIO_THREADS = set() + + def _gpio_threads_shutdown(): while _GPIO_THREADS: for t in _GPIO_THREADS.copy(): @@ -46,4 +48,3 @@ class GPIOThread(Thread): self.stopping.set() self.join() _GPIO_THREADS.discard(self) - diff --git a/gpiozero/input_devices.py b/gpiozero/input_devices.py index 0fbec6a..4490a22 100644 --- a/gpiozero/input_devices.py +++ b/gpiozero/input_devices.py @@ -22,7 +22,8 @@ class InputDevice(GPIODevice): if pull_up: self._active_state = 0 self._inactive_state = 1 - GPIO.setup(pin, GPIO.IN, (GPIO.PUD_DOWN, GPIO.PUD_UP)[pull_up]) + pull = GPIO.PUD_UP if pull_up else GPIO.PUD_DOWN + GPIO.setup(pin, GPIO.IN, pull) @property def pull_up(self): @@ -68,25 +69,29 @@ class MotionSensor(InputDevice): def _get_sample_rate(self): return self._sample_rate + def _set_sample_rate(self, value): if value <= 0: raise InputDeviceError('sample_rate must be greater than zero') self._sample_rate = value + sample_rate = property(_get_sample_rate, _set_sample_rate) def _get_threshold(self): return self._threshold + def _set_threshold(self, value): if value < 0: raise InputDeviceError('threshold must be zero or more') self._threshold = value + threshold = property(_get_threshold, _set_threshold) def _fill_queue(self): while ( - not self._queue_thread.stopping.wait(1 / self.sample_rate) and - len(self._queue) < self._queue.maxlen - ): + not self._queue_thread.stopping.wait(1 / self.sample_rate) and + len(self._queue) < self._queue.maxlen + ): self._queue.append(self.is_active) self._queue_full.set() while not self._queue_thread.stopping.wait(1 / self.sample_rate): @@ -104,7 +109,9 @@ class LightSensor(InputDevice): self.threshold = threshold self.partial = partial self._charged = Event() - GPIO.add_event_detect(self.pin, GPIO.RISING, lambda channel: self._charged.set()) + GPIO.add_event_detect( + self.pin, GPIO.RISING, lambda channel: self._charged.set() + ) self._queue = deque(maxlen=queue_len) self._queue_full = Event() self._queue_thread = GPIOThread(target=self._fill_queue) @@ -124,7 +131,10 @@ class LightSensor(InputDevice): if not self.partial: self._queue_full.wait() try: - return 1.0 - (sum(self._queue) / len(self._queue)) / self.darkness_time + return ( + 1.0 - (sum(self._queue) / len(self._queue)) / + self.darkness_time + ) except ZeroDivisionError: # No data == no light return 0.0 @@ -135,14 +145,17 @@ class LightSensor(InputDevice): def _get_when_light(self): return self._when_light + def _set_when_light(self, value): if not callable(value) and value is not None: raise InputDeviceError('when_light must be None or a function') self._when_light = value + when_light = property(_get_when_light, _set_when_light) def _get_when_dark(self): return self._when_dark + def _set_when_dark(self, value): if not callable(value) and value is not None: raise InputDeviceError('when_dark must be None or a function') @@ -156,27 +169,29 @@ class LightSensor(InputDevice): def _get_darkness_time(self): return self._darkness_time + def _set_darkness_time(self, value): if value <= 0.0: raise InputDeviceError('darkness_time must be greater than zero') self._darkness_time = value # XXX Empty the queue and restart the thread + darkness_time = property(_get_darkness_time, _set_darkness_time) def _get_threshold(self): return self._threshold + def _set_threshold(self, value): if value < 0: raise InputDeviceError('threshold must be zero or more') self._threshold = value + threshold = property(_get_threshold, _set_threshold) def _fill_queue(self): try: - while ( - not self._queue_thread.stopping.is_set() and - len(self._queue) < self._queue.maxlen - ): + while (not self._queue_thread.stopping.is_set() and + len(self._queue) < self._queue.maxlen): self._queue.append(self._time_charging()) if self.partial: self._fire_events() @@ -213,9 +228,8 @@ class LightSensor(InputDevice): if self.when_dark: self.when_dark() + class TemperatureSensor(W1ThermSensor): @property def value(self): return self.get_temperature() - - diff --git a/gpiozero/output_devices.py b/gpiozero/output_devices.py index 0bdd42a..3a5840e 100644 --- a/gpiozero/output_devices.py +++ b/gpiozero/output_devices.py @@ -27,7 +27,9 @@ class LED(OutputDevice): def blink(self, on_time=1, off_time=1): self._stop_blink() - self._blink_thread = GPIOThread(target=self._blink_led, args=(on_time, off_time)) + self._blink_thread = GPIOThread( + target=self._blink_led, args=(on_time, off_time) + ) self._blink_thread.start() def _stop_blink(self): @@ -64,9 +66,7 @@ class Motor(OutputDevice): class Robot(object): def __init__(self, left=None, right=None): if not all([left, right]): - raise GPIODeviceError( - 'left and right pins must be provided' - ) + raise GPIODeviceError('left and right pins must be provided') self._left = Motor(left) self._right = Motor(right)