Skip to content

Commit

Permalink
feat: initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
CyrilDesch committed Feb 3, 2024
0 parents commit d411052
Show file tree
Hide file tree
Showing 50 changed files with 2,525 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pycache__
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"python.analysis.extraPaths": [
"./cocktail-project/components"
]
}
21 changes: 21 additions & 0 deletions LICENSE
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.
11 changes: 11 additions & 0 deletions README.md
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.​
Binary file added block-chart.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
65 changes: 65 additions & 0 deletions cocktail-project/actions/ServeDrinkAction.py
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)
8 changes: 8 additions & 0 deletions cocktail-project/actions/ShutdownAction.py
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.
52 changes: 52 additions & 0 deletions cocktail-project/components/SelectionMenu.py
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
131 changes: 131 additions & 0 deletions cocktail-project/components/VirtualKeyboard.py
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.
43 changes: 43 additions & 0 deletions cocktail-project/config.py
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.
24 changes: 24 additions & 0 deletions cocktail-project/database/connection.py
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',
}
}
})
14 changes: 14 additions & 0 deletions cocktail-project/database/order.py
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'
Loading

0 comments on commit d411052

Please sign in to comment.