diff --git a/babyfut.py b/babyfut.py index 049bba0d2b1fe21123d547f2a20c5e3a24c8b26d..521b4460d8b20c9673338cdb536b959025202fc3 100644 --- a/babyfut.py +++ b/babyfut.py @@ -28,20 +28,18 @@ def getMainWin(): ON_RASP = os.uname()[1] == 'raspberrypi' IMG_PATH = getContent('img') -SIDE = None if __name__=='__main__': __package__ = 'Babyfut' from Babyfut.ui.mainwin import MainWin from Babyfut.modules import GameModule from Babyfut.core.player import Side - from Babyfut.core.input import GPIOThread + from Babyfut.core.input import Input from Babyfut.core.downloader import Downloader from Babyfut.core.database import Database from Babyfut.core.replay import Replay as ReplayThread try: - SIDE = Side.Left #logging.basicConfig(filename='babyfoot.log', level=logging.DEBUG) logging.basicConfig(level=logging.DEBUG) @@ -56,9 +54,10 @@ if __name__=='__main__': threadReplay.start() myapp.dispatchMessage({'replayThread': threadReplay}, toType=GameModule) - threadGPIO = GPIOThread() - threadGPIO.rfidReceived.connect(myapp.rfidHandler) - threadGPIO.start() + input = Input() + input.rfidReceived.connect(lambda side: myapp.dispatchMessage({'rfid': rfid, 'source': side})) + input.goalDetected.connect(lambda side: myapp.dispatchMessage({'goal': True, 'source': side})) + input.start() threadDownloader = Downloader.instance() threadDownloader.start() @@ -66,18 +65,16 @@ if __name__=='__main__': myapp.show() app.exec_() - threadDownloader.stop() - threadGPIO.stop() if ReplayThread.isCamAvailable(): threadReplay.stop() threadReplay.join() - threadGPIO.join() + input.stop() + threadDownloader.stop() threadDownloader.join() finally: - GPIOThread.clean() Database.instance().close() for f in glob.glob(join(IMG_PATH, '*')): os.remove(f) diff --git a/core/ginger.py b/core/ginger.py index f8326b0454738f2d6460f6a4517594117247cd6d..00f00f36eac038665e26706972ed6ee79e7648e2 100644 --- a/core/ginger.py +++ b/core/ginger.py @@ -14,8 +14,8 @@ class Ginger(object): def __init__(self): if Ginger._instance!=None: - self.url = Settings['ginger.url'] self.api_key = Settings['ginger.key'] + self.url = Ginger.URL @property @staticmethod @@ -25,7 +25,7 @@ class Ginger(object): return Ginger._instance @staticmethod - def call(endpoint, params={}): + def get(endpoint, params={}): # Add the API key to the parameter list params['key'] = Ginger.instance.api_key diff --git a/core/input.py b/core/input.py index 70f993e66b35147138cd259cb92548add4a1767c..bfcc035fdf99a82838cedff08128744e95256248 100644 --- a/core/input.py +++ b/core/input.py @@ -7,18 +7,34 @@ import logging import time from threading import Thread -import pyautogui # PyPi library from PyQt5.QtCore import QObject, pyqtSignal from Babyfut.babyfut import ON_RASP from Babyfut.core.player import Side +from Babyfut.core.settings import Settings if ON_RASP: import RPi.GPIO as GPIO from pirc522 import RFID # PyPi library + import pyautogui # PyPi library + +class Input(QObject): + ''' + Defines pins. Uses BCM pin identifiers + ''' + + _RFIDPins = { + 'pin_rst': 25, + 'pin_ce' : 8, + 'pin_irq': 24 + } + + _GoalPins = { + 'pin_trig': 4, + 'pin_echo': 16 + } -class GPIOThread(Thread, QObject): _keyButtonBindings = { 26: 'up', 22: 'left', @@ -28,36 +44,77 @@ class GPIOThread(Thread, QObject): 18: 'escape' } - rfidReceived = pyqtSignal(str) + rfidReceived = pyqtSignal(Side, str) + goalDetected = pyqtSignal(Side) def __init__(self): - Thread.__init__(self) QObject.__init__(self) - self.continueRunning = True - self.lastRFIDReception = 0 if ON_RASP: - self.rf_reader = RFID(pin_rst=25, pin_ce=8, pin_irq=24, pin_mode=GPIO.BCM) - GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) - - for pin in GPIOThread._keyButtonBindings.keys(): - print(pin) + for pin in Input._keyButtonBindings.keys(): GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) - GPIO.add_event_detect(pin, GPIO.RISING, callback=self.handleButtonPress) + GPIO.add_event_detect(pin, GPIO.RISING, callback=self._handleButtonPress) - def run(self): + self.side = Side.Left if Settings['app.side']=='left' else Side.Right + print(self.side) + self.rfidThread = RFIDThread(self, **Input._RFIDPins) + self.goalThread = GoalThread(self, **Input._GoalPins) + + def start(self): + if ON_RASP: + self.rfidThread.start() + self.goalThread.start() + + def stop(self): if ON_RASP: - try: - while self.continueRunning: - self.rf_reader.wait_for_tag() - (error, tag_type) = self.rf_reader.request() - if not error: - self.handleRFID() - finally: - self.clean() - - def handleRFID(self): + self.rfidThread.stop(); self.rfidThread.join() + self.goalThread.stop(); self.goalThread.join() + + def _handleButtonPress(self, button_pin): + if button_pin not in Input._keyButtonBindings.keys(): + logging.warn('Unknown button pin: {}'.format(button_pin)) + else: + key = Input._keyButtonBindings[button_pin] + logging.debug('Sending {} as {}'.format(button_pin, key)) + pyautogui.press(key) + +class GPIOThread(Thread): + def __init__(self): + Thread.__init__(self) + self._running = True + + def running(self): + return self._running + + def start(self): + Thread.start(self) + + def stop(self): + self._running = False + + def clean(self): + GPIO.cleanup() + +class RFIDThread(GPIOThread): + def __init__(self, parent, **pins): + GPIOThread.__init__(self) + self.parent = parent + self.lastRFIDReception = 0 + self.rf_reader = RFID(**pins, pin_mode=GPIO.BCM) + print(self.rf_reader.pin_rst, self.rf_reader.pin_ce, self.rf_reader.pin_irq) + + def run(self): + try: + while self.running(): + self.rf_reader.wait_for_tag() + (error, tag_type) = self.rf_reader.request() + if not error: + self._handleRFID() + finally: + self.clean() + + def _handleRFID(self): (error, id) = self.rf_reader.anticoll() if not error: # Prevent RFID "spam" (one second removal delay) @@ -65,30 +122,59 @@ class GPIOThread(Thread, QObject): if self.lastRFIDReception!=0 and abs(self.lastRFIDReception-now)>1: self.lastRFIDReception = 0 receivedRFID = ':'.join([str(x) for x in id]) - self.rfidReceived.emit(receivedRFID) + self.input.emit(self.parent.side, receivedRFID) logging.debug('Received RFID: {}'.format(receivedRFID)) else: self.lastRFIDReception = now - def handleButtonPress(self, button_pin): - if button_pin not in GPIOThread._keyButtonBindings.keys(): - logging.warn('Unknown button pin: {}'.format(button_pin)) - else: - key = GPIOThread._keyButtonBindings[button_pin] - logging.debug('Sending {} as {}'.format(button_pin, key)) - pyautogui.press(key) - def stop(self): - self.continueRunning = False - # Falsely trigger the rfid reader to stop it waiting - if ON_RASP: - self.rf_reader.irq.set() + GPIOThread.stop(self) + + # Falsely trigger the rfid reader to stop it from waiting + self.rf_reader.irq.set() def clean(self): - GPIOThread.clean() + GPIOThread.clean(self) self.rf_reader.cleanup() - @staticmethod - def clean(): - if ON_RASP: - GPIO.cleanup() +class GoalThread(GPIOThread): + def __init__(self, parent, pin_trig, pin_echo): + GPIOThread.__init__(self) + self.parent = parent + self.pin_trig = pin_trig + self.pin_echo = pin_echo + + GPIO.setmode(GPIO.BCM) + GPIO.setup (self.pin_echo, GPIO.IN) + GPIO.setup (self.pin_trig, GPIO.OUT) + GPIO.output(self.pin_trig, GPIO.LOW) + print(self.pin_trig, pin_echo) + + def run(self): + try: + # Waiting for sensor to settle + time.sleep(2) + + while self.running(): + # Trigger a scan + GPIO.output(self.pin_trig, GPIO.HIGH) + time.sleep(0.00001) + GPIO.output(self.pin_trig, GPIO.LOW) + + # Read the echo + while self.running() and GPIO.input(self.pin_echo)==0: + pulse_start_time = time.time() + while self.running() and GPIO.input(self.pin_echo)==1: + pulse_end_time = time.time() + + if self.running(): + pulse_duration = pulse_end_time - pulse_start_time + distance = round(pulse_duration * 17150, 2) + self._handle_dist(distance) + finally: + self.clean() + + def _handle_dist(self, dist): + logging.debug('Distance: {}cm'.format(dist)) + if dist<3: + self.parent.goalDetected.emit(self.parent.side) diff --git a/core/player.py b/core/player.py index 6107fc9f4f519157811e09d080fc4be9442be06e..c539e94457903078abd0dd7dad0610a6da301298 100644 --- a/core/player.py +++ b/core/player.py @@ -128,7 +128,7 @@ class Player(QObject): ''' Retrieves a player's informations from the Ginger API ''' - response = Ginger.call('badge/{}'.format(rfid)) + response = Ginger.instance.get('badge/{}'.format(rfid)) if isinstance(response, HTTPStatus): logging.warn('Request to Ginger failed ({}): returning Guest'.format(response.value)) return PlayerGuest @@ -138,7 +138,7 @@ class Player(QObject): return Player._loadFromDB(rfid) - def displayImg(self, container_widget, *args): + def displayImg(self, container_widget): self.pic_container = container_widget if self.pic_path.startswith('http'): diff --git a/devtools.sh b/devtools.sh index 2d70f73be50c6eca544b22c62ed1b078afabe0d1..54112abe70066fa7f3f6a42c381fcf16324af0c5 100755 --- a/devtools.sh +++ b/devtools.sh @@ -63,6 +63,37 @@ case "$1" in cd .. python -m Babyfut.babyfut ;; + "install") + echo "Installing.." + echo "** Assuming debian-like environment. This shouldn't be run more than once" + echo "** Updating the system to make sure everything is up-to-date." + echo "" + sudo apt-get update && sudo apt-get upgrade + + echo "" + echo "** Installing python3 and python tools" + # Sometimes the PYTHONPATH wont be set accordingly for some raspbian distributions + # In which case, manually import the right path (/usr/lib/python3/dist-packages) in + # the virtual environment's activation script + sudo apt-get install -y python3 python3-venv python3-pyqt5 python3-pip qtmultimedia5-examples \ + pyqt5-dev pyqt5-dev-tools + + echo "" + echo "** Setting up the python virtual environment" + python3 -m venv ../PyQt5 + source ../PyQt5/bin/activate + + echo "" + echo "** Installing libraries used by the software" + pip install pi-rc522 pyautogui Xlib RPi.GPIO request + + echo "" + echo "****************************" + echo "" + echo "Installation done successfully! You may have to source the v-env." + echo "Don't forget to download the \"content\" folder from another source." + bash ./devtools.sh "allc" + ;; *) echo "Unknown command \"$1\". See script for available commands." ;; diff --git a/translations/babyfut_fr.ts b/translations/babyfut_fr.ts index c6d1947daccf58416102041f037b17e2726cde98..d99990587ed2d1236daf242e585930c83fe2b3c2 100644 --- a/translations/babyfut_fr.ts +++ b/translations/babyfut_fr.ts @@ -66,12 +66,12 @@ Stat - + Player 1 Joueur 1 - + Player 2 Joueur 2 @@ -91,7 +91,7 @@ Joueur 4 - + Congratulations! Félicitations ! diff --git a/ui/mainwin.py b/ui/mainwin.py index b63c23ea89896ed7638c59240c4e0c8ec1d82126..11d0d744177bad6325d99b834060628290d96634 100644 --- a/ui/mainwin.py +++ b/ui/mainwin.py @@ -80,11 +80,6 @@ class MainWin(QtWidgets.QMainWindow): for modIdx in modulesIdx: self.modules[modIdx].other(**msg) - - @pyqtSlot(str) - def rfidHandler(self, rfid): - side = Side.Left if Settings['app.side']=='left' else Side.Right - self.dispatchMessage({'rfid': rfid, 'source': side}) def _loadSettings(self): if Settings['ui.fullscreen']: