From 7e5eb7dcbdadc09334f3628f9b90e2ed440c6f76 Mon Sep 17 00:00:00 2001 From: Balthasar Reuter Date: Thu, 19 Apr 2018 23:54:59 +0200 Subject: [PATCH] GPIO support based on gpiozero added. UNTESTED! --- INSTALL.md | 1 + photobooth/Gpio.py | 38 +++++++++++++++++ photobooth/Photobooth.py | 67 +++++++++++++++++++++++++++--- photobooth/defaults.cfg | 14 +++---- photobooth/gui/PyQt5Gui.py | 20 ++++----- photobooth/printer/PrinterPyQt5.py | 4 +- 6 files changed, 119 insertions(+), 25 deletions(-) create mode 100644 photobooth/Gpio.py diff --git a/INSTALL.md b/INSTALL.md index 8c20c53..2f07b96 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,6 +1,7 @@ pip install pyqt5 pip install opencv-python pip install Pillow +pip install gpiozero apt install gphoto2 libgphoto2-dev pip install gphoto2 diff --git a/photobooth/Gpio.py b/photobooth/Gpio.py new file mode 100644 index 0000000..0c0b91d --- /dev/null +++ b/photobooth/Gpio.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from gpiozero import LED, Button + +class Gpio: + + def __init__(self): + + self._buttons = [] + self._lamps = [] + + + def setButton(self, bcm_pin, handler): + + self._buttons.append(Button(bcm_pin)) + self._buttons[-1].when_pressed = handler + + + def setLamp(self, bcm_pin): + + self._lamps.append(LED(bcm_pin)) + return len(self._lamps) - 1 + + + def lampOn(self, index): + + self._lamps[index].on() + + + def lampOff(self, index): + + self._lamps[index].off() + + + def lampToggle(self, index): + + self._lamps[index].toggle() diff --git a/photobooth/Photobooth.py b/photobooth/Photobooth.py index b2b0711..d70b77d 100644 --- a/photobooth/Photobooth.py +++ b/photobooth/Photobooth.py @@ -14,15 +14,21 @@ class Photobooth: def __init__(self, config, camera): - picture_basename = strftime(config.get('Picture', 'basename'), localtime()) + self.initCamera(config, camera) + self.initGpio(config) + self.initTimings(config) + + self.triggerOff() + + + def initCamera(self, config, camera): self._cap = camera self._pic_dims = PictureDimensions(config, self._cap.getPicture().size) - self._pic_list = PictureList(picture_basename) - self._greeter_time = config.getInt('Photobooth', 'greeter_time') - self._countdown_time = config.getInt('Photobooth', 'countdown_time') - self._display_time = config.getInt('Photobooth', 'display_time') + picture_basename = strftime(config.get('Picture', 'basename'), localtime()) + self._pic_list = PictureList(picture_basename) + self._get_next_filename = self._pic_list.getNext if ( config.getBool('Photobooth', 'show_preview') and self._cap.hasPreview ): @@ -30,7 +36,36 @@ class Photobooth: else: self._show_counter = self.showCounterNoPreview - self._get_next_filename = self._pic_list.getNext + + def initGpio(self, config): + + if config.getBool('Gpio', 'enable'): + from Gpio import Gpio + + self._gpio = Gpio() + + lamp = self._gpio.setLamp(config.getInt('Gpio', 'lamp_pin')) + self._lampOn = lambda : self._gpio.lampOn(lamp) + self._lampOff = lambda : self._gpio.lampOff(lamp) + + self._gpio.setButton(config.getInt('Gpio', 'trigger_pin'), self.gpioTrigger) + self._gpio.setButton(config.getInt('Gpio', 'exit_pin'), self.teardown) + else: + self._lampOn = lambda : None + self._lampOff = lambda : None + + + def initTimings(self, config): + + self._greeter_time = config.getInt('Photobooth', 'greeter_time') + self._countdown_time = config.getInt('Photobooth', 'countdown_time') + self._display_time = config.getInt('Photobooth', 'display_time') + + + def teardown(self): + + self.triggerOff() + self.setCameraIdle() @property @@ -68,6 +103,7 @@ class Photobooth: self._send = send self.setCameraIdle() self._send.send(gui.IdleState()) + self.triggerOn() while True: try: @@ -85,6 +121,7 @@ class Photobooth: self._send.send( gui.ErrorState('Camera error', str(e)) ) event = recv.recv() if str(event) == 'cancel': + self.teardown() return 1 elif str(event) == 'ack': pass @@ -158,6 +195,7 @@ class Photobooth: def trigger(self): self._send.send(gui.GreeterState()) + self.triggerOff() self.setCameraActive() sleep(self.greeterTime) @@ -171,4 +209,21 @@ class Photobooth: sleep(self.displayTime) self._send.send(gui.IdleState()) + self._lampOn() + + def gpioTrigger(self): + + self._gpioTrigger() + + + def triggerOff(self): + + self._lampOff() + self._gpioTrigger = lambda : None + + + def triggerOn(self): + + self._lampOn() + self._gpioTrigger = self.trigger diff --git a/photobooth/defaults.cfg b/photobooth/defaults.cfg index 43cc50f..6b93fad 100644 --- a/photobooth/defaults.cfg +++ b/photobooth/defaults.cfg @@ -15,12 +15,12 @@ module = python-gphoto2 [Gpio] # Enable use of GPIO (True/False) enable = True -# Pin 18 (Channel 24) lets you return to start screen -exit_channel = 24 -# Pin 16 (Channel 23) triggers capturing pictures -trigger_channel = 23 -# Pin 7 (Channel 4) switches the lamp on and off -lamp_channel = 4 +# BOARD pin 18 (BCM pin 24) lets you return to start screen +exit_pin = 24 +# BOARD pin 16 (BCM pin 23) triggers capturing pictures +trigger_pin = 23 +# BOARD pin 7 (BCM pin 4) switches the lamp on and off +lamp_pin = 4 [Printer] # Enable printing (True/False) @@ -40,7 +40,7 @@ greeter_time = 3 # Countdown length in seconds (shown before every shot) countdown_time = 5 # Display time of assembled picture (shown after last shot) -display_time = 5 +display_time = 10 [Picture] # Basename of output pictures diff --git a/photobooth/gui/PyQt5Gui.py b/photobooth/gui/PyQt5Gui.py index ed1f08c..3c89aa2 100644 --- a/photobooth/gui/PyQt5Gui.py +++ b/photobooth/gui/PyQt5Gui.py @@ -59,7 +59,6 @@ class PyQt5Gui(Gui): if event.key() == Qt.Key_Escape: self.showStart() elif event.key() == Qt.Key_Space: - self._p.handleKeypressEvent = self.handleKeypressEventNoTrigger self._transport.send('triggered') @@ -78,6 +77,7 @@ class PyQt5Gui(Gui): self.showIdle() elif isinstance(state, GreeterState): global cfg + self._p.handleKeypressEvent = self.handleKeypressEventNoTrigger num_pictures = ( cfg.getInt('Picture', 'num_x') * cfg.getInt('Picture', 'num_y') ) self._p.setCentralWidget( @@ -335,15 +335,15 @@ class PyQt5Settings(QFrame): self._value_widgets['Gpio']['enable'] = QCheckBox('Enable GPIO') if cfg.getBool('Gpio', 'enable'): self._value_widgets['Gpio']['enable'].toggle() - self._value_widgets['Gpio']['exit_channel'] = QLineEdit(cfg.get('Gpio', 'exit_channel')) - self._value_widgets['Gpio']['trigger_channel'] = QLineEdit(cfg.get('Gpio', 'trigger_channel')) - self._value_widgets['Gpio']['lamp_channel'] = QLineEdit(cfg.get('Gpio', 'lamp_channel')) + self._value_widgets['Gpio']['exit_pin'] = QLineEdit(cfg.get('Gpio', 'exit_pin')) + self._value_widgets['Gpio']['trigger_pin'] = QLineEdit(cfg.get('Gpio', 'trigger_pin')) + self._value_widgets['Gpio']['lamp_pin'] = QLineEdit(cfg.get('Gpio', 'lamp_pin')) layout = QFormLayout() layout.addRow(self._value_widgets['Gpio']['enable']) - layout.addRow(QLabel('Exit channel:'), self._value_widgets['Gpio']['exit_channel']) - layout.addRow(QLabel('Trigger channel:'), self._value_widgets['Gpio']['trigger_channel']) - layout.addRow(QLabel('Lamp channel:'), self._value_widgets['Gpio']['lamp_channel']) + layout.addRow(QLabel('Exit pin (BCM numbering):'), self._value_widgets['Gpio']['exit_pin']) + layout.addRow(QLabel('Trigger pin (BCM numbering):'), self._value_widgets['Gpio']['trigger_pin']) + layout.addRow(QLabel('Lamp pin (BCM numbering):'), self._value_widgets['Gpio']['lamp_pin']) widget = QGroupBox('GPIO settings') widget.setLayout(layout) @@ -494,9 +494,9 @@ class PyQt5Settings(QFrame): cfg.set('Gui', 'height', self._value_widgets['Gui']['height'].text()) cfg.set('Gpio', 'enable', str(self._value_widgets['Gpio']['enable'].isChecked())) - cfg.set('Gpio', 'exit_channel', self._value_widgets['Gpio']['exit_channel'].text()) - cfg.set('Gpio', 'trigger_channel', self._value_widgets['Gpio']['trigger_channel'].text()) - cfg.set('Gpio', 'lamp_channel', self._value_widgets['Gpio']['lamp_channel'].text()) + cfg.set('Gpio', 'exit_pin', self._value_widgets['Gpio']['exit_pin'].text()) + cfg.set('Gpio', 'trigger_pin', self._value_widgets['Gpio']['trigger_pin'].text()) + cfg.set('Gpio', 'lamp_pin', self._value_widgets['Gpio']['lamp_pin'].text()) cfg.set('Printer', 'enable', str(self._value_widgets['Printer']['enable'].isChecked())) cfg.set('Printer', 'module', modules[self._value_widgets['Printer']['module'].currentIndex()][0]) diff --git a/photobooth/printer/PrinterPyQt5.py b/photobooth/printer/PrinterPyQt5.py index a3931c6..e97022c 100644 --- a/photobooth/printer/PrinterPyQt5.py +++ b/photobooth/printer/PrinterPyQt5.py @@ -35,9 +35,9 @@ class PrinterPyQt5(Printer): img = img.scaled(self._printer.pageRect().size(), Qt.KeepAspectRatio, Qt.SmoothTransformation) printable_size = self._printer.pageRect(QPrinter.DevicePixel) - offset = ( (printable_size.width() - img.width()) // 2, + origin = ( (printable_size.width() - img.width()) // 2, (printable_size.height() - img.height()) // 2 ) painter = QPainter(self._printer) - painter.drawImage(QPoint(*offset), img) + painter.drawImage(QPoint(*origin), img) painter.end()