From 51cc4aa3701db036477f8577ea4fedcd414a60f5 Mon Sep 17 00:00:00 2001 From: Blake Matthes Date: Sun, 6 Apr 2025 07:48:05 -0500 Subject: [PATCH] feat(ocp): completly moved ocp to lst --- server/globalUtils/timeZoneFix.ts | 13 ++ server/services/logger/logger.ts | 2 +- server/services/logistics/logisticsService.ts | 3 + .../ocp/controller/labeling/labelProcess.ts | 7 +- .../ocp/controller/printers/printerCycle.ts | 87 ++++++-- .../controller/printers/printerStatUpdate.ts | 61 ++++++ .../ocp/controller/printers/printerStatus.ts | 190 ++++++++++++++++++ .../ocp/controller/printers/updatePrinters.ts | 2 +- .../dualPrinting/dualPrinting.ts | 4 +- server/services/ocp/ocpService.ts | 31 ++- server/services/ocp/utils/checkAssignments.ts | 80 +++----- .../utils/getMachineId.ts | 6 +- server/services/server/utils/settingsCheck.ts | 58 +++--- 13 files changed, 448 insertions(+), 96 deletions(-) create mode 100644 server/globalUtils/timeZoneFix.ts create mode 100644 server/services/ocp/controller/printers/printerStatUpdate.ts create mode 100644 server/services/ocp/controller/printers/printerStatus.ts rename server/services/ocp/{controller/specialProcesses => }/utils/getMachineId.ts (73%) diff --git a/server/globalUtils/timeZoneFix.ts b/server/globalUtils/timeZoneFix.ts new file mode 100644 index 0000000..0b3e68f --- /dev/null +++ b/server/globalUtils/timeZoneFix.ts @@ -0,0 +1,13 @@ +import { addHours } from "date-fns"; + +export const timeZoneFix = () => { + /** + * Returns iso date based on current timezone. + */ + const rawDate = new Date(Date.now()).toISOString(); + const offsetMinutes = new Date().getTimezoneOffset(); // in minutes + const offsetHours = + -offsetMinutes / 60 >= 0 ? offsetMinutes / 60 : -offsetMinutes / 60; + + return addHours(rawDate, offsetHours).toISOString(); +}; diff --git a/server/services/logger/logger.ts b/server/services/logger/logger.ts index 4fc864d..2a66f0e 100644 --- a/server/services/logger/logger.ts +++ b/server/services/logger/logger.ts @@ -1,6 +1,6 @@ import { pino, type LogFn, type Logger } from "pino"; -export let logLevel = process.env.LOGLEVEL || "info"; +export let logLevel = process.env.LOG_LEVEL || "info"; const transport = pino.transport({ targets: [ diff --git a/server/services/logistics/logisticsService.ts b/server/services/logistics/logisticsService.ts index b0695d3..9b98289 100644 --- a/server/services/logistics/logisticsService.ts +++ b/server/services/logistics/logisticsService.ts @@ -4,6 +4,8 @@ import comsumeMaterial from "./route/consumeMaterial.js"; import returnMat from "./route/returnMaterial.js"; import createSiloAdjustment from "./route/siloAdjustments/createSiloAdjustment.js"; import postComment from "./route/siloAdjustments/postComment.js"; +import getStockSilo from "./route/siloAdjustments/getStockData.js"; + const app = new OpenAPIHono(); const routes = [ @@ -13,6 +15,7 @@ const routes = [ // silo createSiloAdjustment, postComment, + getStockSilo, ] as const; // app.route("/server", modules); diff --git a/server/services/ocp/controller/labeling/labelProcess.ts b/server/services/ocp/controller/labeling/labelProcess.ts index f6a076f..32ab9e2 100644 --- a/server/services/ocp/controller/labeling/labelProcess.ts +++ b/server/services/ocp/controller/labeling/labelProcess.ts @@ -3,7 +3,6 @@ import { settings } from "../../../../../database/schema/settings.js"; import { tryCatch } from "../../../../globalUtils/tryCatch.js"; import { createLog } from "../../../logger/logger.js"; import { getLots } from "../lots/lots.js"; -import { getMac } from "../specialProcesses/utils/getMachineId.js"; import { billingCheck } from "../specialProcesses/billingCheck/billingCheck.js"; import { isMainMatStaged } from "../materials/mainMaterial.js"; import { firstLotLabel } from "../specialProcesses/lotChangeLabel/lotCHangeLabel.js"; @@ -12,9 +11,11 @@ import { createLabel } from "./createLabel.js"; import { bookInLabel } from "./bookIn.js"; import { delieryInhouse } from "../specialProcesses/inhouse/inhouseDelivery.js"; import { dualPrintingProcess } from "../specialProcesses/dualPrinting/dualPrinting.js"; +import { getMac } from "../../utils/getMachineId.js"; interface Printer { name: string; + humanReadableId: string; // Add any other expected properties } @@ -72,7 +73,9 @@ export const labelingProcess = async ({ if (printer) { // filter the lot based on the printerID // console.log(printer); - filteredLot = lots.data.filter((l: any) => l.printerID === printer); + filteredLot = lots.data.filter( + (l: any) => l.printerID === parseInt(printer?.humanReadableId) + ); if (filteredLot.length === 0) { // console.log(`There is not a lot assigned to ${printer.name}`); createLog( diff --git a/server/services/ocp/controller/printers/printerCycle.ts b/server/services/ocp/controller/printers/printerCycle.ts index 0c79e37..4559f2d 100644 --- a/server/services/ocp/controller/printers/printerCycle.ts +++ b/server/services/ocp/controller/printers/printerCycle.ts @@ -1,20 +1,81 @@ +import { eq } from "drizzle-orm"; +import { db } from "../../../../../database/dbclient.js"; +import { settings } from "../../../../../database/schema/settings.js"; +import { tryCatch } from "../../../../globalUtils/tryCatch.js"; +import { createLog } from "../../../logger/logger.js"; import { getPrinters } from "./getPrinters.js"; +import { printerStatus } from "./printerStatus.js"; export const printerCycle = async () => { /** * We will cycle through the printers to check there states. */ - let printers = await getPrinters(); - /** - * if the last timeprinted would be greater than x well just change the status to idle and extended based on the 2 times. - * - * to get a printer going again label will need to come from the front end as that will just unpause the printer and start the labeling, or the api for manual print - * well need to adjust this to actually print the label then unpause it. - * - * it will be - * - * less than x since time printed run the printer status - * greater than x but less than y change the status to idle, but ping to make sure its online, - * if greater than y change to extended idle but stil also ping to make sure its online. - */ + + // get the printers + const { data: s, error: se } = await tryCatch( + db.select().from(settings).where(eq(settings.name, "ocpCycleDelay")) + ); + if (se) { + createLog( + "error", + "ocp", + "ocp", + "There was an error getting the ocpCycleDelay." + ); + return { + success: false, + message: "Error getting printers.", + }; + } + + const ocpDelay: any = s; + + // start the actual printer cycle + const actualPrinterCycle = setInterval(async () => { + const { data, error } = await tryCatch(getPrinters()); + + if (error) { + createLog( + "error", + "ocp", + "ocp", + "There was an error getting the printers." + ); + return { + success: false, + message: "Error getting printers.", + }; + } + let printers: any = data.data; + + // only keep the assigned ones + printers = printers.filter((p: any) => p.assigned === true); + + // for autolabelers like dayton and MCD we want to ignore them from the loop as well. + printers = printers.filter( + (p: any) => p.name != "Autolabeler" && !p.remark.includes("ignore") + ); + + printers.forEach(async (p: any) => { + /** + * if the last timeprinted would be greater than x well just change the status to idle and extended based on the 2 times. + * + * to get a printer going again label will need to come from the front end as that will just unpause the printer and start the labeling, or the api for manual print + * well need to adjust this to actually print the label then unpause it. + * + * it will be + * + * less than x since time printed run the printer status + * greater than x but less than y change the status to idle, but ping to make sure its online, + * if greater than y change to extended idle but stil also ping to make sure its online. + */ + + // ignore pdf printer as we want it here for testing purposes + if (p.name.toLowerCase() === "pdf24") { + return; + } + + await printerStatus(p); + }); + }, parseInt(ocpDelay[0]?.value) * 1000); }; diff --git a/server/services/ocp/controller/printers/printerStatUpdate.ts b/server/services/ocp/controller/printers/printerStatUpdate.ts new file mode 100644 index 0000000..117b013 --- /dev/null +++ b/server/services/ocp/controller/printers/printerStatUpdate.ts @@ -0,0 +1,61 @@ +import { eq, sql } from "drizzle-orm"; +import { db } from "../../../../../database/dbclient.js"; +import { printerData } from "../../../../../database/schema/printers.js"; +import { createLog } from "../../../logger/logger.js"; + +export const printStatus = [ + { code: 1, text: "Printing" }, + { code: 2, text: "Pending labels" }, + { code: 3, text: "Printing to fast" }, + { code: 4, text: "Creating label" }, + { code: 6, text: "Printer Paused" }, + { code: 7, text: "Printer error" }, + { + code: 8, + text: "First time printing", + }, +]; + +export const printerUpdate = async (printer: any, status: any) => { + /** + * Updates the status of the printer. + */ + + // get current time + let pd = {}; + const currentTime = sql`NOW()`; + + if (status === 3) { + pd = { + status: status, + statusText: printStatus.filter((c) => c.code === status)[0]?.text, + }; + } else if (status === 6) { + pd = { + status: status, + statusText: printStatus.filter((c) => c.code === status)[0]?.text, + }; + } else { + pd = { + lastTimePrinted: currentTime, + status: status, + statusText: printStatus.filter((c) => c.code === status)[0]?.text, + }; + } + + if (printer.humanReadableId) { + try { + await db + .update(printerData) + .set(pd) + .where( + eq(printerData.humanReadableId, printer.humanReadableId) + ); + } catch (error) { + createLog("error", "ocp", "ocp", `Error updating printer state`); + } + } + + // console.log(printerUpdate.name); + return; +}; diff --git a/server/services/ocp/controller/printers/printerStatus.ts b/server/services/ocp/controller/printers/printerStatus.ts new file mode 100644 index 0000000..041ced9 --- /dev/null +++ b/server/services/ocp/controller/printers/printerStatus.ts @@ -0,0 +1,190 @@ +import net from "net"; +import { pausePrinter } from "../../utils/pausePrinter.js"; +import { addHours, differenceInSeconds } from "date-fns"; +import { printerUpdate } from "./printerStatUpdate.js"; +import { createLog } from "../../../logger/logger.js"; +import { unPausePrinter } from "../../utils/unpausePrinter.js"; + +import { labelingProcess } from "../labeling/labelProcess.js"; +import { timeZoneFix } from "../../../../globalUtils/timeZoneFix.js"; + +let logLevel: string = process.env.LOG_LEVEL || "info"; +let errorCheck = false; +export const printerStatus = async (p: any) => { + /** + * Checks each printer to see what the current state is + */ + createLog("debug", "ocp", "ocp", `Printer cycling`); + + const printer = new net.Socket(); + + return new Promise((resolve) => { + // connect to the printer, and check its status + printer.connect(p.port, p.ipAddress, async () => { + // write the message to the printer below gives us a feedback of the printer + printer.write("~HS"); + }); + + // read the data from the printer + printer.on("data", async (data) => { + const res = data.toString(); + + // turn the data into an array to make it more easy to deal with + const tmp = res.split(","); + + //--------------- time stuff----------------------------------------------------------------- + // get last time printed + const lastTime = new Date(p.lastTimePrinted).toISOString(); + // console.log(lastTime); + + // current time? + + /** + * + * add the time zone to the settings db + */ + // const currentTime = addHours( + // new Date(Date.now()), + // -6 + // ).toISOString(); + + const currentTime = timeZoneFix(); + + let timeBetween = 0; + // if this is our first time printing pause the printer to start the timer, else we just update the time between timer + if (lastTime === undefined) { + printer.end(); + printerUpdate(p, 8); + pausePrinter(p); + resolve({ success: true, message: "First Time printing" }); + } else { + timeBetween = differenceInSeconds(currentTime, lastTime); + } + + // --- end time --- + + // --- printer logic --- + createLog( + "debug", + "ocp", + "ocp", + `${p.name}: timeBetween: ${timeBetween}, delay ${ + p.printDelay || 90 + }, ${currentTime}... ${lastTime}` + ); + + if (tmp[2] === "0" && tmp[4] !== "000") { + // unpaused and printing labels - reset timer + createLog( + "debug", + "ocp", + "ocp", + `Unpaused and printing labels, time remaing ${differenceInSeconds( + p.printDelay || 90, + timeBetween + )}` + ); + + // update last time printed in the array + printerUpdate(p, 1); + } else if (tmp[2] === "1" && tmp[4] !== "000") { + // was paused or label sent from somewhere else + createLog( + "info", + "ocp", + "ocp", + `${ + p.name + } paused to soon, unpausing, remaining time: ${differenceInSeconds( + p.printDelay || 90, + timeBetween + )}` + ); + + // reset the timer for this printer as well other labels shouldnt be sent but if we send them ok + printerUpdate(p, 2); + + unPausePrinter(p); + } else if ((tmp[2] === "0" && timeBetween < p.printDelay) || 90) { + // was unpaused to soon so repause it + createLog( + "debug", + "ocp", + "ocp", + `${p.name} Unpaused before the time allowed, time left ${ + differenceInSeconds(p.printDelay || 90, timeBetween) //seconds + }` + ); + + printerUpdate(p, 3); + pausePrinter(p); + } else if ((tmp[2] === "0" && timeBetween > p.printDelay) || 90) { + // its been long enough we can print a label + createLog( + "debug", + "ocp", + "ocp", + `${p.name} Allowed time passed and printing new label` + ); + + // update last time printed in the array + printerUpdate(p, 4); + + // sending over for labeling. + labelingProcess({ printer: p }); + } else if (tmp[2] === "0") { + // printer was unpaused for the first time or made it here + createLog( + "debug", + "ocp", + "ocp", + `${p.name} Frist time printing` + ); + + // add the time and printer + printerUpdate(p, 4); + + // sending over for labeling. + labelingProcess({ printer: p }); + } else if (tmp[2] === "1") { + // printer is paused and waiting + createLog( + "debug", + "ocp", + "ocp", + `${p.name} paused and waiting` + ); + + printerUpdate(p, 6); + } + + printer.end(); + + resolve({ success: true, message: "Print cycle completed." }); + }); + + printer.on("error", async (error) => { + // just going to say theres an error with the printer + + if (!errorCheck) { + createLog( + "error", + "ocp", + "ocp", + `${p.name} encountered an error: ${error}` + ); + } + + await printerUpdate(p, 7); + errorCheck = true; + + // send log data + // fake line + printer.end(); + resolve({ + success: false, + message: "There was an error with the printer.", + }); + }); + }); +}; diff --git a/server/services/ocp/controller/printers/updatePrinters.ts b/server/services/ocp/controller/printers/updatePrinters.ts index 27fcf0a..4869275 100644 --- a/server/services/ocp/controller/printers/updatePrinters.ts +++ b/server/services/ocp/controller/printers/updatePrinters.ts @@ -25,7 +25,7 @@ export const updatePrinters = async () => { ); if (prodError) { - console.log(prodError); + //console.log(prodError); return { success: false, message: "there was an error getting the printers.", diff --git a/server/services/ocp/controller/specialProcesses/dualPrinting/dualPrinting.ts b/server/services/ocp/controller/specialProcesses/dualPrinting/dualPrinting.ts index a8a9602..4207fe9 100644 --- a/server/services/ocp/controller/specialProcesses/dualPrinting/dualPrinting.ts +++ b/server/services/ocp/controller/specialProcesses/dualPrinting/dualPrinting.ts @@ -88,7 +88,7 @@ export const dualPrintingProcess = async (lotInfo: any) => { "info", "ocp", "ocp", - `Printing label for ${whatToPrint.MachineDescription}` + `Printing label for ${whatToPrint[0].MachineDescription}` ); return whatToPrint; } @@ -103,7 +103,7 @@ export const dualPrintingProcess = async (lotInfo: any) => { "info", "ocp", "ocp", - `Printing label for ${whatToPrint.MachineDescription}` + `Printing label for ${whatToPrint[0].MachineDescription}` ); return whatToPrint; } diff --git a/server/services/ocp/ocpService.ts b/server/services/ocp/ocpService.ts index b106ee8..ea781fd 100644 --- a/server/services/ocp/ocpService.ts +++ b/server/services/ocp/ocpService.ts @@ -13,6 +13,9 @@ import { dycoConnect } from "./controller/specialProcesses/dyco/plcConnection.js import dycoCon from "./routes/specialProcesses/dyco/connection.js"; import dycoClose from "./routes/specialProcesses/dyco/closeConnection.js"; import manualprint from "./routes/labeling/manualPrint.js"; +import { assignedPrinters } from "./utils/checkAssignments.js"; +import { printerCycle } from "./controller/printers/printerCycle.js"; +import { tryCatch } from "../../globalUtils/tryCatch.js"; const app = new OpenAPIHono(); @@ -43,14 +46,34 @@ app.all("/ocp/*", (c) => { }); }); +/** + * Get the settings so we only run items when they are truly active + */ +const dycoActive = setting.filter((n) => n.name == "dycoConnect"); +const ocpActive = setting.filter((n) => n.name === "ocpActive"); // run the printer update on restart just to keep everything good -setTimeout(() => { - updatePrinters(); -}, 3 * 1000); // do the intnal connection to the dyco setTimeout(() => { - dycoConnect(); + if (dycoActive[0].value === "1") { + dycoConnect(); + } }, 3 * 1000); +// check for printers being assigned +setInterval(() => { + if (ocpActive[0].value === "1") { + assignedPrinters(); + } +}, 60 * 1000); + +// start the printer process after everything else is up ad running +setTimeout(async () => { + if (ocpActive[0].value === "1") { + await updatePrinters(); + await assignedPrinters(); + printerCycle(); + } +}, 10 * 1000); + export default app; diff --git a/server/services/ocp/utils/checkAssignments.ts b/server/services/ocp/utils/checkAssignments.ts index bf00a36..27b0b10 100644 --- a/server/services/ocp/utils/checkAssignments.ts +++ b/server/services/ocp/utils/checkAssignments.ts @@ -1,9 +1,14 @@ +import { eq, sql } from "drizzle-orm"; +import { db } from "../../../../database/dbclient.js"; +import { printerData } from "../../../../database/schema/printers.js"; import { delay } from "../../../globalUtils/delay.js"; import { tryCatch } from "../../../globalUtils/tryCatch.js"; import { getLots } from "../controller/lots/lots.js"; import { getPrinters } from "../controller/printers/getPrinters.js"; +import { createLog } from "../../logger/logger.js"; export const assignedPrinters = async () => { + createLog("info", "ocp", "ocp", "Lot assignment check"); const { data: l, error: lotError } = await tryCatch(getLots()); if (lotError) { @@ -23,63 +28,44 @@ export const assignedPrinters = async () => { }; } - const printers: any = print; - const lots: any = l; + const printers: any = print.data; + const lots: any = l.data; - for (let i = 0; i < printers.data.length; i++) { + for (let i = 0; i < printers.length; i++) { // is the printer assinged in alplalabel online? - const assigned = lots.data.filter( - (p: any) => p.printerID === printers[i].humanReadableId + const assigned = lots.filter( + (p: any) => p.printerID === parseInt(printers[i].humanReadableId) ); + let assignedPrinter = false; // if true update the assigned field to true if (assigned.length >= 1) { assignedPrinter = true; } - // if the last time printed is greater than 5 min change the status to 10 - // const lastTime = new Date(printers[i].lastTimePrinted); - // let status = printers[i].status; - // let statusText = printers[i].statusText; + // update the printer to set its assignment + const { data: p, error: pe } = await tryCatch( + db + .update(printerData) + .set({ assigned: assignedPrinter, upd_date: sql`NOW()` }) + .where( + eq(printerData.humanReadableId, printers[i].humanReadableId) + ) + ); - // // states we consider idle - // const printerStateCheck = [1, 2, 3, 4, 5, 6, 10]; - // if ( - // differenceInMinutes(currentTime, lastTime) >= 60 && - // printerStateCheck.includes(printers[i].status) && - // printers[i].assigned - // ) { - // createLog( - // "printerState", - // "info", - // `${printers[i].name} has been idle for more than 60 min, doing a heartbeat check` - // ); - - // status = 11; - // statusText = "idle"; - - // // printerState({printerCheck: printers[i]}); - // } else if (differenceInMinutes(currentTime, lastTime) > 5 && printers[i].status === 7) { - // createLog( - // "printerState", - // "info", - // `${printers[i].name} has been errored for more 5 min changing to idle until, until it gets checked at the hour heartbeat.` - // ); - // status = 10; - // statusText = "idle"; - // } - - // const updatePrinter = await prisma.printers.update({ - // where: { - // humanReadableId: printers[i].humanReadableId, - // }, - // data: { - // assigned: assignedPrinter, - // // status, - // // statusText, - // upd_date: new Date(Date.now()).toISOString(), - // }, - // }); + if (pe) { + createLog( + "error", + "ocp", + "ocp", + `${printers[i].name} encountered an error updating: ${pe}` + ); + return { + success: false, + message: "Error while updating the prints.", + data: pe, + }; + } //delaying 250ms await delay(250); diff --git a/server/services/ocp/controller/specialProcesses/utils/getMachineId.ts b/server/services/ocp/utils/getMachineId.ts similarity index 73% rename from server/services/ocp/controller/specialProcesses/utils/getMachineId.ts rename to server/services/ocp/utils/getMachineId.ts index af48db6..5d3ff9d 100644 --- a/server/services/ocp/controller/specialProcesses/utils/getMachineId.ts +++ b/server/services/ocp/utils/getMachineId.ts @@ -1,6 +1,6 @@ -import { createLog } from "../../../../logger/logger.js"; -import { query } from "../../../../sqlServer/prodSqlServer.js"; -import { machineCheck } from "../../../../sqlServer/querys/ocp/machineId.js"; +import { machineCheck } from "../../sqlServer/querys/ocp/machineId.js"; +import { createLog } from "../../logger/logger.js"; +import { query } from "../../sqlServer/prodSqlServer.js"; export const getMac = async (machine: string) => { let updateQuery = machineCheck.replaceAll("[loc]", machine); diff --git a/server/services/server/utils/settingsCheck.ts b/server/services/server/utils/settingsCheck.ts index 9f83dc6..52c65ee 100644 --- a/server/services/server/utils/settingsCheck.ts +++ b/server/services/server/utils/settingsCheck.ts @@ -191,33 +191,45 @@ const newSettings = [ serviceBelowsTo: "system", roleToChange: "admin", }, + + // ocp + { + name: "acpActive", + value: `1`, + description: "Are we pritning on demand?", + serviceBelowsTo: "ocp", + roleToChange: "admin", + }, + { + name: "ocpCycleDelay", + value: `10`, + description: "How long between printer cycles do we want to monitor.", + serviceBelowsTo: "ocp", + roleToChange: "admin", + }, ]; export const areSettingsIn = async () => { // get the roles try { - const settingsCheck = await db.select().from(settings); - - if (settingsCheck.length !== newSettings.length) { - try { - const newRole = await db - .insert(settings) - .values(newSettings) - .onConflictDoNothing() // this will only update the ones that are new :D - .returning({ name: settings.name }); - createLog( - "info", - "lst", - "server", - "Settings were just added due to missing them on server startup" - ); - } catch (error) { - createLog( - "error", - "lst", - "server", - "There was an error adding new roles to the db" - ); - } + try { + const newRole = await db + .insert(settings) + .values(newSettings) + .onConflictDoNothing() // this will only update the ones that are new :D + .returning({ name: settings.name }); + createLog( + "info", + "lst", + "server", + "Settings were just added due to missing them on server startup" + ); + } catch (error) { + createLog( + "error", + "lst", + "server", + "There was an error adding new roles to the db" + ); } } catch (error) { createLog(