import {WebSocketPayload} from "../../WebSocketPayload"; import debug from "debug"; import {WebSocketHandler} from "../../WebSocketHandler"; import {iTender} from "../../iTender"; import {iTenderStatus} from "../../iTenderStatus"; import {WebSocketEvent} from "../../WebSocketEvent"; import Container from "../../database/Container"; import {SensorType} from "../../SensorType"; import {Settings} from "../../Settings"; import Ingredient from "../../database/Ingredient"; import {RequestType} from "../../RequestType"; import {IJob} from "../../database/IJob"; import {SensorHelper} from "../../SensorHelper"; import {IContainer} from "../../database/IContainer"; import {Mixer} from "../../Mixer"; import {ArduinoProxy} from "../../ArduinoProxy"; import {ContainerHelper} from "../../ContainerHelper"; import * as os from "os"; import {promisify} from "util"; const exec = promisify(require('child_process').exec) const express = require('express'); const router = express.Router(); const log = debug("itender:websocket"); router.ws('/', async (ws, req, next) => { log("Incoming websocket connection..."); if (WebSocketHandler.ws) { WebSocketHandler.ws.close(1001); } WebSocketHandler.ws = ws; await WebSocketHandler.sendRunningConfig(); await WebSocketHandler.sendContainers(); await WebSocketHandler.sendStatus(); await WebSocketHandler.sendDrinks(); ws.on('message', async (raw, bool) => { let msg = WebSocketPayload.parseFromBase64Json(raw); // If message is null, close the socket because it could not be decompiled if (!msg) { ws.close(1011); return; } switch (msg.event) { case WebSocketEvent.CONTAINERS: { let data = msg.data as { pumpPin: number; sensorType: SensorType; sensor1: number; sensor2: number; useProxy: boolean }[]; await Container.deleteMany({}); // V2: Remove this and check every container based on id if changes occurs let i = 0; for (let c of data) { let container = new Container(); container.slot = i; //container.volume = c.volume; // V2: Removed container.pumpPin = c.pumpPin; container.useProxy = c.useProxy; container.sensorType = c.sensorType; container.sensorPin1 = c.sensor1; container.sensorPin2 = c.sensor2; container.enabled = true; await container.save(); i++; } break; } case WebSocketEvent.CONTAINER_UPDATE: { let container: IContainer | null = await Container.findById(msg.data["container"]); if (!container) break; let ingredient; if (msg.data["ingredient"] != null) { ingredient = await Ingredient.findById(msg.data["ingredient"]); if (!ingredient) ingredient = undefined; } 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) { let raw = SensorHelper.measureRaw(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 { container.sensorDelta = await raw - filled; // V2: Kalkuliere differenz zwischen Gewicht und gefülltem Inhalt // Todo Möglicherweise ist der "raw"-Wert nicht Gewicht } } container.content = ingredient; await container.save(); await ContainerHelper.measureContainers(); await iTender.refreshDrinks(); break; } case WebSocketEvent.CONFIG: { // ToDo console.log("New Settings:", msg.data); // Danach setup modus aus for (const [key, value] of Object.entries(msg.data)) { Settings.set(key, value); } Settings.setupDone = true; break; } case WebSocketEvent.SETUP: { if ((msg.data as boolean)) { iTender.setStatus(iTenderStatus.SETUP); } else { if (Settings.setupDone) { iTender.setStatus(iTenderStatus.READY); await WebSocketHandler.sendRunningConfig(); } } await WebSocketHandler.sendContainers(); break; } case WebSocketEvent.CANCEL: { await Mixer.cancelFill(); break; } case WebSocketEvent.REQUEST: { log("Request to " + msg.data["type"]); switch (msg.data["type"] as RequestType) { case RequestType.STATS: { await WebSocketHandler.sendStats(); break; } case RequestType.CONTAINERS: { WebSocketHandler.answerRequest(msg.data["type"] as RequestType, (await Container.find().sort({"slot": 1}).populate("content"))); break; } case RequestType.INGREDIENTS: { WebSocketHandler.answerRequest(msg.data["type"] as RequestType, (await Ingredient.find().sort({"name": 1}))); break; } case RequestType.STARTFILL: { let job: IJob | null = null; try { job = await iTender.onReceiveFill(msg.data.data); } catch (e: any) { console.error(e); } WebSocketHandler.answerRequest(msg.data["type"] as RequestType, {success: (!!job), job: job}); break; } case RequestType.JOB: { WebSocketHandler.answerRequest(msg.data["type"] as RequestType, Mixer.currentJob); break; } case RequestType.DOWNLOAD_DRINKS: { await iTender.refreshFromServer(); WebSocketHandler.answerRequest(msg.data["type"] as RequestType, "ok"); break; } case RequestType.CHECK: { let conf = msg.data.data as { "led_enabled": boolean, "remote_enabled": boolean, "hotspot_enabled": boolean, "arduino_proxy_enabled": boolean, "led_gpio": number, "ambient_color": string } await SensorHelper.clearAllRawMeasurements(); let content: { success: boolean, msg: string } = { success: true, msg: "Prüfung erfolgreich." }; // Check config /// Check Proxy if (conf["arduino_proxy_enabled"]) { try { await ArduinoProxy.disconnect(); } catch( e ) { } try { await ArduinoProxy.connect(); } catch (e) { log("Checkup failed"); content.success = false; content.msg = "Bei der Kommunikation mit dem Arduino Proxy ist ein Fehler aufgetreten.
Technische Details: " + e; return WebSocketHandler.answerRequest(msg.data["type"] as RequestType, content); } } // Check measurements try { await SensorHelper.measureAllRaw(); } catch (e) { content.success = false; content.msg = e + "
Überprüfe die Einstellungen der Sensoren-Pins."; return WebSocketHandler.answerRequest(msg.data["type"] as RequestType, content); } for (let c of await Container.find()) { if (c.sensorType != SensorType.NONE && c.rawData == -1) { content.success = false; content.msg = "Container " + (c.slot + 1) + " weist Fehler im Sensor auf.
Überprüfe die Einstellungen der Sensoren-Pins."; return WebSocketHandler.answerRequest(msg.data["type"] as RequestType, content); } } return WebSocketHandler.answerRequest(msg.data["type"] as RequestType, content); 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(); } } let timeouts: NodeJS.Timer[] = []; async function measureAndSafe() { try { await SensorHelper.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; for (let t of timeouts) clearTimeout(t); } } timeouts.push(setTimeout(measureAndSafe, 500)); timeouts.push(setTimeout(measureAndSafe, 1000)); timeouts.push(setTimeout(measureAndSafe, 2000)); timeouts.push(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; } case RequestType.UPDATE: { /* - git pull - yarn install - yarn run compile - (arduino update?) - reboot */ break; } case RequestType.INFO: { let nets = os.networkInterfaces(); let net = nets["wlan0"]; if(!net) net = nets["wlp0s20f3"]; let ipAddr : string = ""; if( net ) for( let addr of net ) { if( addr.family == "IPv4" && addr.address && addr.address !== "127.0.0.1" ) ipAddr = addr.address; } let packageJson = require('../../../package.json'); let wifi = (await exec("iwgetid")).stdout let data = { "internet": iTender.internetConnection, "ip": ipAddr, "network": wifi.substring(wifi.indexOf('"')+1,wifi.length-2), "uptime": (await exec("uptime -p")).stdout.substring(3), "version": packageJson.version } return WebSocketHandler.answerRequest(msg.data["type"] as RequestType, data); break; } } break; } default: { log("WebSocketHandler does not know how to handle " + msg.event + " Event"); } } }); }); module.exports = router;