diff --git a/ToDo.md b/ToDo.md index b385e04..1348114 100644 --- a/ToDo.md +++ b/ToDo.md @@ -23,7 +23,9 @@ - [ ] Da nun generell eine Fehlermeldung erscheint, sobald eine Wägezelle inkorrekt läuft, muss vor dem Tarieren (also beim Drücken von Speichern) erst eine CHECK request gesendet werden, danach folgt dann bei erfolgreich die Tarierung - [ ] Unterstützung von Arduino - [X] Programmierung der Schnittstelle für Arduino (Proxy) - - [ ] Programmierung des Arduino Codes + - [X] Programmierung des Arduino Codes - [ ] Automatischer Flash - [ ] Bei Container erstellung kann optional "Arduino Proxy" angewählt werden - - Danach werden die Daten dieses Containers über den Arduino bezogen \ No newline at end of file + - Danach werden die Daten dieses Containers über den Arduino bezogen +- [ ] Behälter Menü neu designen +- [ ] In den ganzen messfn checken ob überhaupt eingestellt ist, den proxy zu nutzen \ No newline at end of file diff --git a/src/Mixer.ts b/src/Mixer.ts index 384b3f0..92361b9 100644 --- a/src/Mixer.ts +++ b/src/Mixer.ts @@ -57,7 +57,7 @@ export class Mixer { // Start pump here try { - if (x.container.pumpProxy) { + if (x.container.useProxy) { let payload = new ArduinoProxyPayload(ArduinoProxyPayloadType.SET_PIN, { pin: x.container.pumpPin, mode: "DIGITAL", @@ -95,7 +95,7 @@ export class Mixer { log(`Stopping output of pump ${x.container.pumpPin}`); // Stop pump here try { - if (x.container.pumpProxy) { + if (x.container.useProxy) { let payload = new ArduinoProxyPayload(ArduinoProxyPayloadType.SET_PIN, { pin: x.container.pumpPin, mode: "DIGITAL", @@ -165,7 +165,7 @@ export class Mixer { for (let jobIngredient of this._currentJob.amounts) { // stop pump pin try { - if (jobIngredient.container.pumpProxy) { + if (jobIngredient.container.useProxy) { let payload = new ArduinoProxyPayload(ArduinoProxyPayloadType.SET_PIN, { pin: jobIngredient.container.pumpPin, mode: "DIGITAL", diff --git a/src/MyGPIO.ts b/src/MyGPIO.ts index 543742b..0b62762 100644 --- a/src/MyGPIO.ts +++ b/src/MyGPIO.ts @@ -46,11 +46,11 @@ export class MyGPIO { let containers = await Container.find({}); for (let c of containers) { try { - if (c.sensorType && !c.sensorProxy) { + if (c.sensorType && !c.useProxy) { await MyGPIO.setup(c.sensorPin1, GPIO.DIR_IN); await MyGPIO.setup(c.sensorPin2, GPIO.DIR_IN); } - if( c.pumpPin && !c.pumpProxy ) + if( c.pumpPin && !c.useProxy ) { await MyGPIO.setup(c.pumpPin, GPIO.DIR_OUT); await MyGPIO.write(c.pumpPin, false); diff --git a/src/SensorHelper.ts b/src/SensorHelper.ts index f822cef..9f64c9f 100644 --- a/src/SensorHelper.ts +++ b/src/SensorHelper.ts @@ -21,7 +21,7 @@ export class SensorHelper { return new Promise(async (resolve, reject) => { if (container.sensorType == SensorType.LOADCELL) { try { - if (container.sensorProxy) { + if (container.useProxy) { let payload = new ArduinoProxyPayload(ArduinoProxyPayloadType.GET_SENSOR, { pin_data: container.sensorPin1, pin_clock: container.sensorPin2 diff --git a/src/database/Container.ts b/src/database/Container.ts index f5af7b2..793fd8f 100644 --- a/src/database/Container.ts +++ b/src/database/Container.ts @@ -13,8 +13,7 @@ export const ContainerSchema = new Mongoose.Schema({ content: {type: mongoose.Types.ObjectId, ref: "Ingredient"}, sensorDelta: Number, // V2: Now sensorDelta - Differenz, welche beim Einstellen der Zutat aus Gewicht(Sensor) - Volumen errechnet wird sensorTare: Number, // V2: Now sensorTare - sensorProxy: {type: Boolean, default: false}, - pumpProxy: { type: Boolean, default: false }, + useProxy: { type: Boolean, default: false }, filled: Number, enabled: {type: Boolean, default: false}, }); diff --git a/src/database/IContainer.ts b/src/database/IContainer.ts index f05f213..7893b8d 100644 --- a/src/database/IContainer.ts +++ b/src/database/IContainer.ts @@ -21,16 +21,12 @@ export interface IContainer extends mongoose.Document { sensorPin2: number; /** - * Is the arduino used as proxy for the sensor? + * Is the arduino used as proxy? */ - sensorProxy: boolean + useProxy: boolean rawData: number; pumpPin: number; - /** - * Is the arduino used as proxy for the pump? - */ - pumpProxy: boolean filled: number; enabled: boolean; } \ No newline at end of file diff --git a/src/web/Modal.ts b/src/web/Modal.ts index 8921e6a..924dbfd 100644 --- a/src/web/Modal.ts +++ b/src/web/Modal.ts @@ -33,11 +33,23 @@ export class Modal { } + /** + * Adds an html element to the modal + * @param element + */ public addContent(element: HTMLElement) { this._elements.push(element); } + /** + * Adds a spacer line to the modal + */ + public addBR() { + this.addContent(document.createElement("br")); + } + + set id(value: string) { this._id = value; } @@ -130,10 +142,19 @@ export class Modal { } + + /** + * Closes the modal + */ public close(): void { Modal.close(this._id); } + + /** + * Closes the modal with id + * @param id The id of the modal + */ public static close(id?: string): void { if (id && this.currentModalId != id) return; diff --git a/src/web/Setup.ts b/src/web/Setup.ts index e8ec8c1..5d72e1c 100644 --- a/src/web/Setup.ts +++ b/src/web/Setup.ts @@ -11,17 +11,28 @@ import {RequestType} from "../RequestType"; export class Setup { + + private static usingProxy = false; + + private static pins_pi = [3, 7, 8, 10, 11, 12, 13, 15, 16, 18, 19, 21, 22, 23, 24, 26, 29, 31, 32, 33, 35, 36, 37, 38]; + private static pins_arduino = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53]; + + public static arduinoProxyCheckboxes: HTMLInputElement[] = []; + public static onConfigUpdate(payload: WebSocketPayload) { // Setup containers updated - const ledCheckbox = document.getElementById("ledCheckbox") as HTMLInputElement; const ledGPIO = document.getElementById("ledGPIO") as HTMLInputElement; + const ledCheckbox = document.getElementById("ledCheckbox") as HTMLInputElement; 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; + proxyCheckbox.checked = !!payload.data["arduino_proxy_enabled"]; 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"]; } @@ -31,6 +42,8 @@ export class Setup { } (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"); @@ -71,7 +84,9 @@ Dort werden die Behälter definiert, welche in den iTender gestellt werden.
D } const containerAddBtn = document.getElementById("containerAddBtn") as HTMLButtonElement; - containerAddBtn.onclick = Setup.addSetupContainer; + containerAddBtn.onclick = () => { + Setup.addSetupContainer() + }; const setupSaveBtn = document.getElementById("setup_saveBtn") as HTMLButtonElement; @@ -82,7 +97,7 @@ Dort werden die Behälter definiert, welche in den iTender gestellt werden.
D let ele = document.createElement("p"); ele.innerHTML = `Das Setup konnte nicht abgeschlossen werden.
`; errorModal.addContent(ele); - errorModal.addContent(document.createElement("br")); + errorModal.addBR(); errorModal.addButton(ButtonType.PRIMARY, "Schließen", () => { errorModal.close(); }); @@ -106,7 +121,7 @@ Dort werden die Behälter definiert, welche in den iTender gestellt werden.
D } 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.`; + ele.innerHTML += `Die Sensorart Ultraschall wird nicht mehr unterstützt.
Sollten Sie diese Funktion wünschen wenden Sie sich an den Kundensupport.`; errorModal.open(); return; } @@ -146,7 +161,8 @@ Dort werden die Behälter definiert, welche in den iTender gestellt werden.
D const proxyCheckbox = document.getElementById("proxyCheckbox") as HTMLInputElement; - let cons: { pumpPin: number; sensorType: SensorType; sensor1: number; sensor2: number; volume: number; }[] = []; + // Containers + let cons: { pumpPin: number; sensorType: SensorType; sensor1: number; sensor2: number; useProxy: boolean }[] = []; for (let c of (document.getElementById("setupContainers") as HTMLDivElement).getElementsByTagName("div")) { let sensorType = c.getElementsByTagName("select")[1].value; let type; @@ -158,11 +174,11 @@ Dort werden die Behälter definiert, welche in den iTender gestellt werden.
D type = SensorType.LOADCELL; cons.push({ + "useProxy": (c.getElementsByTagName("input")[0] as HTMLInputElement).checked, "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) + "sensor2": parseInt(c.getElementsByTagName("select")[3].value) }); } @@ -177,12 +193,13 @@ Dort werden die Behälter definiert, welche in den iTender gestellt werden.
D "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); @@ -191,6 +208,7 @@ Dort werden die Behälter definiert, welche in den iTender gestellt werden.
D txt.innerHTML = `Fehler beim Speichern.
iTender hat nicht reagiert.`; setTimeout(() => saveModal.close(), 2500); }); + menuBtn.disabled = false; } @@ -261,54 +279,67 @@ Mindestens ein Sensor konnte nicht kalibriert werden.
${data.msg}
`; } - public static addSetupContainer() { + public static addSetupContainer(container?: IContainer) { let setupContainers = document.getElementById("setupContainers") as HTMLDivElement; - let con = document.createElement("div"); + // Div + let containerDiv = document.createElement("div"); + if (container) + containerDiv.id = container._id; + + // Name let containerName = document.createElement("p"); containerName.innerText = "Behälter " + (setupContainers.getElementsByTagName("div").length + 1); - con.classList.add("setupContainer"); - con.append(containerName); + containerDiv.classList.add("setupContainer"); + containerDiv.append(containerName); + // General Pin Select let selectPin = document.createElement("select"); selectPin.style.display = "none"; selectPin.classList.add("input"); selectPin.style.display = "inline"; - + // NoSelect in Pin Select 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); - } + // Proxy Label + let proxyLabel = document.createElement("label"); + proxyLabel.innerText = "Pumpen Pin"; + containerDiv.append(proxyLabel); + // Proxy checkbox - let nSelect; + let proxyCheckbox = document.createElement("input"); + proxyCheckbox.type = "checkbox"; + proxyCheckbox.checked = !!(Setup.usingProxy && container?.useProxy); // Auto Check + proxyCheckbox.disabled = !(Setup.usingProxy); + this.arduinoProxyCheckboxes.push(proxyCheckbox); + + containerDiv.append(proxyCheckbox); + + + // Pump Pin Selector + let pumpPinSelect; 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); + containerDiv.append(pumpLabel); + pumpPinSelect = selectPin.cloneNode(true); + pumpPinSelect.onchange = () => Setup.checkContainers(); + pumpPinSelect.selectedIndex = 0; + containerDiv.append(pumpPinSelect); - con.append(document.createElement("br")); + containerDiv.append(document.createElement("br")); - // Sensor Art + + // Sensor Type Label let sensorTypeLabel = document.createElement("label"); sensorTypeLabel.innerText = "Sensor Art "; - con.append(sensorTypeLabel); + containerDiv.append(sensorTypeLabel); + // Sensor Type Select let sensorType = document.createElement("select"); sensorType.classList.add("noCheckup"); sensorType.classList.add("input"); @@ -324,30 +355,33 @@ Mindestens ein Sensor konnte nicht kalibriert werden.
${data.msg}
`; sensorTypeScale.innerText = "Wägezelle"; sensorTypeScale.value = "1"; sensorType.append(sensorTypeScale); - con.append(sensorType); - con.append(document.createElement("br")); + containerDiv.append(sensorType); + containerDiv.append(document.createElement("br")); - // Sensor 1 + + // Sensor 1 Label let sensor1Label = document.createElement("label"); sensor1Label.innerText = "Sensor 1 Pin"; - con.append(sensor1Label); + containerDiv.append(sensor1Label); + // Sensor 1 Pin Select let sensor1Select = selectPin.cloneNode(true) as HTMLSelectElement; sensor1Select.selectedIndex = 0; sensor1Select.disabled = true; sensor1Select.onchange = () => Setup.checkContainers(); - con.append(sensor1Select); + containerDiv.append(sensor1Select); - con.append(document.createElement("br")); + containerDiv.append(document.createElement("br")); - // Sensor 2 + // Sensor 2 Label let sensor2Label = document.createElement("label"); sensor2Label.innerText = "Sensor 2 Pin"; - con.append(sensor2Label); + containerDiv.append(sensor2Label); + // Sensor 2 Pin Select let sensor2Select = selectPin.cloneNode(true) as HTMLSelectElement; sensor2Select.selectedIndex = 0; sensor2Select.disabled = true; sensor2Select.onchange = () => Setup.checkContainers(); - con.append(sensor2Select); + containerDiv.append(sensor2Select); sensorType.onchange = () => { if (sensorType.value == "0") { @@ -367,49 +401,66 @@ Mindestens ein Sensor konnte nicht kalibriert werden.
${data.msg}
`; sensor2Select.disabled = true; } }; - - con.append(document.createElement("br")); + containerDiv.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; + // Proxy On change needs to be at the end to get all vars + proxyCheckbox.onchange = () => { + // Clear pins + pumpPinSelect.innerHTML = ''; + sensor1Select.innerHTML = ''; + sensor2Select.innerHTML = ''; + + // Set no-val + pumpPinSelect.append(noSel.cloneNode(true)); + sensor1Select.append(noSel.cloneNode(true)); + sensor2Select.append(noSel.cloneNode(true)); + selectPin.selectedIndex = 0; + sensor1Select.selectedIndex = 0; + sensor2Select.selectedIndex = 0; + // Add pins + for (let pin of (proxyCheckbox.checked ? Setup.pins_arduino : Setup.pins_pi)) { + let pinEle = document.createElement("option") as HTMLOptionElement; + pinEle.innerText = "" + pin; + pinEle.value = "" + pin; + pumpPinSelect.append(pinEle.cloneNode(true)); + sensor1Select.append(pinEle.cloneNode(true)); + sensor2Select.append(pinEle.cloneNode(true)); + } + }; + // Needs to be after selectPin.append because noSel-Pin should always be at pos 0 + let event = new Event('change', {bubbles: true}); + proxyCheckbox.dispatchEvent(event); // Trigger virtual onChange event + + // Auto selects (if container is given as arg) needs to be after the event, because the pin selectors may not there + if (container) { + pumpPinSelect.value = String(container.pumpPin); + sensor1Select.value = String(container.sensorPin1); + sensor2Select.value = String(container.sensorPin2); } - volumeSelect.selectedIndex = 7; - //con.append(volumeSelect); + let removeBtn = document.createElement("button"); removeBtn.classList.add("btn", "btn-danger"); removeBtn.onclick = () => { - con.classList.add("removeSlowly"); + containerDiv.classList.add("removeSlowly"); setTimeout(() => { - con.remove(); + containerDiv.remove(); let i = 1; for (let elementsByTagNameElement of setupContainers.getElementsByTagName("div")) { let e = elementsByTagNameElement.getElementsByTagName("p")[0] as HTMLParagraphElement; - e.innerText = "Behälter " + i; + e.innerText = "Behälter " + i + (containerDiv.id.length != 0 ? " [" + containerDiv.id.substring(containerDiv.id.length - 3) + "]" : ""); i++; } }, 750); } removeBtn.style.float = "right"; - removeBtn.innerText = "Entfernen"; - con.append(removeBtn); + removeBtn.innerText = "Löschen"; + containerDiv.append(removeBtn); - setupContainers.append(con); + setupContainers.append(containerDiv); } @@ -420,46 +471,28 @@ Mindestens ein Sensor konnte nicht kalibriert werden.
${data.msg}
`; let containers = payload.data["content"] as IContainer[]; for (let c of containers) { - Setup.addSetupContainer(); + Setup.addSetupContainer(c); } - - 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(); - let event = new Event('change', {bubbles: true}); - selects[1].dispatchEvent(event); - - i++; - } - } + public static checkContainers(): boolean { - console.log("Checking containers...") + 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.value == "-1") continue; // maybe this shit + if (sel.classList.contains("noCheckup")) continue; if (sel.disabled) continue; + let cIsProxy: HTMLInputElement = c.getElementsByTagName("input")[0]; for (let sel2 of c2.getElementsByTagName("select")) { if (sel2.value == "-1") continue; @@ -467,8 +500,11 @@ Mindestens ein Sensor konnte nicht kalibriert werden.
${data.msg}
`; if (sel == sel2) continue; if (sel2.classList.contains("noCheckup")) continue; + let c2IsProxy: HTMLInputElement = c2.getElementsByTagName("input")[0]; - if (sel.value == sel2.value) { + + // Check if the two pins are the same, but also checks if one is using proxy, or another one is not using it + if (sel.value == sel2.value && cIsProxy.checked == c2IsProxy.checked) { c.classList.add("error"); c2.classList.add("error"); sel.classList.add("error");