Update many stuff, see toDo
Took 9 seconds
This commit is contained in:
parent
05fa75f63c
commit
cb72920611
26
ToDo.md
26
ToDo.md
@ -2,10 +2,10 @@
|
||||
|
||||
- [ ] Behälter unten rechts anzeigen
|
||||
- [ ] Status für Netzwerk oben neben Uhrzeit
|
||||
- [ ] Fix Fehler, wenn keine Getränke hinzugefügt worden sind
|
||||
- [ ] Schriftarten Lokal machen
|
||||
- [ ] ~~Fix Fehler, wenn keine Getränke hinzugefügt worden sind~~
|
||||
- [x] Schriftarten Lokal machen
|
||||
- [x] Probleme beim Laden der Container im Setup
|
||||
- [ ] Container option "Auto tare" hinzufügen
|
||||
- [ ] ~~Container option "Auto tare" hinzufügen~~
|
||||
- Heißt, sobald ein Inhalt in einen Container eingestellt wird und das Volumen angegeben ist, werden die Sensoren auf den aktuellen Füllstand als 100% gesetzt
|
||||
- [ ] Nach Speichern des Setups und bei Einmessen auf Schließen, Setup verlassen
|
||||
|
||||
@ -13,11 +13,17 @@
|
||||
------
|
||||
# New
|
||||
|
||||
- Gesamtvolumen des Containers komplett entfernen
|
||||
- Bei Behälter aktualisieren wird das Volumen des neu zu stellendes Behälters eingestellt, welches dann als 100% interpretiert wird
|
||||
- Im Setup kommt ein neues Feature, tarieren von Wägezelle (also der 0-Wert der Wägezelle) nach Speicherung, anstatt aktueller 2-Wege-Tarierung
|
||||
- Ultraschallsensor wird entfernt
|
||||
- Wenn Sensorik für Behälter vorhanden ist, nutze Wägezelle des Containers und messe anhand dessen Inhaltsmenge
|
||||
- [X] Gesamtvolumen des Containers in fill status entfernen
|
||||
- [X] Bei Behälter aktualisieren wird das Volumen des neu zu stellendes Behälters eingestellt, welches dann als 100% interpretiert wird
|
||||
- [X] Im Setup kommt ein neues Feature, tarieren von Wägezelle (also der 0-Wert der Wägezelle) nach Speicherung, anstatt aktueller 2-Wege-Tarierung
|
||||
- [X] Ultraschallsensor wird entfernt
|
||||
- [X] Wenn Sensorik für Behälter vorhanden ist, nutze Wägezelle des Containers und messe anhand dessen Inhaltsmenge
|
||||
- 1G=1ML
|
||||
- Bei Einstellung neues Inhalts wird das Gewicht als ml übersetzt, danach wird Gewicht-Eingestellte Millitier gerechnet, das Ergebnis ist das Gewicht des Behälters
|
||||
- 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
|
||||
- [X] Bei Einstellung neues Inhalts wird das Gewicht als ml übersetzt, danach wird Gewicht-Eingestellte Millitier gerechnet, das Ergebnis ist das Gewicht des Behälters
|
||||
- [ ] 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
|
||||
- [ ] Automatischer Flash
|
||||
- [ ] Bei Container erstellung kann optional "Arduino Proxy" angewählt werden
|
||||
- Danach werden die Daten dieses Containers über den Arduino bezogen
|
@ -6,7 +6,7 @@ if [ "$EUID" -ne 0 ]; then
|
||||
fi
|
||||
|
||||
echo "Creating user if not exists"
|
||||
adduser itender || true
|
||||
useradd -p $(openssl passwd -1 iTender2022) itender || true
|
||||
|
||||
echo "Updating indexes"
|
||||
apt update
|
||||
@ -52,6 +52,13 @@ echo "Installing mongodb and yarn..."
|
||||
apt install nodejs yarn mongodb-org -y
|
||||
apt upgrade -y
|
||||
|
||||
# V2: Arduino CLI
|
||||
echo "Installing arduino-cli..."
|
||||
sudo -u itender mkdir -p /home/itender/bin
|
||||
sudo -u itender sh -c 'curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=/home/itender/bin/ sh'
|
||||
sudo -u itender /home/itender/bin/arduino-cli config init
|
||||
sudo -u itender /home/itender/bin/arduino-cli core update-index || true
|
||||
|
||||
echo "Installing autostart..."
|
||||
# Autostart
|
||||
cat <<EOT >/etc/xdg/openbox/autostart
|
||||
@ -98,7 +105,8 @@ if [ -d "$DIR" ]; then
|
||||
git pull
|
||||
else
|
||||
echo "Cloning..."
|
||||
sudo git config --global credential.helper store || exit
|
||||
sudo -u itender git config --global credential.helper store
|
||||
git config --global credential.helper store
|
||||
git clone "https://tobiash:!IwedwrimmVeudiweN!@git.gaminggeneration.de/tobiash/itender.git" --quiet
|
||||
fi
|
||||
cd "$DIR" || exit
|
||||
@ -139,6 +147,7 @@ WantedBy=multi-user.target
|
||||
EOT
|
||||
#sh -c "git pull --quiet || true"
|
||||
|
||||
|
||||
echo "Activating systemctl daemons..."
|
||||
systemctl daemon-reload
|
||||
systemctl enable mongod
|
||||
@ -178,6 +187,7 @@ if ! grep -w "gpu_freq=700" /boot/config.txt; then
|
||||
echo "gpu_freq=700" >>/boot/config.txt
|
||||
fi
|
||||
|
||||
|
||||
echo "Setting no-logo..."
|
||||
systemctl disable getty@tty1.service
|
||||
|
||||
@ -191,7 +201,7 @@ if ! grep -w "logo.nologo" /boot/cmdline.txt; then
|
||||
sed -i 's/console=tty0/console=tty3/' /boot/cmdline.txt
|
||||
fi
|
||||
|
||||
echo "iTender 2022
|
||||
echo "iTender© 2022-2023
|
||||
Programmed by Tobias Hopp" >/etc/motd
|
||||
|
||||
echo "[Service]
|
||||
@ -201,4 +211,6 @@ chown itender:itender -R /home/itender/
|
||||
adduser itender gpio
|
||||
adduser itender sudo
|
||||
|
||||
echo "Installation finished!"
|
||||
|
||||
reboot now
|
||||
|
81
getSerialList.js
Normal file
81
getSerialList.js
Normal file
@ -0,0 +1,81 @@
|
||||
const { SerialPort } = require('serialport');
|
||||
const { ReadlineParser } = require('@serialport/parser-readline');
|
||||
|
||||
( async( ) => {
|
||||
console.log( await SerialPort.list() );
|
||||
|
||||
|
||||
let port = new SerialPort( { path: '/dev/ttyS11', baudRate: 9600 } );
|
||||
|
||||
/*port.on('data', function (data) {
|
||||
console.log('Data:', data.toString())
|
||||
|
||||
})*/
|
||||
|
||||
port.close()
|
||||
|
||||
let callbacks = {};
|
||||
|
||||
function request()
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
let id = makeid(8);
|
||||
console.log(id);
|
||||
|
||||
let req = {
|
||||
id: id,
|
||||
type: "REQUEST",
|
||||
data: "1,2"
|
||||
}
|
||||
|
||||
callbacks[req.id] = resolve;
|
||||
|
||||
let done = false;
|
||||
|
||||
setTimeout( () => {
|
||||
if( !done )
|
||||
reject("Request with id " + id + " timed out");
|
||||
}, 15000 );
|
||||
|
||||
port.write(JSON.stringify(req) + "\r", "utf-8");
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
const parser = port.pipe(new ReadlineParser({ delimiter: '\r' }))
|
||||
|
||||
parser.on('data', (data) => {
|
||||
/*let req = {
|
||||
id: id,
|
||||
type: "ACK",
|
||||
data: "1,2"
|
||||
}*/
|
||||
|
||||
data = data.toString().trim();
|
||||
let json = JSON.parse(data);
|
||||
|
||||
console.log("GOT: " + data );
|
||||
callbacks[json.id]();
|
||||
|
||||
});
|
||||
|
||||
try {
|
||||
await request();
|
||||
console.log("FUNCTION RESOLVED YAY!");
|
||||
} catch( e )
|
||||
{
|
||||
console.error(e);
|
||||
}
|
||||
} )();
|
||||
|
||||
function makeid(length) {
|
||||
var result = '';
|
||||
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
var charactersLength = characters.length;
|
||||
for ( var i = 0; i < length; i++ ) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
"watchWP": "webpack --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@serialport/parser-readline": "^10.5.0",
|
||||
"@types/cookie-parser": "^1.4.3",
|
||||
"@types/debug": "^4.1.7",
|
||||
"@types/express": "^4.17.14",
|
||||
@ -22,6 +23,7 @@
|
||||
"@types/node": "^18.11.9",
|
||||
"@types/rpi-gpio": "^2.1.1",
|
||||
"@types/rpi-ws281x-native": "^1.0.0",
|
||||
"@types/serialport": "^8.0.2",
|
||||
"axios": "^1.2.0",
|
||||
"buffer": "^6.0.3",
|
||||
"cookie-parser": "^1.4.6",
|
||||
@ -37,7 +39,8 @@
|
||||
"onoff": "^6.0.3",
|
||||
"pug": "2.0.0-beta11",
|
||||
"rpi-gpio": "^2.1.7",
|
||||
"rpi-ws281x-native": "^1.0.4"
|
||||
"rpi-ws281x-native": "^1.0.4",
|
||||
"serialport": "^10.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^2.0.20",
|
||||
|
93
src/ArduinoProxy.ts
Normal file
93
src/ArduinoProxy.ts
Normal file
@ -0,0 +1,93 @@
|
||||
import SerialPort from "serialport";
|
||||
import debug from "debug";
|
||||
import {ArduinoProxyPayload} from "./ArduinoProxyPayload";
|
||||
import {Utils} from "./Utils";
|
||||
import {ReadlineParser} from "@serialport/parser-readline";
|
||||
|
||||
const log = debug("itender:arduinoProxy");
|
||||
|
||||
export class ArduinoProxy {
|
||||
|
||||
private static serialPort;
|
||||
private static callbacks: Record<string, { resolve: Function, reject: Function }> = {};
|
||||
private static encoding: string = "utf-8";
|
||||
|
||||
private static onData(data) {
|
||||
data = data.toString().trim();
|
||||
try {
|
||||
let json = JSON.parse(data) as ArduinoProxyPayload;
|
||||
if (this.callbacks[json.id]) {
|
||||
this.callbacks[json.id].resolve(json);
|
||||
delete this.callbacks[json.id];
|
||||
log("Answered request " + json.id);
|
||||
} else {
|
||||
log("ERROR - Got an response from arduino but we are not waiting for it?");
|
||||
}
|
||||
} catch (e) {
|
||||
log("ERROR - Got an invalid response from arduino?");
|
||||
}
|
||||
}
|
||||
|
||||
public static connect() {
|
||||
return new Promise<void>(async (resolve, reject) => {
|
||||
// @ts-ignore
|
||||
let list = await SerialPort.list()
|
||||
|
||||
let arduino = list.find((ele) => {
|
||||
return ele.manufacturer == "Arduino";
|
||||
});
|
||||
if (!arduino) {
|
||||
return reject("No arduino found");
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
this.serialPort = new SerialPort({
|
||||
path: arduino.path,
|
||||
baudRate: 9600,
|
||||
autoOpen: false,
|
||||
});
|
||||
|
||||
this.serialPort.open((err: Error | null | undefined) => {
|
||||
if (err) {
|
||||
log("Error whilst connecting to proxy (open serial-connection)");
|
||||
log(err.name + "\n" + err.message + "\n" + err.stack);
|
||||
return reject(err.name);
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const parser = this.serialPort.pipe(new ReadlineParser({delimiter: '\r'}));
|
||||
|
||||
parser.on('data', (data) => this.onData(data));
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static disconnect() {
|
||||
if (this.serialPort.isOpen) {
|
||||
this.serialPort.close((err) => {
|
||||
this.serialPort = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static sendRequest(request: ArduinoProxyPayload, timeout: number = 1000) {
|
||||
return new Promise<ArduinoProxyPayload>((resolve, reject) => {
|
||||
let id = Utils.generateRandomString(8);
|
||||
request.id = id;
|
||||
this.callbacks[id] = {resolve: resolve, reject: reject};
|
||||
|
||||
this.serialPort.write(JSON.stringify(request), ArduinoProxy.encoding, (err: Error | null | undefined) => {
|
||||
if (err) {
|
||||
reject("I/O error on request " + id);
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
reject("Timeout on request " + id);
|
||||
delete this.callbacks[id];
|
||||
}, timeout);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
35
src/ArduinoProxyPayload.ts
Normal file
35
src/ArduinoProxyPayload.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import {ArduinoProxyPayloadType} from "./ArduinoProxyPayloadType";
|
||||
import {ArduinoProxy} from "./ArduinoProxy";
|
||||
|
||||
export class ArduinoProxyPayload {
|
||||
set id(value: string) {
|
||||
this._id = value;
|
||||
}
|
||||
|
||||
private readonly _type: ArduinoProxyPayloadType;
|
||||
private readonly _data: any;
|
||||
|
||||
private _id: string ="";
|
||||
|
||||
|
||||
constructor(type: ArduinoProxyPayloadType, data: any) {
|
||||
this._type = type;
|
||||
this._data = data;
|
||||
}
|
||||
|
||||
get type(): ArduinoProxyPayloadType {
|
||||
return this._type;
|
||||
}
|
||||
|
||||
get data(): any {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
get id(): string {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public send() {
|
||||
return ArduinoProxy.sendRequest(this);
|
||||
}
|
||||
}
|
7
src/ArduinoProxyPayloadType.ts
Normal file
7
src/ArduinoProxyPayloadType.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export enum ArduinoProxyPayloadType {
|
||||
ACK="ACK",
|
||||
SET_PIN="SET_PIN",
|
||||
GET_VAL="GET_VAL",
|
||||
GET_SENSOR="GET_SENSOR",
|
||||
RESTART="RESTART",
|
||||
}
|
0
src/ArduinoProxyUpdater.ts
Normal file
0
src/ArduinoProxyUpdater.ts
Normal file
@ -5,5 +5,7 @@ export enum RequestType {
|
||||
JOB = "JOB",
|
||||
STARTFILL = "STARTFILL",
|
||||
STOPFILL = "STOPFILL",
|
||||
DOWNLOAD_DRINKS = "DOWNLOAD_DRINKS"
|
||||
DOWNLOAD_DRINKS = "DOWNLOAD_DRINKS",
|
||||
TARE = "TARE",
|
||||
CHECK = "CHECK",
|
||||
}
|
10
src/Utils.ts
10
src/Utils.ts
@ -84,4 +84,14 @@ export class Utils {
|
||||
|
||||
|
||||
}
|
||||
|
||||
static generateRandomString(number: number) {
|
||||
let result = '';
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
const charactersLength = characters.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ export const ContainerSchema = new Mongoose.Schema<IContainer>({
|
||||
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},
|
||||
filled: Number,
|
||||
enabled: {type: Boolean, default: false},
|
||||
});
|
||||
|
@ -12,6 +12,7 @@ export interface IContainer extends mongoose.Document {
|
||||
sensorType: SensorType;
|
||||
sensorPin1: number;
|
||||
sensorPin2: number;
|
||||
sensorProxy: boolean
|
||||
rawData: number;
|
||||
pumpPin: number;
|
||||
filled: number;
|
||||
|
@ -470,13 +470,31 @@ export class iTender {
|
||||
});
|
||||
}
|
||||
|
||||
public static clearAllRawMeasurements()
|
||||
{
|
||||
return new Promise<void>(async (resolve, reject) => {
|
||||
for (let c of (await Container.find({}))) {
|
||||
if (c.sensorType != SensorType.NONE) {
|
||||
c.rawData = -1;
|
||||
await c.save();
|
||||
}
|
||||
}
|
||||
resolve();
|
||||
})
|
||||
}
|
||||
|
||||
public static measureAllRaw() {
|
||||
return new Promise<void>(async (resolve, reject) => {
|
||||
for (let c of (await Container.find({}))) {
|
||||
if (c.sensorType != SensorType.NONE) {
|
||||
let weight = SensorHelper.measure(c);
|
||||
if (weight == null) {
|
||||
let weight : number | null = c.rawData;
|
||||
if( !c.sensorProxy )
|
||||
{
|
||||
// Check values
|
||||
weight = SensorHelper.measure(c);
|
||||
}
|
||||
|
||||
if (weight == null || weight > 1000 || weight < 0 ) { //fixme werte
|
||||
// Problem erkannt!
|
||||
return reject("Fehler Sensor (" + c.sensorPin1 + ", " + c.sensorPin2 + ") - Container " + c.slot + 1);
|
||||
}
|
||||
|
@ -157,6 +157,37 @@ router.ws('/', async (ws, req, next) => {
|
||||
WebSocketHandler.answerRequest(msg.data["type"] as RequestType, "ok");
|
||||
break;
|
||||
}
|
||||
case RequestType.CHECK: {
|
||||
await iTender.clearAllRawMeasurements();
|
||||
|
||||
|
||||
let content : {error: boolean, msg: string} = {
|
||||
error: false,
|
||||
msg: ""
|
||||
};
|
||||
|
||||
// Check config
|
||||
/// Check Proxy
|
||||
if( Settings.get("arduino_proxy_enabled") == true )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Check measurements
|
||||
await iTender.measureAllRaw();
|
||||
for( let c of await Container.find() )
|
||||
{
|
||||
if( c.sensorType != SensorType.NONE && c.rawData == -1 )
|
||||
{
|
||||
content.error = true;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
case RequestType.TARE: {
|
||||
let type = msg.data["type"];
|
||||
// Start TARE
|
||||
|
@ -21,6 +21,9 @@ block setup
|
||||
div.inputGroup
|
||||
label(onclick="document.getElementById('hotspotCheckbox').checked = !document.getElementById('hotspotCheckbox').checked;") Ohne WiFi Hotspot aktivieren
|
||||
input#hotspotCheckbox.input(type="checkbox")
|
||||
div.inputGroup
|
||||
label(onclick="document.getElementById('proxyCheckbox').checked = !document.getElementById('proxyCheckbox').checked;") Arduino Mega als Proxy erlauben
|
||||
input#proxyCheckbox.input(type="checkbox")
|
||||
|
||||
|
||||
div#setupContainersDiv
|
||||
@ -52,6 +55,7 @@ block menu
|
||||
block settings
|
||||
// Settings
|
||||
button.btn.btn-primary#settings_refreshDrinks Getränke herunterladen
|
||||
button.btn.btn-primary#settings_update System aktualisieren
|
||||
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user