334 lines
14 KiB
TypeScript
334 lines
14 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";
|
|
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.<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 = 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.<br>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 + "<br>Ü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.<br>Ü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;
|