Update v1.0.0
Took 1 hour 1 minute
Before Width: | Height: | Size: 353 KiB |
Before Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 162 KiB |
Before Width: | Height: | Size: 1.7 MiB |
Before Width: | Height: | Size: 448 KiB |
Before Width: | Height: | Size: 462 KiB |
Before Width: | Height: | Size: 3.7 MiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 1020 KiB |
Before Width: | Height: | Size: 611 KiB |
Before Width: | Height: | Size: 313 KiB |
Before Width: | Height: | Size: 167 KiB |
Before Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 253 KiB |
Before Width: | Height: | Size: 433 KiB |
Before Width: | Height: | Size: 250 KiB |
Before Width: | Height: | Size: 794 KiB |
Before Width: | Height: | Size: 116 KiB |
25
src/Utils.ts
@ -1,5 +1,6 @@
|
||||
import * as dns from "dns";
|
||||
import * as ping from "net-ping";
|
||||
import * as fs from "fs";
|
||||
import * as https from 'https';
|
||||
|
||||
export class Utils {
|
||||
public static checkInternet(): Promise<boolean> {
|
||||
@ -20,4 +21,26 @@ export class Utils {
|
||||
})
|
||||
}
|
||||
|
||||
static downloadImage(url, filepath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
https.get(url, (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
res.pipe(fs.createWriteStream(filepath))
|
||||
.on('error', reject)
|
||||
.once('close', () => resolve(filepath));
|
||||
} else {
|
||||
// Consume response data to free up memory
|
||||
res.resume();
|
||||
reject(new Error(`Request Failed With a Status Code: ${res.statusCode}`));
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static deleteImage( id )
|
||||
{
|
||||
fs.unlinkSync("./public/images/" + id + ".png");
|
||||
}
|
||||
|
||||
}
|
@ -3,8 +3,7 @@ import * as mongoose from "mongoose";
|
||||
|
||||
export const DrinkSchema = new mongoose.Schema<IDrink>({
|
||||
name: {type: String, required: true},
|
||||
ingredients: [{type: {type: mongoose.Types.ObjectId, ref: "Ingredient", required: true}, amount: { type: Number } }],
|
||||
category: String
|
||||
ingredients: [{type: {type: mongoose.Types.ObjectId, ref: "Ingredient", required: true}, amount: { type: Number } }]
|
||||
});
|
||||
|
||||
const Drink = mongoose.model<IDrink>('Drink', DrinkSchema);
|
||||
|
@ -1,5 +1,4 @@
|
||||
import {IIngredient} from "./IIngredient";
|
||||
import {Category} from "../Category";
|
||||
import * as mongoose from "mongoose";
|
||||
|
||||
export interface IDrink extends mongoose.Document {
|
||||
@ -9,8 +8,5 @@ export interface IDrink extends mongoose.Document {
|
||||
// Ingredients
|
||||
ingredients: { type: IIngredient, amount: Number }[];
|
||||
|
||||
// Category of the drink
|
||||
category: Category;
|
||||
|
||||
|
||||
}
|
@ -19,6 +19,7 @@ import {clearInterval} from "timers";
|
||||
import {RejectReason} from "./RejectReason";
|
||||
import {Settings} from "./Settings";
|
||||
import GPIO from "rpi-gpio";
|
||||
import axios from "axios";
|
||||
|
||||
const log = debug("itender:station");
|
||||
const mixLog = debug("itender:mix");
|
||||
@ -56,6 +57,7 @@ export class iTender {
|
||||
this._status = status;
|
||||
if (WebSocketHandler.ws && WebSocketHandler.ws.readyState == 1)
|
||||
WebSocketHandler.sendStatus().then().catch(console.error);
|
||||
log("Status is now " + status);
|
||||
}
|
||||
|
||||
static get status(): iTenderStatus {
|
||||
@ -138,11 +140,11 @@ export class iTender {
|
||||
let timers: NodeJS.Timeout[] = [];
|
||||
for (let x of job.amounts) {
|
||||
// Start pump here
|
||||
await GPIO.setup(x.container.pumpPin,GPIO.DIR_OUT);
|
||||
await GPIO.setup(x.container.pumpPin, GPIO.DIR_OUT);
|
||||
await GPIO.write(x.container.pumpPin, true);
|
||||
|
||||
let waitTime = (Settings.get("secondsPer100ml") as number) / 100 * x.amount * 1000;
|
||||
mixLog( `Starting output of pump ${x.container.pumpPin}` );
|
||||
mixLog(`Starting output of pump ${x.container.pumpPin}`);
|
||||
//mixLog(x.ingredient + " takes " + (waitTime / 1000) + "s for " + x.amount + "ml");
|
||||
let timer = setTimeout(() => {
|
||||
// Stop pump here
|
||||
@ -154,7 +156,7 @@ export class iTender {
|
||||
if (timers[i] != timer)
|
||||
arr.push(timers[i]);
|
||||
}
|
||||
mixLog( `Stopping output of pump ${x.container.pumpPin}` )
|
||||
mixLog(`Stopping output of pump ${x.container.pumpPin}`)
|
||||
timers = arr;
|
||||
|
||||
}, waitTime);
|
||||
@ -287,11 +289,97 @@ export class iTender {
|
||||
static refreshFromServer(): Promise<void> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
iTender.setStatus(iTenderStatus.DOWNLOADING)
|
||||
log("Refreshing drinks from server...");
|
||||
try {
|
||||
const requestIngredients = await axios.get("https://itender.iif.li/api/ingredients");
|
||||
let serverIngredients = requestIngredients.data as IIngredient[];
|
||||
log("Got " + serverIngredients.length + " ingredients from server");
|
||||
|
||||
let localIngredients = await Ingredient.find();
|
||||
for (let local of localIngredients) {
|
||||
let found = false;
|
||||
for (let remote of serverIngredients) {
|
||||
if (local.name == remote.name) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
await Ingredient.deleteOne({"_id": local._id});
|
||||
for( let c of (await Container.find( {content: local._id } )) )
|
||||
{
|
||||
c.content = undefined;
|
||||
c.save();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
for (let remote of serverIngredients) {
|
||||
let ingredient = await Ingredient.findOne({name: remote.name});
|
||||
if (!ingredient)
|
||||
ingredient = new Ingredient();
|
||||
|
||||
ingredient.name = remote.name;
|
||||
await ingredient.save();
|
||||
}
|
||||
|
||||
|
||||
|
||||
const requestDrinks = await axios.get("https://itender.iif.li/api/drinks");
|
||||
let serverDrinks = requestDrinks.data as IDrink[];
|
||||
log("Got " + serverDrinks.length + " drinks from server");
|
||||
|
||||
|
||||
let localDrinks = await Drink.find();
|
||||
for (let local of localDrinks) {
|
||||
let found = false;
|
||||
for (let remote of serverDrinks) {
|
||||
if (local.name == remote.name) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
Utils.deleteImage(local._id);
|
||||
await Drink.deleteOne({"_id": local._id});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
for (let remote of serverDrinks) {
|
||||
let drink = await Drink.findOne({name: remote.name});
|
||||
if (!drink)
|
||||
drink = new Drink();
|
||||
|
||||
drink.name = remote.name;
|
||||
drink.ingredients = remote.ingredients;
|
||||
|
||||
await drink.save();
|
||||
|
||||
|
||||
// Download thumbnail
|
||||
Utils.downloadImage("https://itender.iif.li/images/" + remote._id + ".png", "./public/images/" + drink._id + ".png").then(filepath => {
|
||||
log("Drink " + remote.name + "'s Thumbnail downloaded to " + filepath);
|
||||
}).catch(e => {
|
||||
log("Drink " + remote.name + " failed to download thumbnail!\n" + e);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
iTender.setStatus(iTenderStatus.READY);
|
||||
resolve();
|
||||
iTender.refreshDrinks();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,7 @@ router.ws('/', async (ws, req, next) => {
|
||||
break;
|
||||
}
|
||||
case RequestType.CONTAINERS: {
|
||||
WebSocketHandler.answerRequest(msg.data["type"] as RequestType, (await Container.find().sort({"slot": 1})));
|
||||
WebSocketHandler.answerRequest(msg.data["type"] as RequestType, (await Container.find().sort({"slot": 1}).populate("content")));
|
||||
break;
|
||||
}
|
||||
case RequestType.INGREDIENTS: {
|
||||
|