491 lines
20 KiB
TypeScript
491 lines
20 KiB
TypeScript
import {Pane} from "./Pane";
|
|
import {Modal} from "./Modal";
|
|
import {ButtonType} from "./ButtonType";
|
|
import {WebHandler} from "./WebHandler";
|
|
import {WebSocketPayload} from "../WebSocketPayload";
|
|
import {WebSocketEvent} from "../WebSocketEvent";
|
|
import {WebWebSocketHandler} from "./WebWebSocketHandler";
|
|
import {IContainer} from "../database/IContainer";
|
|
import {SensorType} from "../SensorType";
|
|
import {RequestType} from "../RequestType";
|
|
|
|
|
|
export class Setup {
|
|
public static onConfigUpdate(payload: WebSocketPayload) {
|
|
// Setup containers updated
|
|
const ledCheckbox = document.getElementById("ledCheckbox") as HTMLInputElement;
|
|
const ledGPIO = document.getElementById("ledGPIO") as HTMLInputElement;
|
|
const ambientColor = document.getElementById("ambientColor") as HTMLInputElement;
|
|
const allowRemoteCheckbox = document.getElementById("allowRemoteCheckbox") as HTMLInputElement;
|
|
const hotspotCheckbox = document.getElementById("hotspotCheckbox") as HTMLInputElement;
|
|
|
|
ledCheckbox.checked = !!payload.data["led_enabled"];
|
|
allowRemoteCheckbox.checked = !!payload.data["remote_enabled"];
|
|
hotspotCheckbox.checked = !!payload.data["hotspot_enabled"];
|
|
if (payload.data["led_gpio"]) {
|
|
ledGPIO.value = payload.data["led_gpio"];
|
|
}
|
|
|
|
if (payload.data["ambient_color"]) {
|
|
ambientColor.value = payload.data["ambient_color"];
|
|
}
|
|
|
|
(document.getElementById("setup_cancelBtn") as HTMLButtonElement).disabled = !payload.data["setupDone"];
|
|
if (!payload.data["setupDone"]) {
|
|
let modal = new Modal("setup", "Willkommen!");
|
|
let txt = document.createElement("p");
|
|
txt.innerHTML = `Dieser iTender ist noch nicht eingerichtet.<br>Um ihn zu nutzen, ist eine Grund-Konfiguration (Setup) nötig.<br><br>Das Setup lässt sich später auch jederzeit aus dem Menü erneut aufrufen.<br>Um die Einrichtung des Gerätes abzuschließen, muss mindestens ein Behälter mit Pumpe (optional auch Sensor) hinzugefügt werden.<br><br>`;
|
|
modal.addContent(txt);
|
|
let btn = document.createElement("button");
|
|
btn.classList.add("btn", "btn-primary");
|
|
btn.innerText = "Weiter";
|
|
btn.onclick = () => {
|
|
txt.innerHTML = `Auf der folgenden Seite können nun verschiedene Module eingerichtet werden.<br><br>
|
|
<strong>LED-Modul</strong><br>
|
|
In diesem Modul kann die Ambiente-Farbe sowie der LED-Streifen aktiviert werden.<br><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>
|
|
<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>`;
|
|
btn.innerText = "Einrichtung starten";
|
|
btn.onclick = () => {
|
|
modal.close();
|
|
}
|
|
}
|
|
modal.addContent(btn);
|
|
modal.open();
|
|
}
|
|
}
|
|
|
|
static async openSetup() {
|
|
// new
|
|
|
|
WebHandler.openPane(Pane.SETUP);
|
|
let menuBtn = document.getElementById("menuBtn") as HTMLButtonElement;
|
|
menuBtn.disabled = true;
|
|
|
|
const cancelBtn = document.getElementById("setup_cancelBtn") as HTMLButtonElement;
|
|
cancelBtn.onclick = () => {
|
|
let payload = new WebSocketPayload(WebSocketEvent.SETUP, false, false);
|
|
WebWebSocketHandler.send(payload);
|
|
}
|
|
|
|
const containerAddBtn = document.getElementById("containerAddBtn") as HTMLButtonElement;
|
|
containerAddBtn.onclick = Setup.addSetupContainer;
|
|
|
|
|
|
const setupSaveBtn = document.getElementById("setup_saveBtn") as HTMLButtonElement;
|
|
setupSaveBtn.onclick = () => {
|
|
const containers = document.getElementById("setupContainers") as HTMLDivElement;
|
|
|
|
let errorModal = new Modal("setup", "Fehler!");
|
|
let ele = document.createElement("p");
|
|
ele.innerHTML = `Das Setup konnte nicht abgeschlossen werden.<br>`;
|
|
errorModal.addContent(ele);
|
|
errorModal.addContent(document.createElement("br"));
|
|
errorModal.addButton(ButtonType.PRIMARY, "Schließen", () => {
|
|
errorModal.close();
|
|
});
|
|
|
|
if (containers.childNodes.length == 0) {
|
|
ele.innerHTML += `Es muss mindestens ein Behälter hinzugefügt worden sein.`;
|
|
errorModal.open();
|
|
return;
|
|
}
|
|
|
|
for (let c of containers.getElementsByTagName("div")) {
|
|
let selects = c.getElementsByTagName("select");
|
|
if (selects[0].value == "-1") {
|
|
ele.innerHTML += `Es müssen alle Pumpen-Pins gesetzt sein.`;
|
|
errorModal.open();
|
|
c.classList.add("error");
|
|
setTimeout(() => {
|
|
c.classList.remove("error");
|
|
}, 2500);
|
|
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();
|
|
c.classList.add("error");
|
|
setTimeout(() => {
|
|
c.classList.remove("error");
|
|
}, 2500);
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
if (!Setup.checkContainers()) {
|
|
ele.innerHTML = `Einige Pins sind doppelt belegt.<br>Jeder GPIO-Pin kann nur einmal belegt werden!`;
|
|
errorModal.open();
|
|
return;
|
|
}
|
|
|
|
setupSaveBtn.disabled = true;
|
|
|
|
let saveModal = new Modal("setup", "Setup");
|
|
let txt = document.createElement("p");
|
|
txt.innerHTML = `Die Einstellungen werden gespeichert...<br>
|
|
<div class="lds-ellipsis"><div></div><div></div><div></div><div></div></div>`;
|
|
saveModal.addContent(txt);
|
|
saveModal.open();
|
|
|
|
const ledCheckbox = document.getElementById("ledCheckbox") as HTMLInputElement;
|
|
const ledGPIO = document.getElementById("ledGPIO") as HTMLInputElement;
|
|
const ambientColor = document.getElementById("ambientColor") as HTMLInputElement;
|
|
const allowRemoteCheckbox = document.getElementById("allowRemoteCheckbox") as HTMLInputElement;
|
|
const hotspotCheckbox = document.getElementById("hotspotCheckbox") as HTMLInputElement;
|
|
|
|
|
|
let cons: { pumpPin: number; sensorType: SensorType; sensor1: number; sensor2: number; volume: number; }[] = [];
|
|
for (let c of (document.getElementById("setupContainers") as HTMLDivElement).getElementsByTagName("div")) {
|
|
let sensorType = c.getElementsByTagName("select")[1].value;
|
|
let type;
|
|
if (sensorType == "-1")
|
|
type = SensorType.NONE;
|
|
else if (sensorType == "0")
|
|
type = SensorType.ULTRASOUND;
|
|
else
|
|
type = SensorType.LOADCELL;
|
|
|
|
cons.push({
|
|
"pumpPin": parseInt(c.getElementsByTagName("select")[0].value),
|
|
"sensorType": type,
|
|
"sensor1": parseInt(c.getElementsByTagName("select")[2].value),
|
|
"sensor2": parseInt(c.getElementsByTagName("select")[3].value),
|
|
"volume": parseInt(c.getElementsByTagName("select")[4].value)
|
|
});
|
|
}
|
|
|
|
let payload = new WebSocketPayload(WebSocketEvent.CONTAINERS, false, cons);
|
|
WebWebSocketHandler.send(payload);
|
|
|
|
payload = new WebSocketPayload(WebSocketEvent.CONFIG, false, {
|
|
"led_enabled": ledCheckbox.checked,
|
|
"remote_enabled": allowRemoteCheckbox.checked,
|
|
"hotspot_enabled": hotspotCheckbox.checked,
|
|
"led_gpio": parseInt(ledGPIO.value),
|
|
"ambient_color": ambientColor.value
|
|
});
|
|
menuBtn.disabled = false;
|
|
WebWebSocketHandler.send(payload).then(() => {
|
|
|
|
setTimeout(() => {
|
|
saveModal.close();
|
|
setupSaveBtn.disabled = false;
|
|
this.startTare();
|
|
}, 1000);
|
|
|
|
}).catch(() => {
|
|
setupSaveBtn.disabled = false;
|
|
txt.innerHTML = `Fehler beim Speichern.<br>iTender hat nicht reagiert.`;
|
|
setTimeout(() => saveModal.close(), 2500);
|
|
});
|
|
|
|
|
|
}
|
|
}
|
|
|
|
public static startTare() {
|
|
let tareModal = new Modal("tare", "Einmessung Sensoren");
|
|
let txt = document.createElement("p");
|
|
txt.innerHTML = `Damit alle Sensoren korrekte Werte liefern, sollte eine Einmessung durchgeführt werden.<br>
|
|
Während der Einmessung müssen die Behälter einmal geleert und gefüllt werden.<br><br>`;
|
|
tareModal.addContent(txt);
|
|
|
|
tareModal.addButton(ButtonType.PRIMARY, "Später", () => {
|
|
tareModal.close();
|
|
});
|
|
|
|
let ul;
|
|
tareModal.addButton(ButtonType.PRIMARY, "Starten", async () => {
|
|
tareModal.close();
|
|
|
|
let modal = new Modal("tare", "Einmessung");
|
|
|
|
let txt = document.createElement("p");
|
|
txt.innerHTML = `Messung Teil 1<br>
|
|
Bitte den <strong>Inhalt der Behälter entfernen</strong><br>
|
|
Die Gewichtssensoren werden beim Bestätigen austariert<br><br>Zum fortfahren Tarieren drücken.<br>`;
|
|
modal.addContent(txt);
|
|
|
|
ul = document.createElement("ul");
|
|
modal.addContent(ul);
|
|
|
|
let tareInterval: NodeJS.Timer;
|
|
|
|
let btn = document.createElement("button");
|
|
btn.classList.add("btn", "btn-primary");
|
|
btn.innerText = "Tarieren";
|
|
btn.style.marginTop = "3%";
|
|
btn.onclick = () => {
|
|
let payload = new WebSocketPayload(WebSocketEvent.TARE, false, {tare: 0});
|
|
WebWebSocketHandler.send(payload);
|
|
|
|
txt.innerHTML = `Messung Teil 2<br>
|
|
Bitte nun alle <strong>Behälter mit Inhalt füllen</strong> und wieder einsetzen.<br>
|
|
Die Gewichtssensoren werden beim Bestätigen austariert.<br><br>Zum fortfahren Tarieren drücken.<br>`;
|
|
btn.onclick = () => {
|
|
let payload = new WebSocketPayload(WebSocketEvent.TARE, false, {tare: 1});
|
|
WebWebSocketHandler.send(payload);
|
|
|
|
btn.onclick = () => {
|
|
modal.close();
|
|
clearInterval(tareInterval);
|
|
};
|
|
};
|
|
};
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
public static addSetupContainer() {
|
|
let setupContainers = document.getElementById("setupContainers") as HTMLDivElement;
|
|
|
|
let con = document.createElement("div");
|
|
|
|
let containerName = document.createElement("p");
|
|
containerName.innerText = "Behälter " + (setupContainers.getElementsByTagName("div").length + 1);
|
|
con.classList.add("setupContainer");
|
|
con.append(containerName);
|
|
|
|
let selectPin = document.createElement("select");
|
|
selectPin.style.display = "none";
|
|
selectPin.classList.add("input");
|
|
selectPin.style.display = "inline";
|
|
|
|
let noSel = document.createElement("option") as HTMLOptionElement;
|
|
noSel.innerText = "Bitte wählen";
|
|
noSel.value = "-1";
|
|
noSel.disabled = true;
|
|
|
|
selectPin.append(noSel.cloneNode(true));
|
|
selectPin.selectedIndex = 0;
|
|
// 3,5,7,8,10,11,12,13,15,16,18,19,21,22,23,24,26,29,31,32,33,35,36,37,38,40
|
|
const pins = [3, 7, 8, 10, 11, 12, 13, 15, 16, 18, 19, 21, 22, 23, 24, 26, 29, 31, 32, 33, 35, 36, 37, 38];
|
|
for (let pin of pins) {
|
|
let pinEle = document.createElement("option") as HTMLOptionElement;
|
|
pinEle.innerText = "" + pin;
|
|
pinEle.value = "" + pin;
|
|
selectPin.append(pinEle);
|
|
}
|
|
|
|
let nSelect;
|
|
|
|
let pumpLabel = document.createElement("label");
|
|
pumpLabel.innerText = "Pumpen Pin";
|
|
con.append(pumpLabel);
|
|
nSelect = selectPin.cloneNode(true);
|
|
nSelect.onchange = () => Setup.checkContainers();
|
|
nSelect.selectedIndex = 0;
|
|
con.append(nSelect);
|
|
|
|
con.append(document.createElement("br"));
|
|
|
|
// Sensor Art
|
|
let sensorTypeLabel = document.createElement("label");
|
|
sensorTypeLabel.innerText = "Sensor Art ";
|
|
con.append(sensorTypeLabel);
|
|
|
|
let sensorType = document.createElement("select");
|
|
sensorType.classList.add("noCheckup");
|
|
sensorType.classList.add("input");
|
|
let sensorTypeNone = document.createElement("option") as HTMLOptionElement;
|
|
sensorTypeNone.innerText = "Kein Sensor";
|
|
sensorTypeNone.value = "-1";
|
|
sensorType.append(sensorTypeNone);
|
|
let sensorTypeUltrasound = document.createElement("option") as HTMLOptionElement;
|
|
sensorTypeUltrasound.innerText = "Ultraschall";
|
|
sensorTypeUltrasound.value = "0";
|
|
sensorType.append(sensorTypeUltrasound);
|
|
let sensorTypeScale = document.createElement("option") as HTMLOptionElement;
|
|
sensorTypeScale.innerText = "Wägezelle";
|
|
sensorTypeScale.value = "1";
|
|
sensorType.append(sensorTypeScale);
|
|
con.append(sensorType);
|
|
con.append(document.createElement("br"));
|
|
|
|
// Sensor 1
|
|
let sensor1Label = document.createElement("label");
|
|
sensor1Label.innerText = "Sensor 1 Pin";
|
|
con.append(sensor1Label);
|
|
let sensor1Select = selectPin.cloneNode(true) as HTMLSelectElement;
|
|
sensor1Select.selectedIndex = 0;
|
|
sensor1Select.disabled = true;
|
|
sensor1Select.onchange = () => Setup.checkContainers();
|
|
con.append(sensor1Select);
|
|
|
|
con.append(document.createElement("br"));
|
|
|
|
// Sensor 2
|
|
let sensor2Label = document.createElement("label");
|
|
sensor2Label.innerText = "Sensor 2 Pin";
|
|
con.append(sensor2Label);
|
|
let sensor2Select = selectPin.cloneNode(true) as HTMLSelectElement;
|
|
sensor2Select.selectedIndex = 0;
|
|
sensor2Select.disabled = true;
|
|
sensor2Select.onchange = () => Setup.checkContainers();
|
|
con.append(sensor2Select);
|
|
|
|
sensorType.onchange = () => {
|
|
if (sensorType.value == "0") {
|
|
sensor1Label.innerText = "Trigger Pin";
|
|
sensor2Label.innerText = "Trigger Pin";
|
|
sensor1Select.disabled = false;
|
|
sensor2Select.disabled = false;
|
|
} else if (sensorType.value == "1") {
|
|
sensor1Label.innerText = "Clock Pin";
|
|
sensor2Label.innerText = "Data Pin";
|
|
sensor1Select.disabled = false;
|
|
sensor2Select.disabled = false;
|
|
} else {
|
|
sensor1Label.innerText = "Sensor 1 Pin";
|
|
sensor2Label.innerText = "Sensor 2 Pin";
|
|
sensor1Select.disabled = true;
|
|
sensor2Select.disabled = true;
|
|
}
|
|
};
|
|
|
|
con.append(document.createElement("br"));
|
|
|
|
|
|
// Volume
|
|
let volumeLabel = document.createElement("label");
|
|
volumeLabel.innerText = "Volumen (ml) ";
|
|
con.append(volumeLabel);
|
|
let volumeSelect = document.createElement("select");
|
|
volumeSelect.classList.add("noCheckup");
|
|
volumeSelect.classList.add("input");
|
|
const mls = [50, 100, 200, 250, 300, 330, 500, 750, 1000, 1250, 1500, 2000, 2500, 5000, 10000];
|
|
for (let ml of mls) {
|
|
let pinEle = document.createElement("option") as HTMLOptionElement;
|
|
pinEle.innerText = "" + ml;
|
|
pinEle.value = "" + ml;
|
|
volumeSelect.append(pinEle);
|
|
volumeSelect["volume"] = volumeSelect;
|
|
}
|
|
volumeSelect.selectedIndex = 7;
|
|
con.append(volumeSelect);
|
|
|
|
let removeBtn = document.createElement("button");
|
|
removeBtn.classList.add("btn", "btn-danger");
|
|
|
|
removeBtn.onclick = () => {
|
|
con.classList.add("removeSlowly");
|
|
setTimeout(() => {
|
|
con.remove();
|
|
let i = 1;
|
|
for (let elementsByTagNameElement of setupContainers.getElementsByTagName("div")) {
|
|
let e = elementsByTagNameElement.getElementsByTagName("p")[0] as HTMLParagraphElement;
|
|
e.innerText = "Behälter " + i;
|
|
i++;
|
|
}
|
|
}, 750);
|
|
|
|
}
|
|
removeBtn.style.float = "right";
|
|
removeBtn.innerText = "Entfernen";
|
|
con.append(removeBtn);
|
|
|
|
setupContainers.append(con);
|
|
|
|
|
|
}
|
|
|
|
public static onContainerUpdate(payload: WebSocketPayload) {
|
|
let containerDiv = document.getElementById("setupContainers") as HTMLDivElement;
|
|
containerDiv.innerHTML = "";
|
|
|
|
let containers = payload.data["content"] as IContainer[];
|
|
for (let c of containers) {
|
|
Setup.addSetupContainer();
|
|
}
|
|
|
|
let i = 0;
|
|
let list = containerDiv.getElementsByTagName("div");
|
|
for (let c of containers) {
|
|
let current = list[i] as HTMLDivElement;
|
|
let selects = current.getElementsByTagName("select");
|
|
|
|
(selects[0] as HTMLSelectElement).value = c.pumpPin.toString();
|
|
let type;
|
|
if (c.sensorType == SensorType.NONE)
|
|
type = "-1";
|
|
else if (c.sensorType == SensorType.ULTRASOUND)
|
|
type = "0";
|
|
else
|
|
type = "1";
|
|
(selects[1] as HTMLSelectElement).value = type;
|
|
(selects[2] as HTMLSelectElement).value = c.sensorPin1.toString();
|
|
(selects[3] as HTMLSelectElement).value = c.sensorPin2.toString();
|
|
(selects[4] as HTMLSelectElement).value = c.volume.toString();
|
|
let event = new Event('change', {bubbles: true});
|
|
selects[1].dispatchEvent(event);
|
|
|
|
i++;
|
|
}
|
|
|
|
}
|
|
|
|
public static checkContainers(): boolean {
|
|
console.log("Checking containers...")
|
|
let returner = true;
|
|
const containers = document.getElementById("setupContainers") as HTMLDivElement;
|
|
let setupContainers = containers.getElementsByTagName("div");
|
|
for (let c of setupContainers) {
|
|
for (let c2 of setupContainers) {
|
|
for (let sel of c.getElementsByTagName("select")) {
|
|
if (sel.value == "-1") continue;
|
|
if (sel.classList.contains("noCheckup")) continue;
|
|
if (sel.disabled) continue;
|
|
|
|
|
|
for (let sel2 of c2.getElementsByTagName("select")) {
|
|
if (sel2.value == "-1") continue;
|
|
if (sel2.disabled) continue;
|
|
if (sel == sel2) continue;
|
|
if (sel2.classList.contains("noCheckup")) continue;
|
|
|
|
|
|
if (sel.value == sel2.value) {
|
|
c.classList.add("error");
|
|
c2.classList.add("error");
|
|
sel.classList.add("error");
|
|
sel2.classList.add("error");
|
|
setTimeout(() => {
|
|
c.classList.remove("error");
|
|
c2.classList.remove("error");
|
|
sel.classList.remove("error");
|
|
sel2.classList.remove("error");
|
|
}, 2200);
|
|
returner = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return returner;
|
|
}
|
|
} |