GPIO matches StateMachine now
This commit is contained in:
@@ -1,50 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Photobooth - a flexible photo booth software
|
|
||||||
# Copyright (C) 2018 Balthasar Reuter <photobooth at re - web dot eu>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
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()
|
|
||||||
174
photobooth/gpio/__init__.py
Normal file
174
photobooth/gpio/__init__.py
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Photobooth - a flexible photo booth software
|
||||||
|
# Copyright (C) 2018 Balthasar Reuter <photobooth at re - web dot eu>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from .. import StateMachine
|
||||||
|
from ..Threading import Workers
|
||||||
|
|
||||||
|
|
||||||
|
class Gpio:
|
||||||
|
|
||||||
|
def __init__(self, config, comm):
|
||||||
|
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self._comm = comm
|
||||||
|
self._gpio = None
|
||||||
|
|
||||||
|
self._is_trigger = False
|
||||||
|
self._is_enabled = config.getBool('Gpio', 'enable')
|
||||||
|
|
||||||
|
self.initGpio(config)
|
||||||
|
|
||||||
|
def initGpio(self, config):
|
||||||
|
|
||||||
|
if self._is_enabled:
|
||||||
|
self._gpio = Entities()
|
||||||
|
|
||||||
|
lamp_pin = config.getInt('Gpio', 'lamp_pin')
|
||||||
|
trigger_pin = config.getInt('Gpio', 'trigger_pin')
|
||||||
|
exit_pin = config.getInt('Gpio', 'exit_pin')
|
||||||
|
|
||||||
|
logging.info(('GPIO enabled (lamp_pin=%d, trigger_pin=%d, '
|
||||||
|
'exit_pin=%d)'), lamp_pin, trigger_pin, exit_pin)
|
||||||
|
|
||||||
|
self._gpio.setButton(trigger_pin, self.trigger)
|
||||||
|
self._gpio.setButton(exit_pin, self.exit)
|
||||||
|
self._lamp = self._gpio.setLamp(lamp_pin)
|
||||||
|
else:
|
||||||
|
logging.info('GPIO disabled')
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
|
||||||
|
for state in self._comm.iter(Workers.GPIO):
|
||||||
|
self.handleState(state)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def handleState(self, state):
|
||||||
|
|
||||||
|
if isinstance(state, StateMachine.IdleState):
|
||||||
|
self.showIdle()
|
||||||
|
elif isinstance(state, StateMachine.GreeterState):
|
||||||
|
self.showGreeter()
|
||||||
|
elif isinstance(state, StateMachine.CountdownState):
|
||||||
|
self.showCountdown()
|
||||||
|
elif isinstance(state, StateMachine.CaptureState):
|
||||||
|
self.showCapture()
|
||||||
|
elif isinstance(state, StateMachine.AssembleState):
|
||||||
|
self.showAssemble()
|
||||||
|
elif isinstance(state, StateMachine.ReviewState):
|
||||||
|
self.showReview()
|
||||||
|
elif isinstance(state, StateMachine.PostprocessState):
|
||||||
|
self.showPostprocess()
|
||||||
|
elif isinstance(state, StateMachine.TeardownState):
|
||||||
|
self.teardown(state)
|
||||||
|
|
||||||
|
def teardown(self, state):
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def enableTrigger(self):
|
||||||
|
|
||||||
|
if self._is_enabled:
|
||||||
|
self._is_trigger = True
|
||||||
|
self._gpio.lampOn(self._lamp)
|
||||||
|
|
||||||
|
def disableTrigger(self):
|
||||||
|
|
||||||
|
if self._is_enabled:
|
||||||
|
self._is_trigger = False
|
||||||
|
self._gpio.lampOff(self._lamp)
|
||||||
|
|
||||||
|
def trigger(self):
|
||||||
|
|
||||||
|
if self._is_trigger:
|
||||||
|
self.disableTrigger()
|
||||||
|
self._comm.send(Workers.MASTER, StateMachine.GpioEvent('trigger'))
|
||||||
|
|
||||||
|
def exit(self):
|
||||||
|
|
||||||
|
self._comm.send(
|
||||||
|
Workers.Master,
|
||||||
|
StateMachine.TeardownEvent(StateMachine.TeardownEvent.WELCOME))
|
||||||
|
|
||||||
|
def showIdle(self):
|
||||||
|
|
||||||
|
self.enableTrigger()
|
||||||
|
|
||||||
|
def showGreeter(self):
|
||||||
|
|
||||||
|
self.disableTrigger()
|
||||||
|
|
||||||
|
def showCountdown(self):
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def showCapture(self):
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def showAssemble(self):
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def showReview(self):
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def showPostprocess(self):
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Entities:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
import gpiozero
|
||||||
|
self.LED = gpiozero.LED
|
||||||
|
self.Button = gpiozero.Button
|
||||||
|
|
||||||
|
self._buttons = []
|
||||||
|
self._lamps = []
|
||||||
|
|
||||||
|
def setButton(self, bcm_pin, handler):
|
||||||
|
|
||||||
|
self._buttons.append(self.Button(bcm_pin))
|
||||||
|
self._buttons[-1].when_pressed = handler
|
||||||
|
|
||||||
|
def setLamp(self, bcm_pin):
|
||||||
|
|
||||||
|
self._lamps.append(self.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()
|
||||||
@@ -30,6 +30,7 @@ import sys
|
|||||||
|
|
||||||
from . import camera, gui
|
from . import camera, gui
|
||||||
from .Config import Config
|
from .Config import Config
|
||||||
|
from .gpio import Gpio
|
||||||
from .util import lookup_and_import
|
from .util import lookup_and_import
|
||||||
from .StateMachine import Context, ErrorEvent
|
from .StateMachine import Context, ErrorEvent
|
||||||
from .Threading import Communicator, Workers
|
from .Threading import Communicator, Workers
|
||||||
@@ -38,7 +39,7 @@ from .worker import Worker
|
|||||||
|
|
||||||
class CameraProcess(mp.Process):
|
class CameraProcess(mp.Process):
|
||||||
|
|
||||||
def __init__(self, config, comm):
|
def __init__(self, argv, config, comm):
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.daemon = True
|
self.daemon = True
|
||||||
@@ -60,41 +61,61 @@ class CameraProcess(mp.Process):
|
|||||||
self._comm.send(Workers.MASTER, ErrorEvent('Camera', str(e)))
|
self._comm.send(Workers.MASTER, ErrorEvent('Camera', str(e)))
|
||||||
|
|
||||||
|
|
||||||
class WorkerProcess(mp.Process):
|
|
||||||
|
|
||||||
def __init__(self, config, comm):
|
|
||||||
|
|
||||||
super().__init__()
|
|
||||||
self.daemon = True
|
|
||||||
|
|
||||||
self.cfg = config
|
|
||||||
self.comm = comm
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
if Worker(self.cfg, self.comm).run():
|
|
||||||
break
|
|
||||||
except Exception as e:
|
|
||||||
self._comm.send(Workers.MASTER, ErrorEvent('Worker', str(e)))
|
|
||||||
|
|
||||||
|
|
||||||
class GuiProcess(mp.Process):
|
class GuiProcess(mp.Process):
|
||||||
|
|
||||||
def __init__(self, argv, config, communicator):
|
def __init__(self, argv, config, communicator):
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.argv = argv
|
self._argv = argv
|
||||||
self.cfg = config
|
self._cfg = config
|
||||||
self.comm = communicator
|
self._comm = communicator
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
Gui = lookup_and_import(gui.modules, self.cfg.get('Gui', 'module'),
|
Gui = lookup_and_import(gui.modules, self._cfg.get('Gui', 'module'),
|
||||||
'gui')
|
'gui')
|
||||||
sys.exit(Gui(self.argv, self.cfg, self.comm).run())
|
return Gui(self._argv, self._cfg, self._comm).run()
|
||||||
|
|
||||||
|
|
||||||
|
class WorkerProcess(mp.Process):
|
||||||
|
|
||||||
|
def __init__(self, argv, config, comm):
|
||||||
|
|
||||||
|
super().__init__()
|
||||||
|
self.daemon = True
|
||||||
|
|
||||||
|
self._cfg = config
|
||||||
|
self._comm = comm
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
if Worker(self._cfg, self._comm).run():
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
self._comm.send(Workers.MASTER, ErrorEvent('Worker', str(e)))
|
||||||
|
|
||||||
|
|
||||||
|
class GpioProcess(mp.Process):
|
||||||
|
|
||||||
|
def __init__(self, argv, config, comm):
|
||||||
|
|
||||||
|
super().__init__()
|
||||||
|
self.daemon = True
|
||||||
|
|
||||||
|
self._cfg = config
|
||||||
|
self._comm = comm
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
if Gpio(self._cfg, self._comm).run():
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
self.comm.send(Workers.MASTER, ErrorEvent('Gpio', str(e)))
|
||||||
|
|
||||||
|
|
||||||
def run(argv):
|
def run(argv):
|
||||||
@@ -107,29 +128,28 @@ def run(argv):
|
|||||||
comm = Communicator()
|
comm = Communicator()
|
||||||
context = Context(comm)
|
context = Context(comm)
|
||||||
|
|
||||||
# Initialize processes: We use four processes here:
|
# Initialize processes: We use five processes here:
|
||||||
# 1. Camera processing
|
# 1. Master that collects events and distributes state changes
|
||||||
# 2. Postprocessing
|
# 2. Camera handling
|
||||||
# 3. GUI
|
# 3. GUI
|
||||||
# 4. Master
|
# 4. Postprocessing worker
|
||||||
camera_proc = CameraProcess(config, comm) # camera_conn, worker_queue)
|
# 5. GPIO handler
|
||||||
camera_proc.start()
|
proc_classes = (CameraProcess, WorkerProcess, GuiProcess, GpioProcess)
|
||||||
|
procs = [P(argv, config, comm) for P in proc_classes]
|
||||||
|
|
||||||
worker_proc = WorkerProcess(config, comm)
|
for proc in procs:
|
||||||
worker_proc.start()
|
proc.start()
|
||||||
|
|
||||||
gui_proc = GuiProcess(argv, config, comm)
|
|
||||||
gui_proc.start()
|
|
||||||
|
|
||||||
|
# Enter main loop
|
||||||
for event in comm.iter(Workers.MASTER):
|
for event in comm.iter(Workers.MASTER):
|
||||||
exit_code = context.handleEvent(event)
|
exit_code = context.handleEvent(event)
|
||||||
if exit_code in (0, 123):
|
if exit_code in (0, 123):
|
||||||
break
|
break
|
||||||
|
|
||||||
# Wait for processes to finish
|
# Wait for processes to finish
|
||||||
gui_proc.join()
|
for proc in procs:
|
||||||
worker_proc.join()
|
proc.join()
|
||||||
camera_proc.join()
|
|
||||||
logging.debug('All processes joined, returning code {}'. format(exit_code))
|
logging.debug('All processes joined, returning code {}'. format(exit_code))
|
||||||
|
|
||||||
return exit_code
|
return exit_code
|
||||||
|
|||||||
Reference in New Issue
Block a user