-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit d411052
Showing
50 changed files
with
2,525 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
__pycache__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"python.analysis.extraPaths": [ | ||
"./cocktail-project/components" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2023 Cyril Deschamps | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# picock-tail | ||
|
||
Polytech S5 Project on Raspberry | ||
|
||
## Starting Python Project | ||
|
||
- pip install -r requirements.txt | ||
|
||
## Description du projet | ||
|
||
Notre projet représente la combinaison parfaite entre la technologie et la mixologie. Nous souhaitons offrir une solution qui permettrait à un utilisateur de faire automatiquement et rapidement plusieurs cocktails afin de ravir des convives. Grâce à un système de tubes et de moteurs, la machine utilisera la gravité afin de servir des doses précises de liquides, stockés dans des bouteilles au-dessus de l’embout verseur. Ce sont des moteurs, attachés à des petites pièces imprimées en 3D, qui pinceront ou relâcheront les tubulures pour contrôler le débit des liquides . Afin de servir plusieurs verres à la suite, on utilisera un système de tapis roulant piloté par un moteur. L’interface utilisateur sera un écran LCD permettant d’enregistrer des recettes et de servir des verres. Grâce à un système de lecture NFC de cartes étudiantes, nous comptons pouvoir créer des profils afin d’enregistrer les commandes de chaque utilisateur. Grâce à des capteurs, on s’assurera qu’un verre est présent en dessous de l’embout pour ne pas verser dans le vide. De plus, la maintenance sera assurée par des capteurs de niveau de liquide pour ne jamais tomber en panne sèche. L’utilisateur sera prévenu d’un problème de la machine grâce à un buzzer. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
from multiprocessing import Process | ||
import time | ||
from drivers.Ultrasonic import getDistance | ||
from drivers.Pump import switchOnPump, switchOffPump, pumpDebit | ||
from database.recipe import Recipe | ||
from tortoise.queryset import Q | ||
|
||
class ServeDrinkAction(): | ||
|
||
# Run a subprocess to serve a drink and check if there is glass during service | ||
async def serveDrink(self, recipeId, size): | ||
recipe = await Recipe.get(Q(id=recipeId)) | ||
serveProcess = Process(target=self.physicallyServe, args=(recipe,size,)) | ||
serveProcess.start() | ||
|
||
serveSuccessfully = True | ||
# Check if there is glass during service | ||
while serveProcess.is_alive() and serveSuccessfully: | ||
if not self.checkGlass(): | ||
serveProcess.kill() # Stop service if no glass | ||
switchOffPump(1) # Reset pump | ||
switchOffPump(2) | ||
serveSuccessfully = False | ||
time.sleep(0.1) | ||
|
||
return serveSuccessfully | ||
|
||
|
||
|
||
# Check if there is glass on the scale | ||
def checkGlass(self): | ||
distance1 = getDistance() | ||
time.sleep(0.05) | ||
distance2 = getDistance() | ||
time.sleep(0.05) | ||
distance3 = getDistance() | ||
time.sleep(0.05) | ||
distance4 = getDistance() | ||
|
||
return min(distance1, distance2, distance3, distance4) < 10 #+- 10 cm | ||
|
||
|
||
|
||
# Subprocess function | ||
def physicallyServe(self, recipe, size): | ||
rateBottleOne = recipe.rate_bottle_one | ||
rateBottleTwo = recipe.rate_bottle_two | ||
|
||
# Time = quantity / debit | ||
switchOnDurationBottleOne = (rateBottleOne * size) / pumpDebit | ||
switchOnDurationBottleTwo = (rateBottleTwo * size) / pumpDebit | ||
|
||
switchOnPump(1) | ||
switchOnPump(2) | ||
|
||
time.sleep(min(switchOnDurationBottleOne, switchOnDurationBottleTwo)) | ||
|
||
if switchOnDurationBottleOne < switchOnDurationBottleTwo: | ||
switchOffPump(1) | ||
time.sleep(switchOnDurationBottleTwo - switchOnDurationBottleOne) | ||
switchOffPump(2) | ||
else: | ||
switchOffPump(2) | ||
time.sleep(switchOnDurationBottleOne - switchOnDurationBottleTwo) | ||
switchOffPump(1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from drivers.LCD import setText, setRGB | ||
|
||
class ShutdownAction(): | ||
|
||
def shutdownMachine(self): | ||
setText("") | ||
setRGB(0,0,0) | ||
exit(1) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
from drivers.LCD import setText | ||
from drivers.Joystick import listenJoystick | ||
|
||
class SelectionMenu(): | ||
|
||
# Constructor | ||
# Args : | ||
# - menu : List of the menu items (max 12 chars) | ||
def __init__(self, title, menu): | ||
self.title = title | ||
self.menu = menu | ||
self.currentIndex = 0 | ||
self.renderView() | ||
|
||
|
||
|
||
# Handle the menu selection | ||
# Return: index of the selected item on the list | ||
def handleMenuSelection(self): | ||
while listenJoystick(callback=self.updateCurrentIndexByJoystickAction): pass | ||
return self.currentIndex | ||
|
||
|
||
|
||
# Render the view of the menu | ||
def renderView(self): | ||
textToPrint = "" | ||
if self.currentIndex == 0: | ||
textToPrint += f"{self.title}\n" | ||
textToPrint += f"{self.currentIndex + 1}.{self.menu[self.currentIndex][:12]} O\n" | ||
else: | ||
textToPrint += f"{self.currentIndex + 1}.{self.menu[self.currentIndex][:12]} O\n" | ||
if self.currentIndex < len(self.menu) - 1: | ||
textToPrint += f"{self.currentIndex + 2}.{self.menu[self.currentIndex + 1][:12]}\n" | ||
setText(textToPrint) | ||
|
||
|
||
|
||
# Update current index of the menu based on joystick action and render the view | ||
# Return: True if the action is not a click | ||
def updateCurrentIndexByJoystickAction(self, joystickAction): | ||
if joystickAction == "CLICK": | ||
return False | ||
elif joystickAction == "UP": | ||
if self.currentIndex > 0: | ||
self.currentIndex -= 1 | ||
self.renderView() | ||
elif joystickAction == "DOWN": | ||
if self.currentIndex < len(self.menu) - 1: | ||
self.currentIndex += 1 | ||
self.renderView() | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
from drivers.LCD import setErrorRGB, setText | ||
from drivers.Joystick import listenJoystick | ||
|
||
class VirtualKeyboard(): | ||
|
||
def __init__(self): | ||
# currentText : String -> Text inputed by user | ||
self.currentText = "" | ||
|
||
# currentInputIndex : Int -> Index of the current character in the virtual keyboard | ||
self.currentInputIndex = 0 | ||
|
||
# charactersUppercase : List of 26 characters + back and enter in uppercase | ||
self.charactersUppercase = [chr(ord('A') + i) for i in range(26)] | ||
self.newCurrentInputIndex = None | ||
|
||
|
||
|
||
# Start the VirtualKeyboardView | ||
# Return text inputed by user | ||
def getInput(self): | ||
self.renderView() | ||
self.handleInput() | ||
return self.currentText | ||
|
||
|
||
|
||
# Render the LCD View : | ||
# - First line : currentText | ||
# - Second line : line of the virtual keyboard where the current character is uppercase | ||
def renderView(self): | ||
setText(self.currentText + "\n" + self.getInputHelperLine(self.currentInputIndex)) | ||
|
||
|
||
|
||
# Handle input of the user on the virtual keyboard | ||
# End : update self.currentText | ||
def handleInput(self): | ||
# while user is inputing text | ||
while listenJoystick(callback=self.updateTextByJoystickAction): pass | ||
|
||
|
||
|
||
# Update the LCD View according to the joystick action | ||
def updateTextByJoystickAction(self, joystickAction): | ||
#Checks if the index has changed and if the text has changed | ||
indexChanged = False | ||
textChanged = False | ||
|
||
if joystickAction == "CLICK": | ||
# If index is in range of alphabet, add current character to currentText | ||
if self.currentInputIndex in range (0, 26): | ||
if len(self.currentText) < 16: | ||
newCurrentText = self.currentText + self.getCurrentCharacter(self.currentInputIndex) | ||
textChanged = True #Text has changed | ||
else : | ||
#print("DEBUG : Text too long") | ||
setErrorRGB() | ||
elif self.currentInputIndex == 26: # If index is 26, remove last character of currentText | ||
newCurrentText = self.currentText[:-1] | ||
textChanged = True #Text has changed | ||
elif self.currentInputIndex == 27: # If index is 27, validate currentText and stop inputing | ||
return False | ||
|
||
elif joystickAction == "LEFT": | ||
# print("LEFT") | ||
if self.currentInputIndex > 0: | ||
newCurrentInputIndex = self.currentInputIndex - 1 | ||
indexChanged = True #Index has changed | ||
|
||
elif joystickAction == "RIGHT": | ||
# print("RIGHT") | ||
if self.currentInputIndex < 27: | ||
newCurrentInputIndex = self.currentInputIndex + 1 | ||
indexChanged = True #Index has changed | ||
|
||
# Update currentInputIndex and display if needed | ||
if indexChanged: | ||
if newCurrentInputIndex != None: | ||
self.currentInputIndex = newCurrentInputIndex | ||
newCurrentInputIndex = None | ||
self.renderView() | ||
if textChanged: | ||
if newCurrentText != None: | ||
self.currentText = newCurrentText | ||
newCurrentText = None | ||
self.renderView() | ||
|
||
return True | ||
|
||
|
||
|
||
# getInputHelperLine(index) -> String | ||
# Input : index (Int) | ||
# Output : String of 16 characters with index in Uppercase | ||
def getInputHelperLine(self, index): | ||
|
||
# Verify if index is in range | ||
if index < 0 and index > 27: | ||
index = index % 27 | ||
# print("ERROR : Index out of range") | ||
|
||
# Create line with all characters in lowercase except selected character | ||
characters = [chr(ord('a') + i) for i in range(26)] | ||
characters.append("<") | ||
characters.append("+") | ||
if index < 26: | ||
characters[index] = self.charactersUppercase[index] | ||
|
||
# Set current line "centered" on index when possible | ||
currentLine = "" | ||
if index >= 8 and index <= 19: | ||
for i in range(index - 7, index + 8): | ||
currentLine += characters[i] | ||
if index < 8: | ||
for i in range(0, 15): | ||
currentLine += characters[i] | ||
if index > 19: | ||
for i in range(13, 28): | ||
currentLine += characters[i] | ||
|
||
return currentLine | ||
|
||
|
||
|
||
# getCurrentCharacter(index) -> String (1 character) | ||
# Input : index (Int) | ||
# Output : String of 1 character in Uppercase | ||
# Only for alphabet (index between 0 and 25), do not handle back and enter | ||
def getCurrentCharacter(self, index): | ||
return self.charactersUppercase[index] |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
from enum import Enum | ||
|
||
DB_USER = 'pycock_tail' | ||
DB_PASSWORD = 'pycock_tail' | ||
DB_NAME = 'pycock_tail' | ||
DB_HOST = 'cyrildeschamps.fr' | ||
DB_PORT = 3306 | ||
|
||
|
||
|
||
class State(Enum): | ||
HOME = 0 | ||
AUTHENTIFICATION = 1 # Payload : {nextState} | ||
ACCOUNT_DETAILS = 4 | ||
SERVE_DRINK = 5 | ||
ERROR = 6 | ||
SHUTDOWN = 7 | ||
|
||
|
||
|
||
# Enum of the differents states of the machine accessible with in the menu | ||
# - Label must have a length of 12 characters max | ||
# - Maximum of 9 states | ||
class MenuState(Enum): | ||
SERVE_DRINK = (State.SERVE_DRINK, "Se servir") | ||
ACCOUNT_DETAILS = (State.ACCOUNT_DETAILS, "Mon compte") | ||
SHUTDOWN = (State.SHUTDOWN, "Eteindre") | ||
|
||
def __init__(self, state, label): | ||
self.state = state | ||
self.label = label | ||
|
||
|
||
# Enum of the quantity of the drink | ||
# - First value is the quantity in ml | ||
# - Second value is the label to display (max 12 char) | ||
class ServeQuantity(Enum): | ||
SMALL = (50, "5cl") | ||
LARGE = (200, "20cl") | ||
|
||
def __init__(self, quantity, label): | ||
self.quantity = quantity | ||
self.label = label |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from tortoise import Tortoise | ||
from config import DB_USER, DB_PASSWORD, DB_NAME, DB_HOST, DB_PORT | ||
|
||
async def initDatabase(): | ||
await Tortoise.init(config={ | ||
'connections': { | ||
'default': { | ||
'engine': 'tortoise.backends.mysql', | ||
'credentials': { | ||
'host': DB_HOST, | ||
'port': DB_PORT, | ||
'user': DB_USER, | ||
'password': DB_PASSWORD, | ||
'database': DB_NAME, | ||
} | ||
}, | ||
}, | ||
"apps": { | ||
"models": { | ||
"models": ["database.order", "database.recipe", "database.user"], | ||
'default_connection': 'default', | ||
} | ||
} | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from tortoise import fields | ||
from tortoise.models import Model | ||
from database.user import User | ||
from database.recipe import Recipe | ||
|
||
class Order(Model): | ||
id = fields.IntField(pk=True) | ||
quantity = fields.SmallIntField(default=1, nullable=False) | ||
created_at = fields.DatetimeField(auto_now_add=True) | ||
user: fields.ForeignKeyRelation[User] = fields.ForeignKeyField('models.User', related_name='orders') | ||
recipe: fields.ForeignKeyRelation[Recipe] = fields.ForeignKeyField('models.Recipe', related_name='orders') | ||
|
||
class Meta: | ||
table = 'orders' |
Oops, something went wrong.