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.
Um ihn zu nutzen, ist eine Grund-Konfiguration (Setup) nötig.
Das Setup lässt sich später auch jederzeit aus dem Menü erneut aufrufen.
Um die Einrichtung des Gerätes abzuschließen, muss mindestens ein Behälter mit Pumpe (optional auch Sensor) hinzugefügt werden.
`;
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.
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.
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.
`;
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.
`;
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.
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...
`;
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.
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.
Während der Einmessung müssen die Behälter einmal geleert und gefüllt werden.
`;
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
Bitte den Inhalt der Behälter entfernen
Die Gewichtssensoren werden beim Bestätigen austariert
Zum fortfahren Tarieren drücken.
`;
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
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, 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;
}
}