Update measure and tare

Took 4 hours 19 minutes
This commit is contained in:
Tobias Hopp 2023-01-11 00:06:21 +01:00
parent c509fb2bf7
commit 9626cb43c9
3 changed files with 117 additions and 70 deletions

View File

@ -86,7 +86,6 @@ export class iTender {
const job = new Job(); const job = new Job();
let amounts: { ingredient: IIngredient, amount: number, container?: IContainer }[] = []; let amounts: { ingredient: IIngredient, amount: number, container?: IContainer }[] = [];
job.completeAmount = 0; job.completeAmount = 0;
if (data.amounts) { if (data.amounts) {
@ -227,6 +226,7 @@ export class iTender {
clearInterval(iTender._jobCheckInterval); clearInterval(iTender._jobCheckInterval);
job.endAt = new Date(); job.endAt = new Date();
job.successful = true; job.successful = true;
await job.save(); await job.save();
mixLog("Job successful"); mixLog("Job successful");
setTimeout(() => iTender.setStatus(iTenderStatus.READY), 3000) setTimeout(() => iTender.setStatus(iTenderStatus.READY), 3000)
@ -263,12 +263,13 @@ export class iTender {
// ToDo // ToDo
let container: IContainer = jobIngredient.container; let container: IContainer = jobIngredient.container;
let deltaStartStop = (this._currentJob.endAt.getTime() - this._currentJob.startedAt.getTime()) / 1000; 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(); container.save().then();
} }
iTender.setStatus(iTenderStatus.READY); iTender.setStatus(iTenderStatus.READY);
} }
@ -288,7 +289,15 @@ export class iTender {
} }
// V2: New calculation method // 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(); await c.save();
} }
@ -386,10 +395,8 @@ export class iTender {
c.save(); c.save();
} }
} }
} }
for (let remote of serverIngredients) { for (let remote of serverIngredients) {
let ingredient = await Ingredient.findById(remote._id); let ingredient = await Ingredient.findById(remote._id);
if (!ingredient) if (!ingredient)
@ -463,13 +470,21 @@ export class iTender {
}); });
} }
private static interval;
public static toggleTare(state: boolean) { public static measureAllRaw() {
clearInterval(iTender.interval); return new Promise<void>(async (resolve, reject) => {
if (state) for (let c of (await Container.find({}))) {
this.interval = setInterval(async () => { if (c.sensorType != SensorType.NONE) {
await this.measureContainers(); let weight = SensorHelper.measure(c);
}, 500); if (weight == null) {
// Problem erkannt!
return reject("Fehler Sensor (" + c.sensorPin1 + ", " + c.sensorPin2 + ") - Container " + c.slot + 1);
}
c.rawData = weight;
await c.save();
}
}
resolve();
})
} }
} }

View File

@ -23,7 +23,6 @@ router.ws('/', async (ws, req, next) => {
log("Incoming websocket connection..."); log("Incoming websocket connection...");
if (WebSocketHandler.ws) { if (WebSocketHandler.ws) {
iTender.toggleTare(false);
WebSocketHandler.ws.close(1001); WebSocketHandler.ws.close(1001);
} }
WebSocketHandler.ws = ws; WebSocketHandler.ws = ws;
@ -44,14 +43,6 @@ router.ws('/', async (ws, req, next) => {
switch (msg.event) { switch (msg.event) {
case WebSocketEvent.TARE: {
if (msg.data["state"] == true) {
iTender.toggleTare(true);
} else {
iTender.toggleTare(false);
}
break;
}
case WebSocketEvent.CONTAINERS: { case WebSocketEvent.CONTAINERS: {
let data = msg.data as { pumpPin: number; sensorType: SensorType; sensor1: number; sensor2: number; }[]; 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 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: { 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; if (!container) break;
let ingredient; let ingredient;
@ -83,20 +74,16 @@ router.ws('/', async (ws, req, next) => {
ingredient = undefined; ingredient = undefined;
} }
let filled : number = parseInt(msg.data["filled"]); let filled: number = parseInt(msg.data["filled"]);
container.filled = filled; container.filled = filled;
container.volume = filled; // V2: Volume is now being updated after change of ingredient 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); let raw = SensorHelper.measure(container);
if( !raw ) if (!raw) {
{ await WebSocketHandler.send(new WebSocketPayload(WebSocketEvent.ERROR, "Der Sensor hat beim Austarieren einen ungültigen Wert zurückgegeben.<br>Dies weist auf eine Fehlkonfiguration oder kaputten Sensor hin.<br>Aus Sicherheitsgründen wurde der Sensor für diesen Behälter deaktiviert."));
await WebSocketHandler.send(new WebSocketPayload(WebSocketEvent.ERROR, "Der Sensor hat beim Austarieren einen ungültigen Wert zurückgegeben.<br>Dies weist auf eine Fehlkonfiguration oder kaputten Sensor hin.<br>Aus Sicherheitsgründen wurde der Sensor für diesen Behälter deaktiviert." )); } else {
}
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 = 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"); WebSocketHandler.answerRequest(msg.data["type"] as RequestType, "ok");
break; 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; break;

View File

@ -44,9 +44,9 @@ export class Setup {
<strong>LED-Modul</strong><br> <strong>LED-Modul</strong><br>
In diesem Modul kann die Ambiente-Farbe sowie der LED-Streifen aktiviert werden.<br><br> In diesem Modul kann die Ambiente-Farbe sowie der LED-Streifen aktiviert werden.<br><br>
<strong>Erweiterte Einstellungen</strong><br> <strong>Erweiterte Einstellungen</strong><br>
Hier lässt sich konfigurieren, ob die Nutzung der Remote-Bedienung erlaubt ist, oder ein Hotspot aktiviert werden soll, falls keine WiFI-Verbindung vorliegt.<br><br> Hier lässt sich konfigurieren, ob die Nutzung der Remote-Bedienung erlaubt ist, oder ein Hotspot aktiviert werden soll, falls keine WiFI-Verbindung vorliegt.<br>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.<br><br>
<strong>Behälter-Modul</strong><br> <strong>Behälter-Modul</strong><br>
Dort werden die Behälter definiert, welche in den iTender gestellt werden.<br>Dort müssen GPIO-Pins der Pumpe, etwaige Sensoren-Typen und Pins definiert werden.<br>Außerdem wird das Volumen eingestellt.<br><br>`; Dort werden die Behälter definiert, welche in den iTender gestellt werden.<br>Dort müssen GPIO-Pins der Pumpe, etwaige Sensoren-Typen und Pins definiert werden.<br>Ggf. steht hier auch die Proxy-Option.<br><br>`;
btn.innerText = "Einrichtung starten"; btn.innerText = "Einrichtung starten";
btn.onclick = () => { btn.onclick = () => {
modal.close(); modal.close();
@ -105,6 +105,12 @@ Dort werden die Behälter definiert, welche in den iTender gestellt werden.<br>D
return; return;
} }
if (selects[1].value == "0") {
ele.innerHTML += `Die Sensorart Ultraschall wird nicht mehr unterstützt.<br>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")) { 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.`; ele.innerHTML += `Wenn ein Sensor-Typ definiert ist, müssen alle Sensor-Pins gesetzt sein.`;
errorModal.open(); errorModal.open();
@ -137,6 +143,7 @@ Dort werden die Behälter definiert, welche in den iTender gestellt werden.<br>D
const ambientColor = document.getElementById("ambientColor") as HTMLInputElement; const ambientColor = document.getElementById("ambientColor") as HTMLInputElement;
const allowRemoteCheckbox = document.getElementById("allowRemoteCheckbox") as HTMLInputElement; const allowRemoteCheckbox = document.getElementById("allowRemoteCheckbox") as HTMLInputElement;
const hotspotCheckbox = document.getElementById("hotspotCheckbox") 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; }[] = []; 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.<br>D
"led_enabled": ledCheckbox.checked, "led_enabled": ledCheckbox.checked,
"remote_enabled": allowRemoteCheckbox.checked, "remote_enabled": allowRemoteCheckbox.checked,
"hotspot_enabled": hotspotCheckbox.checked, "hotspot_enabled": hotspotCheckbox.checked,
"arduino_proxy_enabled": proxyCheckbox.checked,
"led_gpio": parseInt(ledGPIO.value), "led_gpio": parseInt(ledGPIO.value),
"ambient_color": ambientColor.value "ambient_color": ambientColor.value
}); });
@ -189,25 +197,24 @@ Dort werden die Behälter definiert, welche in den iTender gestellt werden.<br>D
} }
public static startTare() { public static startTare() {
let tareModal = new Modal("tare", "Einmessung Sensoren"); let tareModal = new Modal("tare", "Sensoren kalibrieren?");
let txt = document.createElement("p"); let txt = document.createElement("p");
txt.innerHTML = `Damit alle Sensoren korrekte Werte liefern, sollte eine Einmessung durchgeführt werden.<br> txt.innerHTML = `Damit alle Sensoren korrekte Werte liefern sollte möglichst oft eine Kalibrierung vorgenommen werden.<br>Grundsätzlich muss diese beim Einrichten neuer Sensoren ausgeführt werden und kann danach übersprungen werden.<br><br>Soll das Kalibrieren aller Sensoren gestartet werden?<br>Dieser Vorgang nimmt circa eine Minute in Anspruch.<br><br>`;
Während der Einmessung müssen die Behälter einmal geleert und gefüllt werden.<br><br>`;
tareModal.addContent(txt); tareModal.addContent(txt);
tareModal.addButton(ButtonType.PRIMARY, "Später", () => { tareModal.addButton(ButtonType.PRIMARY, "Nein", () => {
tareModal.close(); tareModal.close();
}); });
let ul; let ul;
tareModal.addButton(ButtonType.PRIMARY, "Starten", async () => { tareModal.addButton(ButtonType.PRIMARY, "Ja", async () => {
tareModal.close(); tareModal.close();
let modal = new Modal("tare", "Einmessung"); let modal = new Modal("tare", "Kalibrierung");
let txt = document.createElement("p"); let txt = document.createElement("p");
txt.innerHTML = `Messung Teil 1<br> txt.innerHTML = `Kalibrierung<br>
Bitte den <strong>Inhalt der Behälter entfernen</strong><br> Bitte den <strong>alle</strong> Behälter von den Sensoren entfernen.<br>
Die Gewichtssensoren werden beim Bestätigen austariert<br><br>Zum fortfahren Tarieren drücken.<br>`; Die Gewichtssensoren werden beim Bestätigen austariert<br><br>Zum fortfahren Tarieren drücken.<br>`;
modal.addContent(txt); modal.addContent(txt);
@ -221,40 +228,33 @@ Die Gewichtssensoren werden beim Bestätigen austariert<br><br>Zum fortfahren Ta
btn.innerText = "Tarieren"; btn.innerText = "Tarieren";
btn.style.marginTop = "3%"; btn.style.marginTop = "3%";
btn.onclick = () => { btn.onclick = () => {
let payload = new WebSocketPayload(WebSocketEvent.TARE, {tare: 0}); txt.innerHTML = `Kalibriere...<br>
WebWebSocketHandler.send(payload); <strong>Bitte warten!</strong> - Keine Behälter oder sonstige Gegenstände auf die Sensoren stellen!<br>
Die Gewichtssensoren werden gerade austariert...<br>`;
btn.disabled = true;
btn.innerText = "Abschließen"
txt.innerHTML = `Messung Teil 2<br> WebWebSocketHandler.request(RequestType.TARE, true).then((result) => {
Bitte nun alle <strong>Behälter mit Inhalt füllen</strong> und wieder einsetzen.<br> let data: { success: boolean, msg: string } = result.data;
Die Gewichtssensoren werden beim Bestätigen austariert.<br><br>Zum fortfahren Tarieren drücken.<br>`; btn.disabled = false;
btn.onclick = () => { if (data.success) {
let payload = new WebSocketPayload(WebSocketEvent.TARE, {tare: 1}); txt.innerHTML = `Kalibrierung abgeschlossen!<br>
WebWebSocketHandler.send(payload); Alle Sensoren wurden erfolgreich kalibriert.<br>`;
btn.onclick = () => {
btn.onclick = () => { modal.close();
modal.close(); clearInterval(tareInterval);
clearInterval(tareInterval); };
}; } else {
}; btn.innerText = "Erneut versuchen";
txt.innerHTML = `Kalibrierung fehlgeschlagen!<br>
Mindestens ein Sensor konnte nicht kalibriert werden.<br>${data.msg}<br>`;
}
});
}; };
modal.addContent(btn); modal.addContent(btn);
await modal.open(); 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(); tareModal.open();