Skip to content

Commit

Permalink
Merge pull request #14 from AndreWohnsland/dev
Browse files Browse the repository at this point in the history
More bottle support
  • Loading branch information
AndreWohnsland authored Mar 9, 2022
2 parents 1a22936 + 030b4a7 commit 6e14bb7
Show file tree
Hide file tree
Showing 13 changed files with 3,352 additions and 1,229 deletions.
Binary file modified Cocktail_database_default.db
Binary file not shown.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "CocktailBerry"
version = "1.6.0"
version = "1.6.1"
description = "A Python and Qt based App for a Cocktail Machine on a Raspberry Pi. Easily serve Cocktails with Raspberry Pi and Python"
authors = ["Andre Wohnsland <Andre_Wohnsland@web.de>"]
readme = "readme.md"
Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ These values are stored under the `custom_config.yaml` file. This file will be c
| `UI_HEIGHT` | _int_ | Desired interface height, default is 480 | ❌ |
| `PUMP_PINS` | _list[int]_ | List of the RPi-Pins where each Pump is connected | ❌ |
| `PUMP_VOLUMEFLOW` | _list[int]_ | List of the according volume flow for each pump in ml/s | ❌ |
| `MAKER_NUMBER_BOTTLES` | _int_ | Number of displayed bottles. Can use up to ten bottles | ❌ |
| `MAKER_NUMBER_BOTTLES` | _int_ | Number of displayed bottles. Can use up to 16 bottles | ❌ |
| `MAKER_SEARCH_UPDATES` | _bool_ | Boolean flag to search for updates at program start | ❌ |
| `MAKER_CLEAN_TIME` | _int_ | Time the machine will execute the cleaning program | ❌ |
| `MAKER_SLEEP_TIME` | _float_ | Interval between each UI refresh while generating a cocktail | ❌ |
Expand Down
3 changes: 2 additions & 1 deletion src/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
__version__ = "1.6.0"
__version__ = "1.6.1"
PROJECT_NAME = "CocktailBerry"
MAX_SUPPORTED_BOTTLES = 16
38 changes: 31 additions & 7 deletions src/config_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
from typing import List
import typer
import yaml
from src.logger_handler import LoggerHandler

from src.models import Ingredient
from src import __version__, PROJECT_NAME
from src import __version__, PROJECT_NAME, MAX_SUPPORTED_BOTTLES


CONFIG_FILE = Path(__file__).parents[1].absolute() / "custom_config.yaml"
logger = LoggerHandler("config_manager", "production_logs")


class ConfigManager:
Expand Down Expand Up @@ -72,13 +74,15 @@ def sync_config_to_file(self):
yaml.dump(config, stream, default_flow_style=False)

def __read_config(self):
"""Reads all the config data from the file and validates it"""
with open(CONFIG_FILE, "r", encoding="UTF-8") as stream:
configuration = yaml.safe_load(stream)
for k, value in configuration.items():
self.__validate_config_type(k, value)
setattr(self, k, value)

def __validate_config_type(self, configname, configvalue):
"""validates the configvalue if its fit the type / conditions"""
config_type = {
"UI_DEVENVIRONMENT": bool,
"UI_PARTYMODE": bool,
Expand All @@ -104,18 +108,34 @@ def __validate_config_type(self, configname, configvalue):
if isinstance(configvalue, list):
self.__validate_config_list_type(configname, configvalue)
return
raise ValueError(f"The config option {configname} is not of type {datatype}")
raise ConfigError(f"The config option {configname} is not of type {datatype}")

def __validate_config_list_type(self, configname, configlist):
"""Extra validation for list type in case len / types"""
min_bottles = self._choose_bottle_number()
config_type = {
"PUMP_PINS": int,
"PUMP_VOLUMEFLOW": int,
"TEAM_BUTTON_NAMES": str,
"PUMP_PINS": (int, min_bottles),
"PUMP_VOLUMEFLOW": (int, min_bottles),
"TEAM_BUTTON_NAMES": (str, 2),
}
datatype = config_type.get(configname)
datatype, min_len = config_type.get(configname)
for i, config in enumerate(configlist, 1):
if not isinstance(config, datatype):
raise ValueError(f"The {i} position of {configname} is not of type {datatype}")
raise ConfigError(f"The {i} position of {configname} is not of type {datatype}")
# aditional len check of the list data,
self.__validate_list_length(configlist, configname, min_len)

def __validate_list_length(self, configlist, configname, min_len):
"""Checks if the list is at least a given size"""
actual_len = len(configlist)
if actual_len < min_len:
raise ConfigError(f"{configname} is only {actual_len} elements, but you need at least {min_len} elements")

def _choose_bottle_number(self, get_all=False):
"""Selects the number of Bottles, limits by max supported count"""
if get_all:
return MAX_SUPPORTED_BOTTLES
return min(self.MAKER_NUMBER_BOTTLES, MAX_SUPPORTED_BOTTLES)


class Shared:
Expand All @@ -129,6 +149,10 @@ def __init__(self):
self.handaddlist: List[Ingredient] = []


class ConfigError(Exception):
"""Raised when there was an error with the configuration data"""


def version_callback(value: bool):
if value:
typer.echo(f"{PROJECT_NAME} Version {__version__}. Created by Andre Wohnsland.")
Expand Down
2 changes: 1 addition & 1 deletion src/database_commander.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ def create_tables(self):

# Creating the Space Naming of the Bottles
for bottle_count in range(1, 13):
self.cursor.execute("INSERT INTO Bottles(Bottle) VALUES (?)", (bottle_count))
self.cursor.execute("INSERT INTO Bottles(Bottle) VALUES (?)", (bottle_count,))
self.database.commit()
self.database.close()

Expand Down
21 changes: 8 additions & 13 deletions src/display_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from src.dialog_handler import DialogHandler, UI_LANGUAGE
from src.models import Cocktail, Ingredient
from src.config_manager import shared
from src import MAX_SUPPORTED_BOTTLES


class DisplayController(DialogHandler):
Expand Down Expand Up @@ -421,17 +422,17 @@ def set_label_bottles(self, w, label_names: List[str]):
# Migration from supporter.py
def get_pushbottons_newbottle(self, w, get_all=False):
"""Returns all new bottles toggle button objects"""
number = self.__choose_bottle_number(get_all)
number = self._choose_bottle_number(get_all)
return [getattr(w, f"PBneu{x}") for x in range(1, number + 1)]

def get_levelbar_bottles(self, w, get_all=False):
"""Returns all bottles progress bar objects"""
number = self.__choose_bottle_number(get_all)
number = self._choose_bottle_number(get_all)
return [getattr(w, f"ProBBelegung{x}") for x in range(1, number + 1)]

def get_comboboxes_bottles(self, w, get_all=False):
"""Returns all bottles combo box objects"""
number = self.__choose_bottle_number(get_all)
number = self._choose_bottle_number(get_all)
return [getattr(w, f"CBB{x}") for x in range(1, number + 1)]

def get_comboboxes_recipes(self, w):
Expand All @@ -448,7 +449,7 @@ def get_ingredient_fields(self, w):

def get_label_bottles(self, w, get_all=False):
"""Returns all bottles label objects"""
number = self.__choose_bottle_number(get_all)
number = self._choose_bottle_number(get_all)
return [getattr(w, f"LBelegung{x}") for x in range(1, number + 1)]

def get_labels_maker_volume(self, w):
Expand All @@ -459,23 +460,17 @@ def get_labels_maker_ingredients(self, w):
"""Returns all maker label objects for ingredient name"""
return [getattr(w, f"LZutat{x}") for x in range(1, 10)]

def __choose_bottle_number(self, get_all):
"""Selects the number of Bottles in the bottles tab, all is ten"""
if get_all:
return 10
return min(self.MAKER_NUMBER_BOTTLES, 10)

def get_numberlabel_bottles(self, w, get_all=False):
"""Returns all label object for the number of the bottle"""
number = self.__choose_bottle_number(get_all)
number = self._choose_bottle_number(get_all)
return [getattr(w, f"bottleLabel{x}") for x in range(1, number + 1)]

def adjust_bottle_number_displayed(self, w):
"""Removes the UI elements if not all ten bottles are used per config"""
used_bottles = min(self.MAKER_NUMBER_BOTTLES, 10)
used_bottles = self._choose_bottle_number()
# This needs to be done to get rid of registered bottles in the then removed bottles
all_bottles = DB_COMMANDER.get_ingredients_at_bottles()
DB_COMMANDER.set_bottleorder(all_bottles[:used_bottles] + [""] * (10 - used_bottles))
DB_COMMANDER.set_bottleorder(all_bottles[:used_bottles] + [""] * (MAX_SUPPORTED_BOTTLES - used_bottles))
comboboxes_bottles = self.get_comboboxes_bottles(w, True)
self.set_multiple_combobox_to_top_item(comboboxes_bottles[used_bottles::])
to_adjust = [
Expand Down
12 changes: 12 additions & 0 deletions src/migrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ def make_migrations(self):
logger.log_event("INFO", "Making migrations for v1.6.0")
self.__change_git_repo()
self.__install_pip_package("pyfiglet", "1.6.0")
if self.older_than_version("1.6.1"):
logger.log_event("INFO", "Making migrations for v1.6.1")
self.__add_more_bottles_to_db()
self.__check_local_version_data()

def __check_local_version_data(self):
Expand Down Expand Up @@ -105,6 +108,15 @@ def __rename_database_to_english(self):
except OperationalError:
pass

def __add_more_bottles_to_db(self):
"""Updates the bottles to support up to 16 bottles"""
logger.log_event("INFO", "Adding bottle numbers 11 to 16 to DB")
db_handler = DatabaseHandler()
# Adding constraint if still missing
db_handler.query_database("CREATE UNIQUE INDEX IF NOT EXISTS idx_bottle ON Bottles(Bottle)")
for bottle_count in range(11, 17):
db_handler.query_database("INSERT OR IGNORE INTO Bottles(Bottle) VALUES (?)", (bottle_count,))

def __add_team_buffer_to_database(self):
"""Adds an additional table for buffering not send team data"""
logger.log_event("INFO", "Adding team buffer table to database")
Expand Down
21 changes: 9 additions & 12 deletions src/ui/setup_bottle_window.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtCore import Qt

from src.ui_elements.bottlewindow import Ui_Bottlewindow
from PyQt5.QtCore import Qt

from src.config_manager import ConfigManager
from src.bottles import set_fill_level_bars
from src.database_commander import DB_COMMANDER
from src.dialog_handler import UI_LANGUAGE
from src.display_controller import DP_CONTROLLER
from src import MAX_SUPPORTED_BOTTLES


class BottleWindow(QMainWindow, Ui_Bottlewindow, ConfigManager):
Expand All @@ -30,11 +31,11 @@ def __init__(self, parent=None):
self.maxvolume = []
self.asign_bottle_data()
# creates lists of the objects and assings functions later through a loop
number = self.__choose_bottle_number()
myplus = [getattr(self, f"PBMplus{x}") for x in range(1, 11)]
myminus = [getattr(self, f"PBMminus{x}") for x in range(1, 11)]
mylabel = [getattr(self, f"LAmount{x}") for x in range(1, 11)]
myname = [getattr(self, f"LName{x}") for x in range(1, 11)]
number = self._choose_bottle_number()
myplus = [getattr(self, f"PBMplus{x}") for x in range(1, MAX_SUPPORTED_BOTTLES + 1)]
myminus = [getattr(self, f"PBMminus{x}") for x in range(1, MAX_SUPPORTED_BOTTLES + 1)]
mylabel = [getattr(self, f"LAmount{x}") for x in range(1, MAX_SUPPORTED_BOTTLES + 1)]
myname = [getattr(self, f"LName{x}") for x in range(1, MAX_SUPPORTED_BOTTLES + 1)]

# since zip only goes to the minimal of all, only one [:number] is needed
for plus, minus, field, vol in zip(myplus, myminus, mylabel[:number], self.maxvolume):
Expand All @@ -52,17 +53,13 @@ def __init__(self, parent=None):
self.showFullScreen()
DP_CONTROLLER.set_display_settings(self)

def __choose_bottle_number(self):
"""Selects the number of Bottles in the bottles tab, all is ten"""
return min(self.MAKER_NUMBER_BOTTLES, 10)

def abbrechen_clicked(self):
""" Closes the Window without a change. """
self.close()

def eintragen_clicked(self):
""" Enters the Data and closes the window. """
number = self.__choose_bottle_number()
number = self._choose_bottle_number()
labelname = [getattr(self, f"LAmount{i}") for i in range(1, number + 1)]
for label, ingredient_id, maxvolume in zip(labelname, self.id_list, self.maxvolume):
new_amount = min(int(label.text()), maxvolume)
Expand All @@ -71,7 +68,7 @@ def eintragen_clicked(self):
self.close()

def asign_bottle_data(self):
number = self.__choose_bottle_number()
number = self._choose_bottle_number()
bottle_data = DB_COMMANDER.get_bottle_data_bottle_window()[:number]
for i, (ingredient_name, bottle_level, ingredient_id, ingredient_volume) in enumerate(bottle_data, start=1):
labelobj = getattr(self, f"LName{i}")
Expand Down
Loading

0 comments on commit 6e14bb7

Please sign in to comment.