diff --git a/src/iTender.ts b/src/iTender.ts index 4ebd5b3..6e8cf1b 100644 --- a/src/iTender.ts +++ b/src/iTender.ts @@ -86,7 +86,6 @@ export class iTender { const job = new Job(); - let amounts: { ingredient: IIngredient, amount: number, container?: IContainer }[] = []; job.completeAmount = 0; if (data.amounts) { @@ -227,6 +226,7 @@ export class iTender { clearInterval(iTender._jobCheckInterval); job.endAt = new Date(); job.successful = true; + await job.save(); mixLog("Job successful"); setTimeout(() => iTender.setStatus(iTenderStatus.READY), 3000) @@ -263,12 +263,13 @@ export class iTender { // ToDo let container: IContainer = jobIngredient.container; let deltaStartStop = (this._currentJob.endAt.getTime() - this._currentJob.startedAt.getTime()) / 1000; - container.filled = container.filled - ( jobIngredient.amount * (deltaStartStop / ((jobIngredient.amount / 100) * iTender.secondsPer100ml)) ); // V2: Near the current fill value based on time values from delta start stop // todo fixme + + // 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); - } @@ -288,7 +289,15 @@ export class iTender { } // V2: New calculation method - c.filled = weight - c.sensorDelta; // V2: Testing + 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(); } @@ -386,10 +395,8 @@ export class iTender { c.save(); } } - } - for (let remote of serverIngredients) { let ingredient = await Ingredient.findById(remote._id); if (!ingredient) @@ -463,13 +470,21 @@ export class iTender { }); } - private static interval; - public static toggleTare(state: boolean) { - clearInterval(iTender.interval); - if (state) - this.interval = setInterval(async () => { - await this.measureContainers(); - }, 500); + public static measureAllRaw() { + return new Promise(async (resolve, reject) => { + for (let c of (await Container.find({}))) { + if (c.sensorType != SensorType.NONE) { + let weight = SensorHelper.measure(c); + if (weight == null) { + // 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/routes/ws/websocketRoute.ts b/src/routes/ws/websocketRoute.ts index a36594c..21b4df2 100644 --- a/src/routes/ws/websocketRoute.ts +++ b/src/routes/ws/websocketRoute.ts @@ -23,7 +23,6 @@ router.ws('/', async (ws, req, next) => { log("Incoming websocket connection..."); if (WebSocketHandler.ws) { - iTender.toggleTare(false); WebSocketHandler.ws.close(1001); } WebSocketHandler.ws = ws; @@ -44,14 +43,6 @@ router.ws('/', async (ws, req, next) => { switch (msg.event) { - case WebSocketEvent.TARE: { - if (msg.data["state"] == true) { - iTender.toggleTare(true); - } else { - iTender.toggleTare(false); - } - break; - } case WebSocketEvent.CONTAINERS: { let data = msg.data as { pumpPin: number; sensorType: SensorType; sensor1: number; sensor2: number; }[]; await Container.deleteMany({}); // V2: Remove this and check every container based on id if changes occurs @@ -73,7 +64,7 @@ router.ws('/', async (ws, req, next) => { } case WebSocketEvent.CONTAINER_UPDATE: { - let container : IContainer | null = await Container.findById(msg.data["container"]); + let container: IContainer | null = await Container.findById(msg.data["container"]); if (!container) break; let ingredient; @@ -83,20 +74,16 @@ router.ws('/', async (ws, req, next) => { ingredient = undefined; } - let filled : number = parseInt(msg.data["filled"]); + let filled: number = parseInt(msg.data["filled"]); container.filled = filled; container.volume = filled; // V2: Volume is now being updated after change of ingredient - if( container.sensorType != SensorType.NONE ) - { + if (container.sensorType != SensorType.NONE) { let raw = SensorHelper.measure(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 - { + 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 } } @@ -170,6 +157,51 @@ router.ws('/', async (ws, req, next) => { WebSocketHandler.answerRequest(msg.data["type"] as RequestType, "ok"); break; } + case RequestType.TARE: { + let type = msg.data["type"]; + // Start TARE + let success = true; + + for (let c of await Container.find({})) { + if (c.sensorType != SensorType.NONE) { + c.sensorTare = 0; + await c.save(); + } + } + + async function measureAndSafe() { + try { + await iTender.measureAllRaw(); + for (let c of await Container.find({})) { + if (c.sensorType != SensorType.NONE) { + c.sensorTare += c.rawData; + } + } + } catch (e) { + // { success: boolean, msg: string } + WebSocketHandler.answerRequest(type, {success: false, msg: e}); + success = false; + } + } + + setTimeout(measureAndSafe, 500); + setTimeout(measureAndSafe, 1000); + setTimeout(measureAndSafe, 2000); + setTimeout(measureAndSafe, 3000); + + setTimeout(async () => { + if (success) { + for (let c of await Container.find({})) { + if (c.sensorType != SensorType.NONE) { + c.sensorTare = c.sensorTare / 4; + await c.save(); + } + } + WebSocketHandler.answerRequest(type, {success: true, msg: "OK"}); + } + }, 4000); + + } } break; diff --git a/src/web/Setup.ts b/src/web/Setup.ts index 1eacaa7..e8ec8c1 100644 --- a/src/web/Setup.ts +++ b/src/web/Setup.ts @@ -44,9 +44,9 @@ export class Setup { LED-Modul
In diesem Modul kann die Ambiente-Farbe sowie der LED-Streifen aktiviert werden.

Erweiterte Einstellungen
-Hier lässt sich konfigurieren, ob die Nutzung der Remote-Bedienung erlaubt ist, oder ein Hotspot aktiviert werden soll, falls keine WiFI-Verbindung vorliegt.

+Hier lässt sich konfigurieren, ob die Nutzung der Remote-Bedienung erlaubt ist, oder ein Hotspot aktiviert werden soll, falls keine WiFI-Verbindung vorliegt.
Außerdem lässt sich hier optional die Nutzung eines Arduino Mega als Proxy aktivieren. Pro Container kann dann der Proxy aktiviert werden, welcher anstatt dem Raspberry Pi die PINs steuert.

Behälter-Modul
-Dort werden die Behälter definiert, welche in den iTender gestellt werden.
Dort müssen GPIO-Pins der Pumpe, etwaige Sensoren-Typen und Pins definiert werden.
Außerdem wird das Volumen eingestellt.

`; +Dort werden die Behälter definiert, welche in den iTender gestellt werden.
Dort müssen GPIO-Pins der Pumpe, etwaige Sensoren-Typen und Pins definiert werden.
Ggf. steht hier auch die Proxy-Option.

`; btn.innerText = "Einrichtung starten"; btn.onclick = () => { modal.close(); @@ -105,6 +105,12 @@ Dort werden die Behälter definiert, welche in den iTender gestellt werden.
D return; } + if (selects[1].value == "0") { + ele.innerHTML += `Die Sensorart Ultraschall wird nicht mehr unterstützt.
Sollten Sie diesen Support wünschen wenden Sie sich an den Kundensupport.`; + errorModal.open(); + return; + } + if (selects[1].value != "-1" && (selects[2].value == "-1" || selects[3].value == "-1")) { ele.innerHTML += `Wenn ein Sensor-Typ definiert ist, müssen alle Sensor-Pins gesetzt sein.`; errorModal.open(); @@ -137,6 +143,7 @@ Dort werden die Behälter definiert, welche in den iTender gestellt werden.
D const ambientColor = document.getElementById("ambientColor") as HTMLInputElement; const allowRemoteCheckbox = document.getElementById("allowRemoteCheckbox") as HTMLInputElement; const hotspotCheckbox = document.getElementById("hotspotCheckbox") as HTMLInputElement; + const proxyCheckbox = document.getElementById("proxyCheckbox") as HTMLInputElement; let cons: { pumpPin: number; sensorType: SensorType; sensor1: number; sensor2: number; volume: number; }[] = []; @@ -166,6 +173,7 @@ Dort werden die Behälter definiert, welche in den iTender gestellt werden.
D "led_enabled": ledCheckbox.checked, "remote_enabled": allowRemoteCheckbox.checked, "hotspot_enabled": hotspotCheckbox.checked, + "arduino_proxy_enabled": proxyCheckbox.checked, "led_gpio": parseInt(ledGPIO.value), "ambient_color": ambientColor.value }); @@ -189,25 +197,24 @@ Dort werden die Behälter definiert, welche in den iTender gestellt werden.
D } public static startTare() { - let tareModal = new Modal("tare", "Einmessung Sensoren"); + let tareModal = new Modal("tare", "Sensoren kalibrieren?"); let txt = document.createElement("p"); - txt.innerHTML = `Damit alle Sensoren korrekte Werte liefern, sollte eine Einmessung durchgeführt werden.
-Während der Einmessung müssen die Behälter einmal geleert und gefüllt werden.

`; + txt.innerHTML = `Damit alle Sensoren korrekte Werte liefern sollte möglichst oft eine Kalibrierung vorgenommen werden.
Grundsätzlich muss diese beim Einrichten neuer Sensoren ausgeführt werden und kann danach übersprungen werden.

Soll das Kalibrieren aller Sensoren gestartet werden?
Dieser Vorgang nimmt circa eine Minute in Anspruch.

`; tareModal.addContent(txt); - tareModal.addButton(ButtonType.PRIMARY, "Später", () => { + tareModal.addButton(ButtonType.PRIMARY, "Nein", () => { tareModal.close(); }); let ul; - tareModal.addButton(ButtonType.PRIMARY, "Starten", async () => { + tareModal.addButton(ButtonType.PRIMARY, "Ja", async () => { tareModal.close(); - let modal = new Modal("tare", "Einmessung"); + let modal = new Modal("tare", "Kalibrierung"); let txt = document.createElement("p"); - txt.innerHTML = `Messung Teil 1
-Bitte den Inhalt der Behälter entfernen
+ txt.innerHTML = `Kalibrierung
+Bitte den alle Behälter von den Sensoren entfernen.
Die Gewichtssensoren werden beim Bestätigen austariert

Zum fortfahren Tarieren drücken.
`; modal.addContent(txt); @@ -221,40 +228,33 @@ Die Gewichtssensoren werden beim Bestätigen austariert

Zum fortfahren Ta btn.innerText = "Tarieren"; btn.style.marginTop = "3%"; btn.onclick = () => { - let payload = new WebSocketPayload(WebSocketEvent.TARE, {tare: 0}); - WebWebSocketHandler.send(payload); + txt.innerHTML = `Kalibriere...
+Bitte warten! - Keine Behälter oder sonstige Gegenstände auf die Sensoren stellen!
+Die Gewichtssensoren werden gerade austariert...
`; + btn.disabled = true; + btn.innerText = "Abschließen" - txt.innerHTML = `Messung Teil 2
-Bitte nun alle Behälter mit Inhalt füllen und wieder einsetzen.
-Die Gewichtssensoren werden beim Bestätigen austariert.

Zum fortfahren Tarieren drücken.
`; - btn.onclick = () => { - let payload = new WebSocketPayload(WebSocketEvent.TARE, {tare: 1}); - WebWebSocketHandler.send(payload); - - btn.onclick = () => { - modal.close(); - clearInterval(tareInterval); - }; - }; + WebWebSocketHandler.request(RequestType.TARE, true).then((result) => { + let data: { success: boolean, msg: string } = result.data; + btn.disabled = false; + if (data.success) { + txt.innerHTML = `Kalibrierung abgeschlossen!
+Alle Sensoren wurden erfolgreich kalibriert.
`; + btn.onclick = () => { + modal.close(); + clearInterval(tareInterval); + }; + } else { + btn.innerText = "Erneut versuchen"; + txt.innerHTML = `Kalibrierung fehlgeschlagen!
+Mindestens ein Sensor konnte nicht kalibriert werden.
${data.msg}
`; + } + }); }; modal.addContent(btn); await modal.open(); - tareInterval = setInterval(() => WebWebSocketHandler.request(RequestType.CONTAINERS).then((payload) => { - if (!ul) return; - - ul.innerHTML = ""; - let containers = payload.data as IContainer[]; - for (let c of containers) { - if (c.sensorType == SensorType.NONE) continue; - - let li = document.createElement("li"); - li.innerText = `Behälter ${c.slot}: ${c.rawData.toFixed(3)} [${c.sensorType}]`; - ul.append(li); - } - }), 250); - }); tareModal.open();