import {IJob} from "./database/IJob"; import {iTenderStatus} from "./iTenderStatus"; import {MyGPIO} from "./MyGPIO"; import GPIO from "rpi-gpio"; import {SensorType} from "./SensorType"; import {clearInterval} from "timers"; import {IContainer} from "./database/IContainer"; import {iTender} from "./iTender"; import debug from "debug"; import {ArduinoProxyPayload} from "./ArduinoProxyPayload"; import {ArduinoProxyPayloadType} from "./ArduinoProxyPayloadType"; import {ArduinoProxy} from "./ArduinoProxy"; const isPI = require("detect-rpi"); const log = debug("itender:mix"); export class Mixer { static get currentJob(): IJob { return this._currentJob; } /** * Timers for the job, for the pumps etc. * @private */ private static _jobTimers: NodeJS.Timeout[] = []; /** * The current itender job * @private */ private static _currentJob: IJob; /** * Checks if the job has finished every 500ms * @private */ private static _jobEndCheckInterval: NodeJS.Timer; /** * Start the internal fill method, a sub-method of the onReceiveFill method * This method only gets executed if REALLY all is okay, it is the internal function * @param job */ static async startFill(job: IJob) { job.startedAt = new Date(); await job.populate([{path: "amounts.ingredient"}, {path: "amounts.container"}, {path: "drink"}]); log("New fill job " + job.drink.name + " will take " + job.estimatedTime + "s"); this._currentJob = job; iTender.setStatus(iTenderStatus.FILLING); for (let x of job.amounts) { // Start pump here try { if (x.container.useProxy) { let payload = new ArduinoProxyPayload(ArduinoProxyPayloadType.SET_PIN, { pin: x.container.pumpPin, mode: "DIGITAL", value: 255 }); await ArduinoProxy.sendRequest(payload); } else { await MyGPIO.setup(x.container.pumpPin, GPIO.DIR_OUT) await MyGPIO.write(x.container.pumpPin, true); } } catch (e) { if (isPI()) { log("[ERROR] GPIO I/O Error " + e); // Todo error handling to user await this.cancelFill(); return; } else { log("[WARNING] GPIO I/O Error, but it's normal cause you are not on raspberry"); } } let waitTime = (iTender.secondsPer100ml as number) / 100 * x.amount * 1000; log(`Starting output of pump ${x.container.pumpPin}`); //mixLog(x.ingredient + " takes " + (waitTime / 1000) + "s for " + x.amount + "ml"); let timer = setTimeout(async () => { // Remove from list of timers let arr: NodeJS.Timer[] = []; for (let i = 0; i < this._jobTimers.length; i++) { if (this._jobTimers[i] != timer) arr.push(this._jobTimers[i]); } log(`Stopping output of pump ${x.container.pumpPin}`); // Stop pump here try { if (x.container.useProxy) { let payload = new ArduinoProxyPayload(ArduinoProxyPayloadType.SET_PIN, { pin: x.container.pumpPin, mode: "DIGITAL", "value": 0 }); await ArduinoProxy.sendRequest(payload); } else { await MyGPIO.write(x.container.pumpPin, false); } } catch (e) { if (isPI()) { log("[ERROR] GPIO I/O Error " + e); await this.cancelFill(); return; } else { log("[WARNING] GPIO I/O Error, but it's normal cause you are not on raspberry"); } } if (x.container.sensorType == SensorType.NONE) { // V2: Manual measuring x.container.filled = x.container.filled - x.amount; await x.container.save(); } this._jobTimers = arr; }, waitTime); this._jobTimers.push(timer); } this._jobEndCheckInterval = setInterval(async () => { if (this._jobTimers.length != 0) return; clearInterval(this._jobEndCheckInterval); job.endAt = new Date(); job.successful = true; await job.save(); log("Job successful"); setTimeout(() => iTender.setStatus(iTenderStatus.READY), 3000) }, 500); } /** * Cancel the fill instantly */ static async cancelFill() { if (!this._currentJob || iTender.status != iTenderStatus.FILLING) return; clearInterval(this._jobEndCheckInterval); this._currentJob.successful = false; this._currentJob.endAt = new Date(); await this._currentJob.save(); for (let timer of this._jobTimers) { // Clears all the ongoing stop timers clearTimeout(timer); } for (let jobIngredient of this._currentJob.amounts) { // stop pump pin try { if (jobIngredient.container.useProxy) { let payload = new ArduinoProxyPayload(ArduinoProxyPayloadType.SET_PIN, { pin: jobIngredient.container.pumpPin, mode: "DIGITAL", "value": 0 }); await ArduinoProxy.sendRequest(payload); } else { await MyGPIO.write(jobIngredient.container.pumpPin, false); } } catch (e) { } // ToDo v2 calc let container: IContainer = jobIngredient.container; let deltaStartStop = (this._currentJob.endAt.getTime() - this._currentJob.startedAt.getTime()) / 1000; // füllmenge - ( ( (stopp-start) / 1000 ) * ( sekunden100ml / 100 ) ) container.filled = container.filled - (deltaStartStop * (iTender.secondsPer100ml / 100)) // V2: Near the current fill value based on time values from delta start stop container.save().then(); } iTender.setStatus(iTenderStatus.READY); } }