itender/src/routes/ws/websocketRoute.ts
2023-01-11 00:06:21 +01:00

219 lines
8.7 KiB
TypeScript

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";
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; }[];
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.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.measure(container);
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."));
} else {
container.sensorDelta = 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 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.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["content"]);
} 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, iTender.currentJob);
break;
}
case RequestType.DOWNLOAD_DRINKS: {
await iTender.refreshFromServer();
WebSocketHandler.answerRequest(msg.data["type"] as RequestType, "ok");
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;
}
default: {
log("WebSocketHandler does not know how to handle " + msg.event + " Event");
}
}
});
});
module.exports = router;