add and close #12

Took 1 hour 46 minutes
This commit is contained in:
Tobias Hopp 2023-02-02 14:28:09 +01:00
parent a021d25332
commit 937f825e82
13 changed files with 135 additions and 89 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "itender", "name": "itender",
"version": "1.0.2", "version": "2.2.8",
"private": true, "private": true,
"author": "Tobias Hopp <tobi@gaminggeneration.de>", "author": "Tobias Hopp <tobi@gaminggeneration.de>",
"license": "UNLICENSED", "license": "UNLICENSED",

View File

@ -63,12 +63,12 @@
.modalBlendIn { .modalBlendIn {
animation: modalBlendIn 0.5s forwards; animation: modalBlendIn 0.4s forwards;
} }
.modalBlendOut { .modalBlendOut {
animation: modalBlendOut 0.8s forwards; animation: modalBlendOut 0.4s forwards;
} }

View File

@ -30,10 +30,10 @@ export class Settings {
} }
public static saveSettings() { public static saveSettings() {
fs.writeFileSync(path.join(__dirname, "../config.json"), JSON.stringify(this._json)); fs.writeFileSync(path.join(__dirname, "../config.json"), JSON.stringify(this._json, null, 1));
} }
public static get(key: string): any { public static get(key: "setupDone"|"secondsPer100ml"|"arduino_proxy_enabled"|"led_enabled"|"remote_enabled"|"hotspot_enabled"|"led_gpio"|"ambient_color"): any {
return this._json[key]; return this._json[key];
} }

View File

@ -33,7 +33,7 @@ export class iTender {
* How many seconds it takes to fill 100ml * How many seconds it takes to fill 100ml
* @private * @private
*/ */
static secondsPer100ml: number = 35.3335; static secondsPer100ml: number = 19.3335; // 35.3335
/** /**
* Sensitivity-Factor of the hx711 scales * Sensitivity-Factor of the hx711 scales

View File

@ -10,6 +10,7 @@ import Drink from "./database/Drink";
import {MyGPIO} from "./MyGPIO"; import {MyGPIO} from "./MyGPIO";
import {ContainerHelper} from "./ContainerHelper"; import {ContainerHelper} from "./ContainerHelper";
import {Mixer} from "./Mixer"; import {Mixer} from "./Mixer";
import {ArduinoProxy} from "./ArduinoProxy";
const log = debug("itender:server"); const log = debug("itender:server");
@ -20,11 +21,25 @@ const wsApp = new WebsocketApp();
(async () => { (async () => {
try { try {
log("Starting..."); log("Starting...");
Settings.loadSettings();
await Database.connect(); await Database.connect();
if( Settings.get("arduino_proxy_enabled") as boolean )
{
try {
await ArduinoProxy.connect();
} catch( e )
{
Settings.set("arduino_proxy_enabled",false);
Settings.setupDone = false;
log("Force iTender to setup, because proxy not connected!");
}
}
//await test(); //await test();
await app.listen(); await app.listen();
await wsApp.listen(); await wsApp.listen();
Settings.loadSettings();
iTender.setStatus(iTenderStatus.STARTING); iTender.setStatus(iTenderStatus.STARTING);
await Utils.sleep(2000); await Utils.sleep(2000);

View File

@ -77,6 +77,17 @@ router.ws('/', async (ws, req, next) => {
await container.save(); await container.save();
i++; i++;
} }
let containers : IContainer[] = await Container.find();
for( let c of containers )
{
let find = data.find( (e) => {
return c._id == e.id;
} );
if( !find )
await Container.deleteOne({_id: c._id });
}
break; break;
} }
@ -211,7 +222,7 @@ router.ws('/', async (ws, req, next) => {
} catch (e) { } catch (e) {
log("Checkup failed"); log("Checkup failed");
content.success = false; content.success = false;
content.msg = "Bei der Kommunikation mit dem Arduino Proxy ist ein Fehler aufgetreten.<br>Technische Details: " + e; content.msg = "Bei der Kommunikation mit dem Arduino Proxy ist ein Fehler aufgetreten.<br><br><em>Technische Details: " + e + "</em>";
return WebSocketHandler.answerRequest(msg.data["type"] as RequestType, content); return WebSocketHandler.answerRequest(msg.data["type"] as RequestType, content);
} }
} }
@ -288,13 +299,20 @@ router.ws('/', async (ws, req, next) => {
} }
case RequestType.UPDATE: { case RequestType.UPDATE: {
/* if( !iTender.internetConnection )
- git pull return WebSocketHandler.answerRequest(msg.data["type"] as RequestType, false);
- yarn install WebSocketHandler.answerRequest(msg.data["type"] as RequestType, true);
- yarn run compile
- (arduino update?)
- reboot try {
*/ let result = await exec("/home/itender/itender/update.sh");
if( result.stderr )
await WebSocketHandler.send(new WebSocketPayload(WebSocketEvent.ERROR, "Der iTender konnte das Update nicht installieren.<br>Möglicherweise ist die Internetverbindung nicht ausreichend oder das Update enthält Fehler.<br>"));
} catch( e )
{
await WebSocketHandler.send(new WebSocketPayload(WebSocketEvent.ERROR, "Der iTender konnte das Update nicht installieren.<br>Möglicherweise ist die Internetverbindung nicht ausreichend oder das Update enthält Fehler.<br>"));
}
break; break;
} }
@ -321,7 +339,9 @@ router.ws('/', async (ws, req, next) => {
"ip": ipAddr, "ip": ipAddr,
"network": wifi.substring(wifi.indexOf('"')+1,wifi.length-2), "network": wifi.substring(wifi.indexOf('"')+1,wifi.length-2),
"uptime": (await exec("uptime -p")).stdout.substring(3), "uptime": (await exec("uptime -p")).stdout.substring(3),
"version": packageJson.version "version": packageJson.version,
"author": "Tobias Hopp",
"contact": "tobi@gaminggeneration.de"
} }
return WebSocketHandler.answerRequest(msg.data["type"] as RequestType, data); return WebSocketHandler.answerRequest(msg.data["type"] as RequestType, data);

View File

@ -82,7 +82,7 @@ export class Containers {
let selectIngredient = document.createElement("select"); let selectIngredient = document.createElement("select");
selectIngredient.classList.add("hidden"); selectIngredient.classList.add("hidden");
selectIngredient.classList.add("input"); selectIngredient.classList.add("input");
selectIngredient.style.width = "50%" selectIngredient.style.width = "35%"
// When ingredient is changed // When ingredient is changed
selectIngredient.onchange = () => { selectIngredient.onchange = () => {
@ -189,6 +189,7 @@ export class Containers {
selectContainer.dispatchEvent(event); selectContainer.dispatchEvent(event);
selectIngredient.dispatchEvent(event); selectIngredient.dispatchEvent(event);
}); });
modal.close();
}; };
modal.open(); modal.open();

View File

@ -177,7 +177,7 @@ export class Modal {
modalContent.classList.remove("modalBlendOut"); modalContent.classList.remove("modalBlendOut");
modal.classList.remove("modalBlendOut"); modal.classList.remove("modalBlendOut");
this.modalInClose = false; this.modalInClose = false;
}, 800); }, 402);
this.currentModalId = undefined; this.currentModalId = undefined;
} }

View File

@ -13,6 +13,9 @@ export class Settings {
const reload = document.getElementById("settings_reload") as HTMLButtonElement; const reload = document.getElementById("settings_reload") as HTMLButtonElement;
reload.onclick = () => window.location.reload(); reload.onclick = () => window.location.reload();
const update = document.getElementById("settings_update") as HTMLButtonElement;
update.onclick = () => this.update();
} }
private static onClickRefreshDrinks() { private static onClickRefreshDrinks() {
@ -41,32 +44,47 @@ export class Settings {
th.append(tdTh1, tdTh2); th.append(tdTh1, tdTh2);
let x = [["internet","Internet-Konnektivität"], ["ip","IP-Adresse"], ["network","WiFi-Netzwerk"], ["uptime","Gerät aktiv seit"], ["version", "Version"]]; let x = [["internet", "Internet-Konnektivität"], ["ip", "IP-Adresse"], ["network", "WiFi-Netzwerk"], ["uptime", "Gerät aktiv seit"], ["version", "Version"], ["author", "Entwickler"], ["contact", "Support-Adresse"]];
for( let y of x ) for (let y of x) {
{
let tr = document.createElement("tr"); let tr = document.createElement("tr");
let td1 = document.createElement("td"); let td1 = document.createElement("td");
let td2 = document.createElement("td"); let td2 = document.createElement("td");
td1.innerText = y[1]; td1.innerText = y[1];
td1.style.fontWeight = "bold"; td1.style.fontWeight = "bold";
if( payload.data[y[0]] === true || payload.data[y[0]] === false ) if (payload.data[y[0]] === true || payload.data[y[0]] === false) {
{
td2.innerText = payload.data[y[0]] == true ? "Verbunden" : "Getrennt"; td2.innerText = payload.data[y[0]] == true ? "Verbunden" : "Getrennt";
} } else {
else
{
td2.innerText = payload.data[y[0]]; td2.innerText = payload.data[y[0]];
} }
tr.append(td1,td2); tr.append(td1, td2);
table.append(tr); table.append(tr);
} }
modal.addContent(table); modal.addContent(table);
modal.addBR(); modal.addBR();
modal.addButton(ButtonType.PRIMARY, "Schließen", () => modal.close() ); modal.addButton(ButtonType.PRIMARY, "Schließen", () => modal.close());
modal.open();
});
}
private static update() {
WebWebSocketHandler.request(RequestType.UPDATE, null).then((payload) => {
let modal = new Modal("info", "System-Update");
let txt = document.createElement("p");
if (payload.data as boolean) {
txt.innerHTML = `Der iTender wird nun aktualisiert!<br><br>
Sobald das Update installiert ist, wird das System neu gestartet.<br>Die dadurch hergehende Verbindungswarnung kann ignoriert werden.<br>Der iTender stellt die Verbindung automatisch wieder her.<br><br><span style="color:red;font-weight: bold">Schalten Sie das System nicht aus und entfernen Sie nicht das Netzkabel!</span>`;
modal.addContent(txt);
modal.loader = true;
} else {
txt.innerHTML = `Das System kann nicht aktualisiert werden.<br>iTender hat keine Internet-Konnektivität fest gestellt.<br>Versuchen Sie es zu einem späteren Zeitpunkt erneut.`;
modal.addButton(ButtonType.PRIMARY, "Schließen", () => modal.close());
}
modal.open(); modal.open();
}); });
} }

View File

@ -199,9 +199,9 @@ Dort werden die Behälter definiert, welche in den iTender gestellt werden.<br>D
// Check // Check
let answer = await WebWebSocketHandler.request(RequestType.CHECK, newConf); let answer = await WebWebSocketHandler.request(RequestType.CHECK, newConf);
console.log(answer);
if (!(answer.data["success"] as boolean)) { if (!(answer.data["success"] as boolean)) {
ele.innerHTML = `Die Konfiguration weist Fehler auf!<br>${answer.data["msg"]}`; ele.innerHTML = `Die Überprüfung schlug fehl!<br>${answer.data["msg"]}`;
await errorModal.open(); await errorModal.open();
return; return;
} }
@ -552,8 +552,11 @@ Mindestens ein Sensor konnte nicht kalibriert werden.<br>${data.msg}<br>`;
setTimeout(() => { setTimeout(() => {
c.classList.remove("error"); c.classList.remove("error");
c2.classList.remove("error"); c2.classList.remove("error");
sel.classList.remove("error"); setTimeout( () => {
sel2.classList.remove("error"); sel.classList.remove("error");
sel2.classList.remove("error");
}, 1500 );
}, 2200); }, 2200);
returner = false; returner = false;
} }

View File

@ -31,7 +31,7 @@ document.addEventListener("DOMContentLoaded", async () => {
setInterval(() => { setInterval(() => {
if(!time ) return; if (!time) return;
let currentDate = new Date(); let currentDate = new Date();
time.innerText = "" + (currentDate.getHours() < 10 ? "0" + currentDate.getHours() : currentDate.getHours()) + ":" + (currentDate.getMinutes() < 10 ? "0" + currentDate.getMinutes() : currentDate.getMinutes()); time.innerText = "" + (currentDate.getHours() < 10 ? "0" + currentDate.getHours() : currentDate.getHours()) + ":" + (currentDate.getMinutes() < 10 ? "0" + currentDate.getMinutes() : currentDate.getMinutes());
@ -39,29 +39,28 @@ document.addEventListener("DOMContentLoaded", async () => {
WebWebSocketHandler.registerForEvent(WebSocketEvent.CONTAINERS, (payload) => { WebWebSocketHandler.registerForEvent(WebSocketEvent.CONTAINERS, (payload) => {
console.log("Updating container list...") console.log("Updating container list...")
let container : IContainer; let container: IContainer;
let bottomContainers = document.getElementById("menuContainers") as HTMLDivElement; let bottomContainers = document.getElementById("menuContainers") as HTMLDivElement;
bottomContainers.innerHTML = ""; bottomContainers.innerHTML = "";
for( container of payload.data ) for (container of payload.data) {
{
let containerDiv = document.createElement("div") as HTMLDivElement; let containerDiv = document.createElement("div") as HTMLDivElement;
containerDiv.classList.add("container"); containerDiv.classList.add("container");
let span = document.createElement("span") as HTMLSpanElement; let span = document.createElement("span") as HTMLSpanElement;
let pcnt = Math.round( container.filled * 100 / container.volume ); let pcnt = Math.round(container.filled * 100 / container.volume);
if( !container.content ) if (!container.content)
span.innerText = "-"; span.innerText = "-";
else if( isNaN(pcnt) ) else if (isNaN(pcnt))
span.innerText = "?%"; span.innerText = "?%";
else else
span.innerText = pcnt + "%"; span.innerText = pcnt + "%";
if( pcnt < 5 ) if (pcnt < 5)
containerDiv.style.backgroundColor = "red"; containerDiv.style.backgroundColor = "red";
else if ( pcnt < 15 ) else if (pcnt < 15)
containerDiv.style.backgroundColor = "#ef4f00"; containerDiv.style.backgroundColor = "#EF4F00";
else if ( pcnt < 30 ) else if (pcnt < 30)
containerDiv.style.backgroundColor = "#ff5400"; containerDiv.style.backgroundColor = "#FF5400";
containerDiv.append(span); containerDiv.append(span);
@ -75,18 +74,6 @@ function setupOnClickEvents() {
const menuBtn = document.getElementById("menuBtn") as HTMLButtonElement; const menuBtn = document.getElementById("menuBtn") as HTMLButtonElement;
menuBtn.disabled = true; menuBtn.disabled = true;
let timer = 0;
function mouseDown() {
timer = Date.now();
}
function mouseUp() {
if( ( Date.now() - timer ) / 1000 > 5 )
window.location.reload();
}
menuBtn.onmousedown = mouseDown;
menuBtn.ontouchstart = mouseDown;
menuBtn.onmouseup = mouseUp;
menuBtn.ontouchend = mouseUp;
function doMenu() { function doMenu() {
if (WebHandler.currentPane != Pane.MENU) { if (WebHandler.currentPane != Pane.MENU) {
@ -107,43 +94,43 @@ function setupOnClickEvents() {
menuStatsBtn.onclick = async () => { menuStatsBtn.onclick = async () => {
let statsModal = new Modal("stats", "Statistiken"); let modal = new Modal("stats", "Statistiken");
let txt = document.createElement("p"); let table = document.createElement("table");
txt.innerHTML = `Folgende Statistiken wurden erfasst.`; table.style.marginLeft = "auto";
statsModal.addContent(txt); table.style.marginRight = "auto";
let div = document.createElement("div"); let th = document.createElement("th");
div.style.textAlign = "left"; table.append(th);
statsModal.addContent(div);
let list = document.createElement("ul"); let tdTh1 = document.createElement("td");
div.append(list); tdTh1.innerText = "";
let tdTh2 = document.createElement("td");
tdTh2.innerText = "";
statsModal.addContent(document.createElement("br")); th.append(tdTh1, tdTh2);
statsModal.addButton(ButtonType.PRIMARY, "Schließen", () => statsModal.close());
WebWebSocketHandler.request(RequestType.STATS).then((payload) => { WebWebSocketHandler.request(RequestType.STATS).then((payload) => {
let li = document.createElement("li"); let x = [["drinks_finished", "Ausgegebene Cocktails"], ["drink_most", "Beliebtester Cocktail"], ["count_cocktails", "Anzahl an Cocktails"], ["count_ingredients", "Anzahl an Zutaten"]];
console.log(payload); for (let y of x) {
li.innerText = "Cocktails ausgegeben: " + payload.data["drinks_finished"]; let tr = document.createElement("tr");
list.append(li); let td1 = document.createElement("td");
let td2 = document.createElement("td");
li = document.createElement("li"); td1.innerText = y[1];
li.innerText = "Häufigster Cocktail: " + payload.data["drink_most"]; td1.style.fontWeight = "bold";
list.append(li); td2.innerText = payload.data[y[0]];
tr.append(td1, td2);
li = document.createElement("li"); table.append(tr);
li.innerText = "Anzahl Ingredients: " + payload.data["count_ingredients"]; }
list.append(li); modal.addContent(table);
li = document.createElement("li");
li.innerText = "Anzahl Cocktails: " + payload.data["count_cocktails"];
list.append(li);
modal.addContent(document.createElement("br"));
modal.addButton(ButtonType.PRIMARY, "Schließen", () => modal.close());
modal.open();
}); });
await statsModal.open();
}; };
const menuSettingsBtn = document.getElementById("menu_settings") as HTMLButtonElement; const menuSettingsBtn = document.getElementById("menu_settings") as HTMLButtonElement;
@ -159,8 +146,6 @@ function setupOnClickEvents() {
Settings.addListeners(); Settings.addListeners();
} }
let wsHandler; let wsHandler;

View File

@ -1,5 +1,7 @@
#!/bin/bash #!/bin/bash
cd /home/itender/itender || exit -1
git pull "https://tobiash:!IwedwrimmVeudiweN!@git.gaminggeneration.de/tobiash/itender.git" --quiet git pull "https://tobiash:!IwedwrimmVeudiweN!@git.gaminggeneration.de/tobiash/itender.git" --quiet
yarn yarn
yarn run compile yarn run compile
sudo systemctl restart itender sudo systemctl restart itender
exit 0

View File

@ -11,7 +11,7 @@ block setup
input#ledGPIO.input(type="number" value="40" style="width:15%" disabled="disabled") input#ledGPIO.input(type="number" value="40" style="width:15%" disabled="disabled")
div.inputGroup div.inputGroup
label Ambiente Farbe label Ambiente Farbe
input#ambientColor.input(type="color" value="#05445E" style="width:15%" disabled="disabled") input#ambientColor.input(type="color" value="#05445E" style="width:15%")
div#setupExtraDiv div#setupExtraDiv
h1 Erweiterte Einstellungen h1 Erweiterte Einstellungen
@ -54,11 +54,13 @@ block menu
block settings block settings
// Settings // Settings
button.btn.btn-primary#settings_refreshDrinks Getränke herunterladen button.btn.btn-primary#settings_refreshDrinks Getränke aktualisieren
button.btn.btn-primary#settings_update System aktualisieren button.btn.btn-primary#settings_deleteDrinks(disabled="disabled") Getränke-DB löschen
button.btn.btn-primary#settings_reload Oberfläche neu starten
button.btn.btn-primary#settings_getInfo Systeminformationen button.btn.btn-primary#settings_getInfo Systeminformationen
button.btn.btn-primary#settings_reload Oberfläche neustarten button.btn.btn-primary#settings_update System aktualisieren
button.btn.btn-primary#settings_restart(disabled="disabled") iTender neu starten
button.btn.btn-primary#settings_shutdown(disabled="disabled") iTender herunterfahren
block main block main