diff --git a/.gitignore b/.gitignore index a9fbe25..a306745 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ /node_modules /public/images/ /config.json -/yarn-error.log \ No newline at end of file +/yarn-error.log +/docs/ diff --git a/arduino/itender/itender.ino b/arduino/itender/itender.ino index 419b4ae..5ae5d99 100644 --- a/arduino/itender/itender.ino +++ b/arduino/itender/itender.ino @@ -2,6 +2,7 @@ * Official proxy code for iTender GPIO Communication **/ #include +#include "HX711.h" // Define the size of the JSON buffer #define JSON_BUFFER_SIZE 256 @@ -10,17 +11,16 @@ StaticJsonDocument incomingJson; // Create a JSON object for outgoing messages -DynamicJsonDocument outgoingJson; +DynamicJsonDocument outgoingJson(JSON_BUFFER_SIZE); void setup() { // Initialize serial communication Serial.begin(9600); } -void(* resetFunc) (void) = 0; //declare reset function @ address 0 +void (*resetFunc)(void) = 0; //declare reset function @ address 0 void loop() { - // Wait for a new line on the serial console if (Serial.available()) { // Read the incoming JSON message DeserializationError error = deserializeJson(incomingJson, Serial); @@ -29,43 +29,74 @@ void loop() { } else { // Extract the "type" and "data" fields from the JSON object String id = incomingJson["id"]; - String type = incomingJson["type"]; + int type = incomingJson["type"]; JsonVariant data = incomingJson["data"]; // Create a nested object in the root object JsonObject outgoingData = outgoingJson.to().createNestedObject("data"); - outgoingData["success"] = true; + outgoingData["success"] = true; // Handle the message based on the "type" field switch (type) { - case "ACK": - // Handle ACK message - break; - case "SET_PIN": + case 1: // Handle SET_PIN message + pinMode((int)data["pin"], OUTPUT); + if (data["mode"] == "DIGITAL") { + digitalWrite((int)data["pin"], data["value"]); + } else { + analogWrite((int)data["pin"], (data["value"] == 255) ? HIGH : LOW); + } break; - case "GET_VAL": + case 2: // Handle GET_VAL message + pinMode((int)data["pin"], INPUT); + int val; + if (data["mode"] == "DIGITAL") { + val = digitalRead((int)data["pin"]); + } else { + val = analogRead((int)data["pin"]); + } break; - case "GET_SENSOR": + case 3: // Handle GET_SENSOR message + + /* + (WEIGHT_VAL - NO_WEIGHT_VAL) / Sensitivitätsfaktor = Gewicht in Gramm + (WEIGHT_VAL - NO_WEIGHT_VAL) / (100g_val /100) ist die Formel zur Berechnung des Gewichts in Gramm nach der Kalibrierung mit einem 100 Gramm Gewicht. + 100g_val /100 gibt den Sensitivitätsfaktor an, der angibt, wie viel sich der Sensorwert ändert, wenn sich das Gewicht um ein Gramm ändert. + Durch die Division von 100g_val durch 100 wird der Sensitivitätsfaktor berechnet, und durch die Division von (WEIGHT_VAL - NO_WEIGHT_VAL) durch den Sensitivitätsfaktor wird das Gewicht in Gramm berechnet. + + Beispiel: + (WEIGHT_VAL - NO_WEIGHT_VAL) / (100g_val /100) = Gewicht in Gramm + (2400 - 2000) / (2450 /100) = 80 Gramm + */ + // HX711 circuit wiring + const int LOADCELL_DATA_PIN = (int)data["pin_data"]; + const int LOADCELL_CLOCK_PIN = (int)data["pin_clock"]; + HX711 scale; + scale.begin(LOADCELL_DATA_PIN, LOADCELL_CLOCK_PIN); + + // Get the weight value from the scale + long weight_val = scale.get_units(); + outgoingData["value"] = weight_val; break; - case "RESTART": + case 4: resetFunc(); //call reset break; default: // Handle unknown message type + outgoingData[""] = 0; break; } // Prepare the outgoing JSON message outgoingJson["id"] = id; - outgoingJson["type"] = type; - outgoingJson["data"] = ""; + outgoingJson["type"] = 0; + outgoingJson["data"] = outgoingData; // Send the outgoing JSON message serializeJson(outgoingJson, Serial); } } -} \ No newline at end of file +} diff --git a/arduino/itender/tare.ino b/arduino/itender/tare.ino index 8b497d5..d0528c1 100644 --- a/arduino/itender/tare.ino +++ b/arduino/itender/tare.ino @@ -1,4 +1,3 @@ -/** #include "HX711.h" @@ -7,37 +6,45 @@ const int LOADCELL_SCK_PIN = 3; HX711 scale; -int minus = 0; +long scale_factor = 0; +long no_weight = 0; -void setup() { +void tare() { // put your setup code here, to run once: Serial.begin(9600); delay(1000); - Serial.println("TARE"); + Serial.println("Alle Gewichte entfernen..."); scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN); - scale.set_scale(429.6159259259259); - scale.tare(); + delay(4000); + Serial.println("[Measureing]"); + + Serial.print("Null-Gewicht: "); + no_weight = scale.get_units(3); + Serial.println(no_weight); delay(1000); - minus=abs(scale.get_units(5)); - // scale.set_scale(); - // scale.tare(); - // Serial.println("TARE OK - PLACE WEIGHT"); - //delay(5000); + Serial.println("100g Gewicht platzieren..."); + delay(4000); + + Serial.print("100g-Gewicht: "); + scale_factor = scale.get_units(3); + Serial.println(scale_factor); + + scale_factor = scale_factor / 100; + Serial.print("Skalierungsfaktor: "); + Serial.println(scale_factor); + + delay(2000); } int len = 0; long sum = 0; -void loop() { - if (scale.is_ready()) { - long data = scale.get_units(5) + minus; - Serial.println(data); - - } - +void tare_loop() { + delay(2000); + long val = scale.get_units(1); + // (WEIGHT_VAL - NO_WEIGHT_VAL) / (100g_val /100) = Gewicht in Gramm + Serial.println( ( val - no_weight ) / scale_factor ); } - -**/ diff --git a/doc/Notes.md b/doc/Notes.md deleted file mode 100644 index 33dc6ca..0000000 --- a/doc/Notes.md +++ /dev/null @@ -1,68 +0,0 @@ -# ### Achtung! \### -Diese Datei ist nicht mehr aktuell.
-Bitte nutze die neue Wiki unter [https://git.gaminggeneration.de/tobiash/itender/wiki](https://git.gaminggeneration.de/tobiash/itender/wiki) (Wiki des iTender Projekts) - -











- - - -# Notes und kleine Dokumentation - -Was haben wir bereits am iTender Projekt gemacht? - -
- -## Konzept-Erstellung - -#### Ideen - -- Grund-Ideen - - Smarten Cocktail-Mischer - - 4 Getränke Behälter (mit Saft, Sirup oder Likör bzw. Schnapps) - - 4 Pumpen (Peristaltik Pumpe) - - Raspberry Pi als Prozessoreinheit - - Display in der Front mit Benutzeroberfläche - - Automatisches filtern von Getränken, je nachdem welche "Zutaten" in den Behältern sind - - Messung der aktuellen Füllmenge der Behälter, basierend auf Gewicht (mittels Wägezelle) oder Abstand zur - Wasseroberfläche (mittels Ultraschall-Sensor) - -- Nice to have - - LED-Stripes für schöne Beleuchtung, basierend auf dem aktuellen Status der Maschine - - Extra Schlauch für weitere außenstehende Getränke - - Mit Bier-Fass Adapter? - - Kühlung der Container mittels Peltierelement und Lüftern - -#### Erstes 3D-Modell - - - - -#### Neues 3D-Modell - - - - - -
- -## Das Programm - -#### Aufbau - -- Das Programm des iTenders ist getrennt in 3 Teile -- iTender Basis - - Die Basis besteht aus der Kommunikation zwischen den Pumpen, LEDs und jeglicher Hardware - - Außerdem gibt es Timer, automatische Events, Prüfung und aktualisierung von Getränken etc. - - Sie übernimmt z.B. das Starten vom Getränke-Füllen, stoppen sowie Berechnen von den Zutaten für ein Getränk - - Dieser Teil arbeitet seh eng mit dem Websocket-Server zusammen, um so auf Events vom Endnutzer zu reagieren. -- iTender Webserver - - Der Webserver ist einfach ein statischer Webserver welche Dateien "serviert", die dann von der Oberfläche geladen werden können. - - Der Client-Browser oder iTender-Display lädt dann diese Seite, erstmal passiert dann noch nichts -- iTender Websocket-Server - - Der Websocket-Server dient zur eigentlichen Live-Kommunikation zwischen Client und Gerät. - - Der Server und die Webseite (Endgerät), bauen eine Ende-zu-Ende Verbindung auf - - Die Kommunikation zwischen Client und Websocket-Server basiert auf JSON (Javascript-Objekt-Notation). - - Da der Websocket in früheren Client-Versionen anfällig für Fehler beim Übertragen von nicht alphabetischen Zeichen war, wird der gesendete Inhalt noch in Base64-Kodiert. - - Base64 dient dazu, die Daten binär zu kodieren, um sie auf der Gegenstelle wieder zu entkodieren. - - Außerdem wird beim übertragen eine Checksumme mitgegeben, um bei Fehlerhaften Paketen ein neues anzufragen. - diff --git a/doc/Screenshot_Model1.1_BackDownLeft.png b/doc/Screenshot_Model1.1_BackDownLeft.png deleted file mode 100644 index 3e1e8fc..0000000 Binary files a/doc/Screenshot_Model1.1_BackDownLeft.png and /dev/null differ diff --git a/doc/Screenshot_Model1.1_FrontTopRight.png b/doc/Screenshot_Model1.1_FrontTopRight.png deleted file mode 100644 index 26f3406..0000000 Binary files a/doc/Screenshot_Model1.1_FrontTopRight.png and /dev/null differ diff --git a/doc/Screenshot_Model1.2_Back.png b/doc/Screenshot_Model1.2_Back.png deleted file mode 100644 index 474a7c3..0000000 Binary files a/doc/Screenshot_Model1.2_Back.png and /dev/null differ diff --git a/doc/Screenshot_Model1.2_Front.png b/doc/Screenshot_Model1.2_Front.png deleted file mode 100644 index b172f31..0000000 Binary files a/doc/Screenshot_Model1.2_Front.png and /dev/null differ diff --git a/doc/autostart.config b/doc/autostart.config deleted file mode 100644 index a89b477..0000000 --- a/doc/autostart.config +++ /dev/null @@ -1,33 +0,0 @@ -# -# These things are run when an Openbox X Session is started. -# You may place a similar script in $HOME/.config/openbox/autostart -# to run user-specific things. -# - -# If you want to use GNOME config tools... -# -#if test -x /usr/lib/aarch64-linux-gnu/gnome-settings-daemon >/dev/null; then -# /usr/lib/aarch64-linux-gnu/gnome-settings-daemon & -#elif which gnome-settings-daemon >/dev/null 2>&1; then -# gnome-settings-daemon & -#fi - -# If you want to use XFCE config tools... -# -#xfce-mcs-manager & - -xset s off -xset s noblank -xset -dpms - -setxkbmap -option terminate:ctrl_alt_bksp - -# Start Chromium in kiosk mode -sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' ~/.config/chromium/'Local State' -sed -i 's/"exited_cleanly":false/"exited_cleanly":true/; s/"exit_type":"[^"]\+"/"exit_type":"Normal"/' ~/.config/chromium/Default/Preferences - -/usr/bin/chromium-browser --disable-infobars --kiosk --incognito --disable-pinch --overscroll-history-navigation=0 http://192.168.1.186:3000/ - - - - diff --git a/doc/installPi.sh b/doc/installPi.sh deleted file mode 100644 index 5743519..0000000 --- a/doc/installPi.sh +++ /dev/null @@ -1,220 +0,0 @@ -#!/bin/bash - -if [ "$EUID" -ne 0 ]; then - echo "Please run as root!" - exit -fi - -echo "Creating user if not exists" -useradd -p $(openssl passwd -1 iTender2022) itender || true - -echo "Updating indexes" -apt update - -echo "Installing xserver xinit openbox ufw xserver-xorg x11 unclutter make chromium-browser crontab cmake g++ gcc and git..." -apt install --no-install-recommends ufw xserver-xorg x11-xserver-utils xinit openbox -y || exit -apt install git gcc g++ make cmake chromium-browser unclutter iptables cron -y || exit -echo "Try to uninstall node and npm... (Can fail)" -apt purge node -y || true -apt purge npm -y || true - -echo "Setup xserver..." -# XServer -echo "allowed_users=anybody" >/etc/X11/Xwrapper.config -#no-uncomment cp autostart.config /etc/xdg/openbox/autostart - -echo "Adding apt keys..." -# Keys and stuff --- -# Nodejs -curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - -# Yarn -curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | sudo tee /usr/share/keyrings/yarnkey.gpg >/dev/null -echo "deb [signed-by=/usr/share/keyrings/yarnkey.gpg] https://dl.yarnpkg.com/debian stable main" | sudo tee /etc/apt/sources.list.d/yarn.list - -# MongoDB -wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add - -echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list - -# End Keys and stuff --- - -echo "Updating firewall..." -# Firewall -ufw allow ssh -ufw allow 3000/tcp -ufw allow 3015/tcp -ufw --force enable - -echo "Updating indexes..." -# Final update -apt update -echo "Installing mongodb and yarn..." -apt install nodejs yarn mongodb-org -y -apt upgrade -y - -# V2: Arduino CLI -echo "Installing arduino-cli..." -sudo -u itender mkdir -p /home/itender/bin -sudo -u itender sh -c 'curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=/home/itender/bin/ sh' -sudo -u itender /home/itender/bin/arduino-cli config init -sudo -u itender /home/itender/bin/arduino-cli core update-index || true -sudo -u itender /home/itender/bin/arduino-cli lib search ArduinoJson || true -sudo -u itender /home/itender/bin/arduino-cli lib install ArduinoJson || true - - - -echo "Installing autostart..." -# Autostart -cat </etc/xdg/openbox/autostart -xset s off -xset s noblank -xset -dpms -setxkbmap -option terminate:ctrl_alt_bksp - -# Start Chromium in kiosk mode -sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' ~/.config/chromium/'Local State' -sed -i 's/"exited_cleanly":false/"exited_cleanly":true/; s/"exit_type":"[^"]\+"/"exit_type":"Normal"/' ~/.config/chromium/Default/Preferences - -/usr/bin/chromium-browser --disable-infobars --kiosk --incognito --disable-pinch --overscroll-history-navigation=0 "http://127.0.0.1:3000/" & -EOT - -echo "Setting to console autologin..." -raspi-config nonint do_boot_behaviour B2 - -echo "Installing bashrc" -echo "clear" >>/home/itender/.bashrc -echo "[[ -z \$DISPLAY && \$XDG_VTNR -eq 1 ]] && startx -- -nocursor >/dev/null 2>&1" >>/home/itender/.bashrc -# -#echo "Installing start.sh" -#cat <>/home/itender/start.sh -##!/bin/bash -#cd /home/itender/ || exit -#sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' ~/.config/chromium/'Local State' -#sed -i 's/"exited_cleanly":false/"exited_cleanly":true/; s/"exit_type":"[^"]\+"/"exit_type":"Normal"/' ~/.config/chromium/Default/Preferences -# -#address="localhost" -# -#echo "Waiting 5 seconds to start chromium..." -#sleep 5 -#/usr/bin/chromium-browser --disable-infobars --kiosk --incognito --disable-pinch --overscroll-history-navigation=0 "http://\${address}:3000/" -##/usr/bin/startx /usr/bin/chromium-browser --kiosk --incognito --disable-pinch --overscroll-history-navigation=0 http://192.168.1.186:3000/ -#EOT -#chmod +x /home/itender/start.sh - -DIR="/home/itender/itender/" -if [ -d "$DIR" ]; then - # Take action if $DIR exists. # - cd "$DIR" || exit - echo "Updating..." - git pull -else - echo "Cloning..." - sudo -u itender git config --global credential.helper store - git config --global credential.helper store - git clone "https://tobiash:!IwedwrimmVeudiweN!@git.gaminggeneration.de/tobiash/itender.git" --quiet -fi -cd "$DIR" || exit -yarn install -echo "Compiling..." -yarn run compile - -echo "Updating Cron..." -# Add line to cron -echo "@reboot sudo chmod g+rw /dev/tty?" >/tmp/currentCron -#echo "@reboot cd /home/itender/itender/ && /usr/bin/yarn run start &" >> /tmp/currentCron -chown itender:itender /tmp/currentCron -#install new cron file -sudo -u itender crontab /tmp/currentCron - -echo "Installing systemd service..." -cat </etc/systemd/system/itender.service -[Unit] -Description=iTender App -After=network.target mongod.service -StartLimitIntervalSec=1 -StartLimitBurst=1000 - -[Service] -Type=simple -Restart=always -RestartSec=1s -User=itender -ExecStartPre=sleep 3 -WorkingDirectory=/home/itender/itender/ -ExecStart=/usr/bin/yarn run start -StandardOutput=append:/var/log/itender.log -StandardError=append:/var/log/itender.log - -[Install] -WantedBy=multi-user.target - -EOT -#sh -c "git pull --quiet || true" - - -echo "Activating systemctl daemons..." -systemctl daemon-reload -systemctl enable mongod -systemctl enable itender - -echo "Backing up /boot/config.txt to /root/config.txt.bak" -cp /boot/config.txt /root/config.txt.bak -echo "Updating Boot config..." -if ! grep -w "hdmi_group=2" /boot/config.txt; then - echo "hdmi_group=2" >>/boot/config.txt -fi -if ! grep -w "hdmi_mode=87" /boot/config.txt; then - echo "hdmi_mode=87" >>/boot/config.txt -fi -if ! grep -w "hdmi_cvt 1024 600 60 0 0 0 0" /boot/config.txt; then - echo "hdmi_cvt 1024 600 60 0 0 0 0" >>/boot/config.txt -fi -if ! grep -w "hdmi_drive=1" /boot/config.txt; then - echo "hdmi_drive=1" >>/boot/config.txt -fi -if ! grep -w "disable_splash=1" /boot/config.txt; then - echo "disable_splash=1" >>/boot/config.txt -fi -if ! grep -w "vc4-fkms-v3d" /boot/config.txt; then - sed -i 's/dtoverlay=vc4-kms-v3d/dtoverlay=vc4-fkms-v3d,disable-bt/' /boot/config.txt -fi -if ! grep -w "boot_delay=0" /boot/config.txt; then - echo "boot_delay=0" >>/boot/config.txt -fi -if ! grep -w "over_voltage=6" /boot/config.txt; then - echo "over_voltage=6" >>/boot/config.txt -fi -if ! grep -w "arm_freq=1300" /boot/config.txt; then - echo "arm_freq=1300" >>/boot/config.txt -fi -if ! grep -w "gpu_freq=700" /boot/config.txt; then - echo "gpu_freq=700" >>/boot/config.txt -fi - - -echo "Setting no-logo..." -systemctl disable getty@tty1.service - -if ! grep -w "logo.nologo" /boot/cmdline.txt; then - echo "Backing up /boot/cmdline.txt to /root/cmdline.txt.bak" - cp /boot/cmdline.txt /root/cmdline.txt.bak - sed -i '1 s_$_ loglevel=3 logo.nologo disable\_splash=1 splash quiet plymouth.ignore-serial-consoles logo.nologo vt.global\_cursor_default=0_' /boot/cmdline.txt - #cp /tmp/cmdline.txt /boot/cmdline.txt - sed -i "1 s|$| vt.global_cursor_default=0|" /boot/cmdline.txt - sed -i '1 i\avoid_warnings=1' /boot/config.txt - sed -i 's/console=tty0/console=tty3/' /boot/cmdline.txt -fi - -echo "iTender© 2022-2023 -Programmed by Tobias Hopp" >/etc/motd - -echo "[Service] - ExecStart=/usr/sbin/dhcpcd -q" >/etc/systemd/system/dhcpcd.service.d/wait.conf - -chown itender:itender -R /home/itender/ -adduser itender gpio -adduser itender sudo - -echo "Installation finished!" - -reboot now diff --git a/doc/start.sh b/doc/start.sh deleted file mode 100644 index a414ed4..0000000 --- a/doc/start.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -exit -cd /home/itender/ || exit -sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' ~/.config/chromium/'Local State' -sed -i 's/"exited_cleanly":false/"exited_cleanly":true/; s/"exit_type":"[^"]\+"/"exit_type":"Normal"/' ~/.config/chromium/Default/Preferences - -#address="" -#if ping -c1 -W1 192.168.1.186; then -# address="192.168.1.186" -#fi -#if ping -c1 -W1 192.168.208.15; then -# address="192.168.208.15" -#fi -#if ping -c1 -W1 10.10.0.5; then -# address="10.10.0.5" -#fi -address="localhost" - -echo "Waiting 5 seconds to start chromium..." -sleep 5 -/usr/bin/chromium-browser --disable-infobars --kiosk --incognito --disable-pinch --overscroll-history-navigation=0 "http://${address}:3000/" -#/usr/bin/startx /usr/bin/chromium-browser --kiosk --incognito --disable-pinch --overscroll-history-navigation=0 http://192.168.1.186:3000/ \ No newline at end of file diff --git a/doc/v1Containers.png b/doc/v1Containers.png deleted file mode 100644 index e5b01af..0000000 Binary files a/doc/v1Containers.png and /dev/null differ diff --git a/doc/v1Fill.png b/doc/v1Fill.png deleted file mode 100644 index a020c88..0000000 Binary files a/doc/v1Fill.png and /dev/null differ diff --git a/doc/v1Main.png b/doc/v1Main.png deleted file mode 100644 index cc6ac5e..0000000 Binary files a/doc/v1Main.png and /dev/null differ diff --git a/doc/v1Menu.png b/doc/v1Menu.png deleted file mode 100644 index 67682a0..0000000 Binary files a/doc/v1Menu.png and /dev/null differ diff --git a/doc/v1Setup.png b/doc/v1Setup.png deleted file mode 100644 index f77b6e0..0000000 Binary files a/doc/v1Setup.png and /dev/null differ diff --git a/doc/v1Stats.png b/doc/v1Stats.png deleted file mode 100644 index be90735..0000000 Binary files a/doc/v1Stats.png and /dev/null differ diff --git a/package.json b/package.json index be558a9..d014950 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "itender", - "version": "1.0.1", + "version": "1.0.2", "private": true, "author": "Tobias Hopp ", "license": "UNLICENSED", @@ -46,6 +46,8 @@ "nodemon": "^2.0.20", "ts-loader": "^9.4.1", "ts-node": "^10.9.1", + "typedoc": "^0.23.24", + "typedoc-plugin-missing-exports": "^1.0.0", "typescript": "^4.8.4", "webpack": "^5.74.0", "webpack-cli": "^4.10.0" diff --git a/src/ArduinoProxyPayload.ts b/src/ArduinoProxyPayload.ts index c0da47b..206e58b 100644 --- a/src/ArduinoProxyPayload.ts +++ b/src/ArduinoProxyPayload.ts @@ -12,7 +12,7 @@ export class ArduinoProxyPayload { private _id: string =""; - constructor(type: ArduinoProxyPayloadType, data: any) { + constructor(type: ArduinoProxyPayloadType, data: { pin?: number, value?: number|"HIGH"|"LOW", pin_data?: number, pin_clock?: number, mode?: "DIGITAL"|"ANALOG" } ) { this._type = type; this._data = data; } @@ -21,7 +21,7 @@ export class ArduinoProxyPayload { return this._type; } - get data(): any { + get data(): {value?: number} { return this._data; } diff --git a/src/ArduinoProxyPayloadType.ts b/src/ArduinoProxyPayloadType.ts index 019bde8..78f8bd7 100644 --- a/src/ArduinoProxyPayloadType.ts +++ b/src/ArduinoProxyPayloadType.ts @@ -1,7 +1,7 @@ export enum ArduinoProxyPayloadType { - ACK="ACK", - SET_PIN="SET_PIN", - GET_VAL="GET_VAL", - GET_SENSOR="GET_SENSOR", - RESTART="RESTART", + ACK = 0, + SET_PIN = 1, + GET_VAL = 2, + GET_SENSOR = 3, + RESTART = 4, } \ No newline at end of file diff --git a/src/ContainerHelper.ts b/src/ContainerHelper.ts new file mode 100644 index 0000000..8c50f3d --- /dev/null +++ b/src/ContainerHelper.ts @@ -0,0 +1,65 @@ +import Container from "./database/Container"; +import {SensorType} from "./SensorType"; +import {SensorHelper} from "./SensorHelper"; +import {WebSocketHandler} from "./WebSocketHandler"; +import {WebSocketPayload} from "./WebSocketPayload"; +import {WebSocketEvent} from "./WebSocketEvent"; +import debug from "debug"; +import {iTender} from "./iTender"; + +const log = debug("itender:container"); + +export class ContainerHelper { + + /** + * Measure all containers based on their sensor values + */ + static measureContainers(): Promise { + log("Measuring containers..."); + + return new Promise(async resolve => { + for (let c of (await Container.find({}))) { + if (c.sensorType != SensorType.NONE) { + + let weight; + try { + weight = await SensorHelper.measureRaw(c); + } catch (e) { + await WebSocketHandler.send(new WebSocketPayload(WebSocketEvent.ERROR, "Ein Sensor hat beim Austarieren einen ungültigen Wert zurückgegeben.
Dies weist auf eine Fehlkonfiguration oder kaputten Sensor hin.
Aus Sicherheitsgründen wurde der Sensor für diesen Behälter deaktiviert.")); + continue; + } + + + // V2: New calculation method + /* + (WEIGHT_VAL - NO_WEIGHT_VAL) / Sensitivitätsfaktor = Gewicht in Gramm + (WEIGHT_VAL - NO_WEIGHT_VAL) / (100g_val /100) ist die Formel zur Berechnung des Gewichts in Gramm nach der Kalibrierung mit einem 100 Gramm Gewicht. + 100g_val /100 gibt den Sensitivitätsfaktor an, der angibt, wie viel sich der Sensorwert ändert, wenn sich das Gewicht um ein Gramm ändert. + Durch die Division von 100g_val durch 100 wird der Sensitivitätsfaktor berechnet, und durch die Division von (WEIGHT_VAL - NO_WEIGHT_VAL) durch den Sensitivitätsfaktor wird das Gewicht in Gramm berechnet. + + Beispiel: + (WEIGHT_VAL - NO_WEIGHT_VAL) / (100g_val /100) = Gewicht in Gramm + (2400 - 2000) / (2450 /100) = 80 Gramm + */ + let newFilled = weight - c.sensorDelta / iTender.sensitivityFactor; + + if (newFilled <= 3 && c.filled != -1) { + c.filled = -1; + // Container is empty! + } else { + // Container > 2 + c.filled = newFilled; + } + + await c.save(); + } + + } + log("Containers measured!"); + resolve(); + + let payload = new WebSocketPayload(WebSocketEvent.CONTAINERS, (await Container.find())); + await WebSocketHandler.send(payload); + }); + } +} \ No newline at end of file diff --git a/src/HX711.ts b/src/HX711.ts index 2e8052b..926653b 100644 --- a/src/HX711.ts +++ b/src/HX711.ts @@ -3,7 +3,7 @@ export class HX711 { private dataPin: number; - constructor(clockPin: number, dataPin: number) { + constructor(dataPin: number, clockPin: number) { this.clockPin = clockPin; this.dataPin = dataPin; } diff --git a/src/Mixer.ts b/src/Mixer.ts new file mode 100644 index 0000000..fbe178a --- /dev/null +++ b/src/Mixer.ts @@ -0,0 +1,162 @@ +import {IJob} from "./database/IJob"; +import {iTenderStatus} from "./iTenderStatus"; +import {MyGPIO} from "./MyGPIO"; +import GPIO from "rpi-gpio"; +import {SensorType} from "./SensorType"; +import {clearInterval} from "timers"; +import {IContainer} from "./database/IContainer"; +import {iTender} from "./iTender"; +import debug from "debug"; + +const isPI = require("detect-rpi"); + +const log = debug("itender:mix"); + +export class Mixer { + static get currentJob(): IJob { + return this._currentJob; + } + + /** + * Timers for the job, for the pumps etc. + * @private + */ + private static _jobTimers: NodeJS.Timeout[] = []; + + /** + * The current itender job + * @private + */ + private static _currentJob: IJob; + + /** + * Checks if the job has finished every 500ms + * @private + */ + private static _jobEndCheckInterval: NodeJS.Timer; + + /** + * Start the internal fill method, a sub-method of the onReceiveFill method + * This method only gets executed if REALLY all is okay, it is the internal function + * @param job + */ + + static async startFill(job: IJob) { + job.startedAt = new Date(); + await job.populate([{path: "amounts.ingredient"}, {path: "amounts.container"}, {path: "drink"}]); + log("New fill job " + job.drink.name + " will take " + job.estimatedTime + "s"); + + this._currentJob = job; + iTender.setStatus(iTenderStatus.FILLING); + + + for (let x of job.amounts) { + + // Start pump here + try { + await MyGPIO.setup(x.container.pumpPin, GPIO.DIR_OUT) + + await MyGPIO.write(x.container.pumpPin, true); + } catch (e) { + if (isPI()) { + log("[ERROR] GPIO I/O Error " + e); + // Todo error handling to user + await this.cancelFill(); + return; + } else { + log("[WARNING] GPIO I/O Error, but it's normal cause you are not on raspberry"); + } + } + + + let waitTime = (iTender.secondsPer100ml as number) / 100 * x.amount * 1000; + log(`Starting output of pump ${x.container.pumpPin}`); + //mixLog(x.ingredient + " takes " + (waitTime / 1000) + "s for " + x.amount + "ml"); + let timer = setTimeout(async () => { + // Remove from list of timers + let arr: NodeJS.Timer[] = []; + for (let i = 0; i < this._jobTimers.length; i++) { + if (this._jobTimers[i] != timer) + arr.push(this._jobTimers[i]); + } + + log(`Stopping output of pump ${x.container.pumpPin}`); + // Stop pump here + try { + await MyGPIO.write(x.container.pumpPin, false); + } catch (e) { + if (isPI()) { + log("[ERROR] GPIO I/O Error " + e); + await this.cancelFill(); + return; + } else { + log("[WARNING] GPIO I/O Error, but it's normal cause you are not on raspberry"); + } + } + + if (x.container.sensorType == SensorType.NONE) { + // V2: Manual measuring + x.container.filled = x.container.filled - x.amount; + await x.container.save(); + } + + this._jobTimers = arr; + + }, waitTime); + this._jobTimers.push(timer); + } + + this._jobEndCheckInterval = setInterval(async () => { + + if (this._jobTimers.length != 0) + return; + + clearInterval(this._jobEndCheckInterval); + job.endAt = new Date(); + job.successful = true; + + await job.save(); + log("Job successful"); + setTimeout(() => iTender.setStatus(iTenderStatus.READY), 3000) + + }, 500); + } + + + /** + * Cancel the fill instantly + */ + static async cancelFill() { + if (!this._currentJob || iTender.status != iTenderStatus.FILLING) + return; + + clearInterval(this._jobEndCheckInterval); + this._currentJob.successful = false; + this._currentJob.endAt = new Date(); + await this._currentJob.save(); + + for (let timer of this._jobTimers) { + // Clears all the ongoing stop timers + clearTimeout(timer); + } + + for (let jobIngredient of this._currentJob.amounts) { + // stop pump pin + try { + await MyGPIO.write(jobIngredient.container.pumpPin, false); + } catch (e) { + + } + + // ToDo + let container: IContainer = jobIngredient.container; + let deltaStartStop = (this._currentJob.endAt.getTime() - this._currentJob.startedAt.getTime()) / 1000; + + // füllmenge - ( ( (stopp-start) / 1000 ) * ( sekunden100ml / 100 ) ) + container.filled = container.filled - (deltaStartStop * (iTender.secondsPer100ml / 100)) // V2: Near the current fill value based on time values from delta start stop + container.save().then(); + } + + iTender.setStatus(iTenderStatus.READY); + } +} \ No newline at end of file diff --git a/src/SensorHelper.ts b/src/SensorHelper.ts index f750e91..916f193 100644 --- a/src/SensorHelper.ts +++ b/src/SensorHelper.ts @@ -2,44 +2,97 @@ import {IContainer} from "./database/IContainer"; import {SensorType} from "./SensorType"; import {HX711} from "./HX711"; import debug from "debug"; +import {ArduinoProxyPayload} from "./ArduinoProxyPayload"; +import {ArduinoProxyPayloadType} from "./ArduinoProxyPayloadType"; +import {ArduinoProxy} from "./ArduinoProxy"; +import Container from "./database/Container"; const log = debug("itender:sensor"); export class SensorHelper { /** - * Returns the current container weight + * Returns the current raw container weight * @param container */ - static measure(container: IContainer): number | null { - if (container.sensorType == SensorType.LOADCELL) { - try { - // V2: Measure weight - let sensor = new HX711(container.sensorPin1, container.sensorPin2); + static measureRaw(container: IContainer): Promise { + return new Promise(async (resolve, reject) => { + if (container.sensorType == SensorType.LOADCELL) { + try { + if (container.sensorProxy) { + let payload = new ArduinoProxyPayload(ArduinoProxyPayloadType.GET_SENSOR, { + pin_data: container.sensorPin1, + pin_clock: container.sensorPin2 + }); + let val = await ArduinoProxy.sendRequest(payload); + if (!val.data.value) + return reject(""); - container.rawData = sensor.measure(); - } catch (e) { - log("Sensor (Weight cell) of container " + container._id + " is broken or has malfunction - Removing it!"); - container.sensorType = SensorType.NONE; - container.save(); - return null; + container.rawData = val.data.value; + } else { + let sensor = new HX711(container.sensorPin1, container.sensorPin2); + container.rawData = sensor.measure(); + } + } catch (e) { + log("Sensor (Weight cell) of container " + container._id + " is broken or has malfunction - Removing it!"); + container.sensorType = SensorType.NONE; + await container.save(); + return reject(); + } + } else if (container.sensorType == SensorType.ULTRASOUND) { + try { + // V2: Measure weight + let sensor = new HX711(container.sensorPin1, container.sensorPin2); + + container.rawData = sensor.measure(); + + } catch (e) { + log("Sensor (Ultrasound) of container " + container._id + " is broken or has malfunction - Removing it!"); + container.sensorType = SensorType.NONE; + await container.save(); + return reject(); + } } - } else if (container.sensorType == SensorType.ULTRASOUND) { - try { - // V2: Measure weight - let sensor = new HX711(container.sensorPin1, container.sensorPin2); - container.rawData = sensor.measure(); - } catch (e) { - log("Sensor (Ultrasound) of container " + container._id + " is broken or has malfunction - Removing it!"); - container.sensorType = SensorType.NONE; - container.save(); - return null; - } - } - - // todo Überprüfen ob hier Umrechnungen nötig sind. Soll in Gramm zurück gegeben werden - return container.rawData; + resolve(container.rawData); + }); } -} \ No newline at end of file + + /** + * All raw values from the measurements get cleared + */ + public static clearAllRawMeasurements() { + return new Promise(async (resolve, reject) => { + for (let c of (await Container.find({}))) { + if (c.sensorType != SensorType.NONE) { + c.rawData = -1; + await c.save(); + } + } + resolve(); + }) + } + + /** + * All containers will be measured + */ + public static measureAllRaw() { + return new Promise(async (resolve, reject) => { + for (let c of (await Container.find({}))) { + if (c.sensorType != SensorType.NONE) { + let weight: number | null = c.rawData; + try { + weight = await SensorHelper.measureRaw(c); + } catch (e) { + return reject("Fehler Sensor (" + c.sensorPin1 + ", " + c.sensorPin2 + ") - Container " + c.slot + 1); + } + } + } + resolve(); + }) + } +} + + + diff --git a/src/Utils.ts b/src/Utils.ts index 0cad525..57aa222 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -7,7 +7,7 @@ import {Settings} from "./Settings"; export class Utils { public static checkInternet(): Promise { return new Promise(resolve => { - dns.resolve('gaminggeneration.de', (err) => { + dns.resolve('itender.iif.li', (err) => { if (err) resolve(false); else diff --git a/src/database/IContainer.ts b/src/database/IContainer.ts index 854f799..dc54275 100644 --- a/src/database/IContainer.ts +++ b/src/database/IContainer.ts @@ -10,7 +10,14 @@ export interface IContainer extends mongoose.Document { sensorTare: number; // Sensor Type sensorType: SensorType; + + /** + * HX711 DATA-Pin + */ sensorPin1: number; + /** + * HX711 CLOCK-Pin + */ sensorPin2: number; sensorProxy: boolean rawData: number; diff --git a/src/iTender.ts b/src/iTender.ts index 374e5ef..ca62134 100644 --- a/src/iTender.ts +++ b/src/iTender.ts @@ -12,43 +12,57 @@ import {WebSocketEvent} from "./WebSocketEvent"; import Job from "./database/Job"; import {IIngredient} from "./database/IIngredient"; import Ingredient from "./database/Ingredient"; -import {clearInterval} from "timers"; import {RejectReason} from "./RejectReason"; import axios from "axios"; -import GPIO from "rpi-gpio"; -import {MyGPIO} from "./MyGPIO"; -import {SensorHelper} from "./SensorHelper"; -import {SensorType} from "./SensorType"; +import {Mixer} from "./Mixer"; + -const isPI = require("detect-rpi"); const log = debug("itender:station"); -const mixLog = debug("itender:mix"); +const mixLog = debug("itender:mixer"); + /** * The main class of the itender, here a located all main features of the system, like starting pumps, firing events and stuff */ export class iTender { - private static secondsPer100ml: number = 35.3335; + + /** + * How many seconds it takes to fill 100ml + * @private + */ + static secondsPer100ml: number = 35.3335; + + /** + * Sensitivity-Factor of the hx711 scales + * Calculated by (Value /100) Value needs to be measured by hx711 when a known weight is on the sensor, + * in this example its 100g, so divide it by 100 + */ + static sensitivityFactor: number = 1.0; + + /** + * Retrieve all drinks in cache + */ static get drinks(): IDrink[] { return this._drinks; } - /** - * The current job of the itender - */ - static get currentJob(): IJob | null { - return this._currentJob; - } + /** + * Current internal status of itender + * @private + */ private static _status: iTenderStatus = iTenderStatus.STARTING; - private static _currentJob: IJob | null = null; - private static _jobCheckInterval: NodeJS.Timer; + + + /** + * Current internal connection-status boolean + * @private + */ private static _internetConnection: boolean = false; - private static _jobTimers: NodeJS.Timeout[] = []; /** * Returns true if internet connection is active @@ -57,8 +71,16 @@ export class iTender { return this._internetConnection; } + /** + * Drinks in cache + * @private + */ private static _drinks: IDrink[]; + /** + * Sets the current itender status and sends it to the client + * @param status + */ static setStatus(status: iTenderStatus) { this._status = status; if (WebSocketHandler.ws && WebSocketHandler.ws.readyState == 1) @@ -66,6 +88,9 @@ export class iTender { log("Status is now " + status); } + /** + * Returns the internal status of itender app + */ static get status(): iTenderStatus { return this._status; } @@ -73,6 +98,8 @@ export class iTender { /** * This method is fired if the user likes to mix a drink + * It starts to calculate the ingredients and amounts of each ingredient + * also calculates the amount of time, the drink will need to be done * @param data */ static onReceiveFill(data: { drink: IDrink, amounts?: { ingredient: String, amount: number }[], amount?: number }): Promise { @@ -142,176 +169,13 @@ export class iTender { await job.save() resolve(job); - await this.startFill(job); + await Mixer.startFill(job); }); } - /** - * Start the internal fill method - * @param job - */ - static async startFill(job: IJob) { - job.startedAt = new Date(); - await job.populate([{path: "amounts.ingredient"}, {path: "amounts.container"}, {path: "drink"}]); - mixLog("New fill job " + job.drink.name + " will take " + job.estimatedTime + "s"); - - this._currentJob = job; - iTender.setStatus(iTenderStatus.FILLING); - - - for (let x of job.amounts) { - - // Start pump here - try { - await MyGPIO.setup(x.container.pumpPin, GPIO.DIR_OUT) - - await MyGPIO.write(x.container.pumpPin, true); - } catch (e) { - if (isPI()) { - log("[ERROR] GPIO I/O Error " + e); - // Todo error handling to user - await iTender.cancelFill(); - return; - } else { - log("[WARNING] GPIO I/O Error, but it's normal cause you are not on raspberry"); - } - } - - - let waitTime = (iTender.secondsPer100ml as number) / 100 * x.amount * 1000; - mixLog(`Starting output of pump ${x.container.pumpPin}`); - //mixLog(x.ingredient + " takes " + (waitTime / 1000) + "s for " + x.amount + "ml"); - let timer = setTimeout(async () => { - // Remove from list of timers - let arr: NodeJS.Timer[] = []; - for (let i = 0; i < this._jobTimers.length; i++) { - if (this._jobTimers[i] != timer) - arr.push(this._jobTimers[i]); - } - - mixLog(`Stopping output of pump ${x.container.pumpPin}`); - // Stop pump here - try { - await MyGPIO.write(x.container.pumpPin, false); - } catch (e) { - if (isPI()) { - log("[ERROR] GPIO I/O Error " + e); - await iTender.cancelFill(); - return; - } else { - log("[WARNING] GPIO I/O Error, but it's normal cause you are not on raspberry"); - } - } - - if (x.container.sensorType == SensorType.NONE) { - // V2: Manual measuring - x.container.filled = x.container.filled - x.amount; - await x.container.save(); - } - - this._jobTimers = arr; - - }, waitTime); - this._jobTimers.push(timer); - } - - iTender._jobCheckInterval = setInterval(async () => { - - if (this._jobTimers.length != 0) - return; - - clearInterval(iTender._jobCheckInterval); - job.endAt = new Date(); - job.successful = true; - - await job.save(); - mixLog("Job successful"); - setTimeout(() => iTender.setStatus(iTenderStatus.READY), 3000) - - }, 500); - } - - - /** - * Cancel the fill - */ - static async cancelFill() { - if (!this._currentJob || this.status != iTenderStatus.FILLING) - return; - - clearInterval(this._jobCheckInterval); - this._currentJob.successful = false; - this._currentJob.endAt = new Date(); - await this._currentJob.save(); - - for (let timer of this._jobTimers) { - // Clears all the ongoing stop timers - clearTimeout(timer); - } - - for (let jobIngredient of this._currentJob.amounts) { - // stop pump pin - try { - await MyGPIO.write(jobIngredient.container.pumpPin, false); - } catch (e) { - - } - - // ToDo - let container: IContainer = jobIngredient.container; - let deltaStartStop = (this._currentJob.endAt.getTime() - this._currentJob.startedAt.getTime()) / 1000; - - // füllmenge - ( ( (stopp-start) / 1000 ) * ( sekunden100ml / 100 ) ) - container.filled = container.filled - (deltaStartStop * (iTender.secondsPer100ml / 100)) // V2: Near the current fill value based on time values from delta start stop - container.save().then(); - } - - iTender.setStatus(iTenderStatus.READY); - } - - - /** - * Measure all containers based on their sensor values - */ - static measureContainers(): Promise { - log("Measuring containers..."); - - return new Promise(async resolve => { - for (let c of (await Container.find({}))) { - if (c.sensorType != SensorType.NONE) { - let weight = SensorHelper.measure(c); - if (!weight) { - await WebSocketHandler.send(new WebSocketPayload(WebSocketEvent.ERROR, "Ein Sensor hat beim Austarieren einen ungültigen Wert zurückgegeben.
Dies weist auf eine Fehlkonfiguration oder kaputten Sensor hin.
Aus Sicherheitsgründen wurde der Sensor für diesen Behälter deaktiviert.")); - continue; - } - - // V2: New calculation method - let newFilled = weight - c.sensorDelta; - - if (newFilled <= 3 && c.filled != -1) { - c.filled = -1; - // Container is empty! - } else { - // Container > 2 - c.filled = newFilled; - } - - await c.save(); - } - - } - log("Containers measured!"); - resolve(); - - let payload = new WebSocketPayload(WebSocketEvent.CONTAINERS, (await Container.find())); - await WebSocketHandler.send(payload); - }); - } - - /** * Refresh the drinks to the local variable * Check which drinks can be done, based on the current container ingredients @@ -343,28 +207,36 @@ export class iTender { } + /** + * Automatic checkup (all 30 seconds) + * When no current job is ongoing, skip + * if current job is active, but the start time was more than 2mins ago, the job gets canceled + */ public static async autoCheckup() { setInterval(async () => { log("Auto Checkup"); - if (!this._currentJob) + if (!Mixer.currentJob) return; // Check if startedTime plus 2 mins smaller than now - if (this._currentJob.startedAt.getTime() + 1000 * 60 * 2 <= Date.now()) { + if (Mixer.currentJob.startedAt.getTime() + 1000 * 60 * 2 <= Date.now()) { // Job can be declared as stuck! - this._currentJob.successful = false; - this._currentJob.endAt = new Date(); - await this._currentJob.save(); - this._currentJob = null; - this.setStatus(iTenderStatus.READY); + await Mixer.cancelFill(); } - }, 30000); + }, 1000 * 30); } + + /** + * Checks the internet connection + */ public static async checkNetwork() { this._internetConnection = await Utils.checkInternet(); } + /** + * Refrehs drinks from the cloud (https://itender.iif.li) + */ static refreshFromServer(): Promise { return new Promise(async (resolve, reject) => { iTender.setStatus(iTenderStatus.DOWNLOADING) @@ -431,7 +303,6 @@ export class iTender { Utils.deleteImage(local._id); await Drink.deleteOne({"_id": local._id}); } - } @@ -470,39 +341,5 @@ export class iTender { }); } - public static clearAllRawMeasurements() - { - return new Promise(async (resolve, reject) => { - for (let c of (await Container.find({}))) { - if (c.sensorType != SensorType.NONE) { - c.rawData = -1; - await c.save(); - } - } - resolve(); - }) - } - public static measureAllRaw() { - return new Promise(async (resolve, reject) => { - for (let c of (await Container.find({}))) { - if (c.sensorType != SensorType.NONE) { - let weight : number | null = c.rawData; - if( !c.sensorProxy ) - { - // Check values - weight = SensorHelper.measure(c); - } - - if (weight == null || weight > 1000 || weight < 0 ) { //fixme werte - // Problem erkannt! - return reject("Fehler Sensor (" + c.sensorPin1 + ", " + c.sensorPin2 + ") - Container " + c.slot + 1); - } - c.rawData = weight; - await c.save(); - } - } - resolve(); - }) - } } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 4082760..ea9d343 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,6 +8,8 @@ import {Utils} from "./Utils"; import {Settings} from "./Settings"; import Drink from "./database/Drink"; import {MyGPIO} from "./MyGPIO"; +import {ContainerHelper} from "./ContainerHelper"; +import {Mixer} from "./Mixer"; const log = debug("itender:server"); @@ -51,6 +53,9 @@ const wsApp = new WebsocketApp(); } })(); +/** + * tst + */ function init(): Promise { return new Promise(async resolve => { @@ -69,7 +74,7 @@ function init(): Promise { // Containers //await iTender.refreshContainers(); - await iTender.measureContainers(); + await ContainerHelper.measureContainers(); log("2"); // Drinks await iTender.refreshDrinks(); @@ -90,11 +95,11 @@ function refresh(): Promise { // Below are refreshments of containers / drinks // If there is a current job, DO NOT REFRESH! - if (iTender.currentJob) + if (Mixer.currentJob) return; //await iTender.refreshContainers(); Not needed because there is no change in containers? - await iTender.measureContainers(); + await ContainerHelper.measureContainers(); //await iTender.refreshDrinks(); Not needed because there is no change in drinks? }); } \ No newline at end of file diff --git a/src/routes/ws/websocketRoute.ts b/src/routes/ws/websocketRoute.ts index f6b4159..a375684 100644 --- a/src/routes/ws/websocketRoute.ts +++ b/src/routes/ws/websocketRoute.ts @@ -12,6 +12,7 @@ import {RequestType} from "../../RequestType"; import {IJob} from "../../database/IJob"; import {SensorHelper} from "../../SensorHelper"; import {IContainer} from "../../database/IContainer"; +import {Mixer} from "../../Mixer"; const express = require('express'); const router = express.Router(); @@ -80,11 +81,11 @@ router.ws('/', async (ws, req, next) => { container.volume = filled; // V2: Volume is now being updated after change of ingredient if (container.sensorType != SensorType.NONE) { - let raw = SensorHelper.measure(container); + let raw = SensorHelper.measureRaw(container); if (!raw) { await WebSocketHandler.send(new WebSocketPayload(WebSocketEvent.ERROR, "Der Sensor hat beim Austarieren einen ungültigen Wert zurückgegeben.
Dies weist auf eine Fehlkonfiguration oder kaputten Sensor hin.
Aus Sicherheitsgründen wurde der Sensor für diesen Behälter deaktiviert.")); } else { - container.sensorDelta = raw - filled; // V2: Kalkuliere differenz zwischen Gewicht und gefülltem Inhalt // Todo Möglicherweise ist der "raw"-Wert nicht Gewicht + container.sensorDelta = await raw - filled; // V2: Kalkuliere differenz zwischen Gewicht und gefülltem Inhalt // Todo Möglicherweise ist der "raw"-Wert nicht Gewicht } } @@ -149,7 +150,7 @@ router.ws('/', async (ws, req, next) => { break; } case RequestType.JOB: { - WebSocketHandler.answerRequest(msg.data["type"] as RequestType, iTender.currentJob); + WebSocketHandler.answerRequest(msg.data["type"] as RequestType, Mixer.currentJob); break; } case RequestType.DOWNLOAD_DRINKS: { @@ -158,7 +159,7 @@ router.ws('/', async (ws, req, next) => { break; } case RequestType.CHECK: { - await iTender.clearAllRawMeasurements(); + await SensorHelper.clearAllRawMeasurements(); let content : {error: boolean, msg: string} = { @@ -174,7 +175,7 @@ router.ws('/', async (ws, req, next) => { } // Check measurements - await iTender.measureAllRaw(); + await SensorHelper.measureAllRaw(); for( let c of await Container.find() ) { if( c.sensorType != SensorType.NONE && c.rawData == -1 ) @@ -202,7 +203,7 @@ router.ws('/', async (ws, req, next) => { async function measureAndSafe() { try { - await iTender.measureAllRaw(); + await SensorHelper.measureAllRaw(); for (let c of await Container.find({})) { if (c.sensorType != SensorType.NONE) { c.sensorTare += c.rawData; diff --git a/tsconfig.json b/tsconfig.json index 821923d..9961822 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "pretty": true, "noImplicitAny": false, "sourceMap": true, "outDir": "dist", @@ -19,10 +20,11 @@ "node_modules/@types" ] }, + "include": [ - "./src/", + "./src/" ], "exclude": [ - "node_modules", + "node_modules" ] } \ No newline at end of file diff --git a/typedoc.json b/typedoc.json new file mode 100644 index 0000000..7cb976c --- /dev/null +++ b/typedoc.json @@ -0,0 +1,14 @@ +{ + "entryPoints": [ + "src/main.ts", + "src/iTender.ts", + "src/web/main.ts", + "src/WebsocketApp.ts", + "src/App.ts", + "src/routes/ws/websocketRoute.ts" + ], + "out": "docs/", + "readme": "README.md", + "name": "iTender Documentation", + "tsconfig": "./tsconfig.json" +} diff --git a/yarn.lock b/yarn.lock index 1a245f0..aa2c111 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1430,6 +1430,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -2123,6 +2130,11 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +jsonc-parser@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" + integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== + jstransformer@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/jstransformer/-/jstransformer-1.0.0.tgz#ed8bf0921e2f3f1ed4d5c1a44f68709ed24722c3" @@ -2165,11 +2177,21 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lunr@^2.3.9: + version "2.3.9" + resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" + integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== + make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +marked@^4.2.5: + version "4.2.12" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.2.12.tgz#d69a64e21d71b06250da995dcd065c11083bebb5" + integrity sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -2227,6 +2249,13 @@ minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^5.1.2: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + mongodb-connection-string-url@^2.5.4: version "2.6.0" resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz#57901bf352372abdde812c81be47b75c6b2ec5cf" @@ -2806,6 +2835,15 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +shiki@^0.12.1: + version "0.12.1" + resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.12.1.tgz#26fce51da12d055f479a091a5307470786f300cd" + integrity sha512-aieaV1m349rZINEBkjxh2QbBvFFQOlgqYTNtCal82hHj4dDZ76oMlQIX+C7ryerBTDiga3e5NfH6smjdJ02BbQ== + dependencies: + jsonc-parser "^3.2.0" + vscode-oniguruma "^1.7.0" + vscode-textmate "^8.0.0" + sift@16.0.1: version "16.0.1" resolved "https://registry.yarnpkg.com/sift/-/sift-16.0.1.tgz#e9c2ccc72191585008cf3e36fc447b2d2633a053" @@ -2996,6 +3034,21 @@ type-is@~1.6.16: media-typer "0.3.0" mime-types "~2.1.24" +typedoc-plugin-missing-exports@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-1.0.0.tgz#7212a2cfaba7b48264df4b4110f3a5684b5c49a1" + integrity sha512-7s6znXnuAj1eD9KYPyzVzR1lBF5nwAY8IKccP5sdoO9crG4lpd16RoFpLsh2PccJM+I2NASpr0+/NMka6ThwVA== + +typedoc@^0.23.24: + version "0.23.24" + resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.23.24.tgz#01cf32c09f2c19362e72a9ce1552d6e5b48c4fef" + integrity sha512-bfmy8lNQh+WrPYcJbtjQ6JEEsVl/ce1ZIXyXhyW+a1vFrjO39t6J8sL/d6FfAGrJTc7McCXgk9AanYBSNvLdIA== + dependencies: + lunr "^2.3.9" + marked "^4.2.5" + minimatch "^5.1.2" + shiki "^0.12.1" + typescript@^4.8.4: version "4.9.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78" @@ -3051,6 +3104,16 @@ void-elements@^3.1.0: resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w== +vscode-oniguruma@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz#439bfad8fe71abd7798338d1cd3dc53a8beea94b" + integrity sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA== + +vscode-textmate@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-8.0.0.tgz#2c7a3b1163ef0441097e0b5d6389cd5504b59e5d" + integrity sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg== + watchpack@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"