Skip to content

Commit

Permalink
Merge pull request #42 from AndreWohnsland/dev
Browse files Browse the repository at this point in the history
WS281x LED support
  • Loading branch information
AndreWohnsland authored Mar 2, 2023
2 parents 04d72b3 + fdb2982 commit fa7a0ec
Show file tree
Hide file tree
Showing 30 changed files with 444 additions and 148 deletions.
1 change: 1 addition & 0 deletions docs/about.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
This app is used to control a cocktail machine and easily prepare cocktails over a nice-looking user interface.
It also offers the option to create and manage your recipes and ingredients over the interface and calculates the possible cocktails to prepare over given ingredients.
Track and display cocktail data for different teams to even further increase the fun.
Have also a look into the [User Guide](assets/CocktailBerryUserGuide.pdf)
Let's get started!

## tl;dr
Expand Down
Binary file added docs/assets/CocktailBerryUserGuide.pdf
Binary file not shown.
13 changes: 12 additions & 1 deletion docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,15 @@ It's for some optional advanced features you can add anytime you are interested

If your pumps got a long tube to the bottle, the first cocktail may have too little volume.
You can set the `MAKER_TUBE_VOLUME` to an approximate value which corresponds to the average of the tube volume.
When applying a new bottle, CocktailBerry will also pump that much volume up.
When applying a new bottle, CocktailBerry will also pump that much volume up.

### Whats up with LEDs

You can define one or more pins which control a LED (array).
The LEDs will light up during cocktail preparation, as well when the cocktail is finished.
If it's an controllable WS28x LED you can activate the setting.
Instead of just turning on / off / blinking, the LED will then have some advanced light effects.
If you want to have multiple ring LEDs having the effect synchronously, you can define the number of identical daisy chained rings.
The program will then not treat this chain as one, but as multiple chains.
This does not include some default LEDs used for general lighting of the machine, because they usually don't need controlling.
It's better to directly connect them to the main source current and turn them on when the machine is turned on.
1 change: 1 addition & 0 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Usually, updating to the lastest version is always a good idea.
| **v1.11.0** | Internet check and time adjustment feature |
| **v1.13.1** | Clearing the database over the CLI |
| **v1.14.0** | Can invert pin, set simultaneous pump count, generic board |
| **v1.15.0** | Control a LED during cocktail preparation |

!!! abstract "And much More"
This list is by no means a full list of changes.
Expand Down
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ CocktailBerry can do:
- Keep track of cocktail count and volume from different teams for some fun competition
- Select different themes to fit your liking
- Switch between user interface languages
- Support WS281x LEDs on your machine

In addition, there is the possibility to use and set up a second device as a dashboard:

Expand Down
5 changes: 5 additions & 0 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ python3 runme.py # (1)!

1. Newer systems may execute python instead of python3

!!! note "This Should be All"
As long as you are on the recommended Raspberry Pi + OS, this should be all you need to execute for a complete setup.
This provided script will probably not properly work on other systems, since each OS may handle things differently.
If you are on another system, have a look into the other instructions, [faq](faq.md) or [troubleshooting](troubleshooting.md).

## Installing Requirements
The best way is to use the provided `requirements.txt` file.
If Python is installed, just run:
Expand Down
Binary file modified docs/pictures/Recipes_ui.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 33 additions & 28 deletions docs/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,34 +26,39 @@ If any of the values got a wrong data type, a ConfigError will be thrown with th
Names starting with `EXP` are experimental and may be changed in the future.
They can be used at own risk of CocktailBerry not working 100% properly.

| Value Name | Description |
| :--------------------------- | :----------------------------------------------------------------------------------- |
| `UI_DEVENVIRONMENT` | Enables some development features, like a cursor |
| `UI_PARTYMODE` | Protects other tabs than maker tab with a password |
| `UI_MASTERPASSWORD` | String for password, Use numbers for numpad like '1234' |
| `UI_LANGUAGE` | 2 char code for the language, see [supported languages](languages.md) |
| `UI_WIDTH` | Desired interface width, default is 800 |
| `UI_HEIGHT` | Desired interface height, default is 480 |
| `PUMP_PINS` | List of the [Pins](#configuring-the-pins-or-used-board) where each Pump is connected |
| `PUMP_VOLUMEFLOW` | List of the according volume flow for each pump in ml/s |
| `MAKER_BOARD` | Used [board](#configuring-the-pins-or-used-board) for Hardware |
| `MAKER_NAME` | Give your CocktailBerry an own name, max 30 chars |
| `MAKER_NUMBER_BOTTLES` | Number of displayed bottles, can use up to 16 bottles |
| `MAKER_SIMULTANEOUSLY_PUMPS` | Number of pumps which can be simultaneously active |
| `MAKER_SEARCH_UPDATES` | Search for updates at program start |
| `MAKER_PINS_INVERTED` | [Inverts](faq.md#what-is-the-inverted-option) pin signal (on=low, off=high) |
| `MAKER_THEME` | Choose which [theme](#themes) to use |
| `MAKER_CLEAN_TIME` | Time the machine will execute the cleaning program |
| `MAKER_SLEEP_TIME` | Interval between each time check while generating a cocktail |
| `MAKER_CHECK_INTERNET` | Do a connection check at start for time adjustment window |
| `MAKER_TUBE_VOLUME` | Volume in ml to pump up when bottle is set to new |
| `MICROSERVICE_ACTIVE` | Post to microservice set up by docker |
| `MICROSERVICE_BASE_URL` | Base URL for microservice (default: http://127.0.0.1:5000) |
| `TEAMS_ACTIVE` | Use teams feature |
| `TEAM_BUTTON_NAMES` | List of format ["Team1", "Team2"] |
| `TEAM_API_URL` | Endpoint of teams API, default used port by API is 8080 |
| `EXP_MAKER_UNIT` | Change the displayed unit in the maker tab (visual only\*) |
| `EXP_MAKER_FACTOR` | Multiply the displayed unit in the maker tab (visual only\*) |
| Value Name | Description |
| :--------------------------- | :--------------------------------------------------------------------------------------- |
| `UI_DEVENVIRONMENT` | Enables some development features, like a cursor |
| `UI_PARTYMODE` | Protects other tabs than maker tab with a password |
| `UI_MASTERPASSWORD` | String for password, Use numbers for numpad like '1234' |
| `UI_LANGUAGE` | 2 char code for the language, see [supported languages](languages.md) |
| `UI_WIDTH` | Desired interface width, default is 800 |
| `UI_HEIGHT` | Desired interface height, default is 480 |
| `PUMP_PINS` | List of the [Pins](#configuring-the-pins-or-used-board) where each Pump is connected |
| `PUMP_VOLUMEFLOW` | List of the according volume flow for each pump in ml/s |
| `MAKER_BOARD` | Used [board](#configuring-the-pins-or-used-board) for Hardware |
| `MAKER_NAME` | Give your CocktailBerry an own name, max 30 chars |
| `MAKER_NUMBER_BOTTLES` | Number of displayed bottles, can use up to 16 bottles |
| `MAKER_SIMULTANEOUSLY_PUMPS` | Number of pumps which can be simultaneously active |
| `MAKER_SEARCH_UPDATES` | Search for updates at program start |
| `MAKER_PINS_INVERTED` | [Inverts](faq.md#what-is-the-inverted-option) pin signal (on=low, off=high) |
| `MAKER_THEME` | Choose which [theme](#themes) to use |
| `MAKER_CLEAN_TIME` | Time the machine will execute the cleaning program |
| `MAKER_SLEEP_TIME` | Interval between each time check while generating a cocktail |
| `MAKER_CHECK_INTERNET` | Do a connection check at start for time adjustment window |
| `MAKER_TUBE_VOLUME` | Volume in ml to pump up when bottle is set to new |
| `LED_PINS` | List of pins connected to LEDs for preparation |
| `LED_BRIGHTNESS` | Brightness for the WS281x LED (1-255) |
| `LED_COUNT` | Number of LEDs on the WS281x |
| `LED_NUMBER_RINGS` | Number of IDENTICAL daisy chained WS281x LED rings |
| `LED_IS_WS` | Is the led a controllable WS281x LED, [see also](troubleshooting.md#get-the-led-working) |
| `MICROSERVICE_ACTIVE` | Post to microservice set up by docker |
| `MICROSERVICE_BASE_URL` | Base URL for microservice (default: http://127.0.0.1:5000) |
| `TEAMS_ACTIVE` | Use teams feature |
| `TEAM_BUTTON_NAMES` | List of format ["Team1", "Team2"] |
| `TEAM_API_URL` | Endpoint of teams API, default used port by API is 8080 |
| `EXP_MAKER_UNIT` | Change the displayed unit in the maker tab (visual only\*) |
| `EXP_MAKER_FACTOR` | Multiply the displayed unit in the maker tab (visual only\*) |

\* You still need to provide the units in ml for the DB (recipes / ingredients).
This is purely visual in the maker tab, at least for now.
Expand Down
27 changes: 27 additions & 0 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,24 @@ This new option tackles that. If it's set active with an active microservice, it
If there is no connection, a dialog will pop up and give the user the possibility to adjust the time.
In case the machine got a RTC build in and uses it, this option can usually be set to `false`, because due to the RTC, the time should be correct.

## Get the LED Working

Getting the WS281x to work may be a little bit tricky.
You MUST run the program as sudo (`sudo python runme.py`), so you also need to change this in `~/launcher.sh`.
If the GUI looks different than when you run it without sudo, try `sudo -E python runme.y` this should use your environment for Qt.
If you ran the program as non root, you will need to install the required python packages for the main program with sudo pip install.
Also, install the rpi_ws281x python package with:

```
sudo pip install rpi_ws281x
sudo pip install PyQt5 requests pyyaml GitPython typer pyfiglet qtawesome
```

See [here](https://github.com/jgarff/rpi_ws281x#gpio-usage) for a possible list and explanation for GPIOs.
I had success using the 12 and 18 PWM0 pin, while also disabling (use a # for comment) the line `#dtparam=audio=on` on `/boot/config.txt`.
Other described pins may also work, but are untested, so I recommend to stick to the both one that should work.
If you use any other non controllable LED connected over the relay, you can use any pin you want, since it's only activating the relay.


## Ui Seems Wrong on none RaspOS System
On different Linux systems (other than the recommended Raspbian OS), there may be differences in the look and functionality of the user interface.
Expand All @@ -97,6 +115,14 @@ Please take note that CocktailBerry will run on other systems than the Raspberry
Since I probably don't own that combination of Hardware and OS, you probably need to figure out that settings by yourself.
If you are a unexperienced user with Linux, I recommend you stick to the recommended settings on a Pi.

## Task Bar Overlap / Push GUI

This may happen (especially at older versions os RPi OS or higher res screens) when running the program and some dialog window opens.
The task bar (bar with programs on it) may overlap the dialog window or push it down by it's height.
Ensure that you have unchecked the "Reserve space, and not covered by maximised windows" option.
You can find it under the panel preferences (right click the task bar > panel settings > Advanced).
Unchecking this box usually fixes this problem.

## Problems Installing Software on Raspberry Pi

The Raspberry Pi can sometimes differ from other machines in terms of installation. Here are some issues that might occur.
Expand Down Expand Up @@ -162,6 +188,7 @@ sudo chmod 755 ~/launcher.sh
I've noticed when running as root (sudo python3) and running as the pi user (python3) by default the pi will use different GUI resources.
Using the pi user will result in the shown interfaces at CocktailBerry (and the program should work without root privilege).
Setting the XDG_RUNTIME_DIR to use the qt5ct plugin may also work but is untested.
Using the users environment with `sudo -E python runme.py` should also do the trick.

### Some Python Things do not Work

Expand Down
34 changes: 18 additions & 16 deletions microservice/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@
import requests
from dotenv import load_dotenv
from flask import Flask, request, abort, jsonify
from flask.logging import create_logger

from querry_sender import try_send_querry_data
from email_sender import send_mail
from query_sender import try_send_query_data
from database import DatabaseHandler
from helper import generate_urls_and_headers

load_dotenv()

app = Flask(__name__)
logging.basicConfig(level=logging.INFO)
_logger = create_logger(app)


@app.route("/")
Expand All @@ -27,21 +28,21 @@ def welcome():

@app.route("/hookhandler/cocktail", methods=["POST"])
def post_cocktail_hook():
def post_to_hook(url: str, payload: str, headers: Dict, send_querry: bool):
def post_to_hook(url: str, payload: str, headers: Dict, send_query: bool):
try:
req = requests.post(url, data=payload, headers=headers)
app.logger.info(f"{req.status_code}: Posted to {url} with payload: {payload}")
req = requests.post(url, data=payload, headers=headers, timeout=10)
_logger.info("%s: Posted to %s with payload: %s", req.status_code, url, payload)
# Check if there is still querries data which was not send previously
# Needs to be specified to send, since multiple threads would cause double sending
if send_querry:
try_send_querry_data(app)
if send_query:
try_send_query_data(app)
except requests.exceptions.ConnectionError:
app.logger.error(f"Could not connect to {url} for the cocktail data!")
_logger.error("Could not connect to %s for the cocktail data!", url)
db_handler = DatabaseHandler()
db_handler.save_failed_post(payload, url, headers)
# pylint: disable=broad-except
except Exception as err:
app.logger.error(f"Some other error occured: {err}")
_logger.error("Some other error occurred: %s", err)

if not request.json or "cocktailname" not in request.json:
abort(400)
Expand All @@ -59,26 +60,27 @@ def post_to_hook(url: str, payload: str, headers: Dict, send_querry: bool):
return jsonify({"text": "No endpoints activated"}), 201

for pos, (url, headers) in enumerate(endpoint_data):
send_querry = pos == 0
thread = Thread(target=post_to_hook, args=(url, payload, headers, send_querry,))
send_query = pos == 0
thread = Thread(target=post_to_hook, args=(url, payload, headers, send_query,))
thread.start()
return jsonify({"text": "Post to cocktail webhook started"}), 201


@app.route("/email", methods=["POST"])
@app.route("/data-export", methods=["POST"])
def post_file_with_mail():
data_file = request.files["upload_file"]
text = send_mail(data_file.filename, data_file)
app.logger.info(text)
# TODO: Implement new sender / Endpoint
text = f"Not implemented sending data. Datatype is {type(data_file)}"
_logger.info(text)
return jsonify({"text": text}), 200


@app.route("/debug", methods=["POST"])
def debug_ep():
app.logger.info(request.json)
_logger.info(request.json)
return jsonify({"text": "debug"}), 200


if __name__ == "__main__":
try_send_querry_data(app)
try_send_query_data(app)
app.run(host="0.0.0.0", port=int(os.getenv("PORT", "5000")))
4 changes: 2 additions & 2 deletions microservice/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ def delete_failed_by_id(self, data_id: int):
sql = "DELETE FROM Querry WHERE ID = ?"
self.query_database(sql, (data_id,))

def query_database(self, sql: str, serachtuple=()):
self.cursor.execute(sql, serachtuple)
def query_database(self, sql: str, serach_tuple=()):
self.cursor.execute(sql, serach_tuple)
if sql[0:6].lower() == "select":
result = self.cursor.fetchall()
else:
Expand Down
47 changes: 0 additions & 47 deletions microservice/email_sender.py

This file was deleted.

Loading

0 comments on commit fa7a0ec

Please sign in to comment.