feat(ocp): printer cycling backend and frontend done :)

This commit is contained in:
2025-04-07 07:02:31 -05:00
parent 75f94eae14
commit dc5ee5b97a
14 changed files with 302 additions and 35 deletions

View File

@@ -5,6 +5,7 @@ import {
Table, Table,
TableBody, TableBody,
TableCell, TableCell,
TableFooter,
TableHead, TableHead,
TableHeader, TableHeader,
TableRow, TableRow,
@@ -137,6 +138,16 @@ export default function LabelLog() {
))} ))}
</TableBody> </TableBody>
)} )}
<TableFooter>
{labelData.length === 0 && (
<div>
<h2 className="text-center text-2xl">
No labels have been printed in the last 2 hours
</h2>
</div>
)}
</TableFooter>
</Table> </Table>
</LstCard> </LstCard>
); );

View File

@@ -71,6 +71,7 @@ export default function Lots() {
const server = settings.filter((n) => n.name === "server")[0]?.value || ""; const server = settings.filter((n) => n.name === "server")[0]?.value || "";
const roles = ["admin", "manager", "operator"]; const roles = ["admin", "manager", "operator"];
const lotdata = data ? data : [];
if (user && roles.includes(user.role)) { if (user && roles.includes(user.role)) {
//width = 1280; //width = 1280;
@@ -144,7 +145,6 @@ export default function Lots() {
</div> </div>
); );
} }
return ( return (
<LstCard className="m-2 p-2 min-h-2/5"> <LstCard className="m-2 p-2 min-h-2/5">
<ScrollArea className="h-[400px]"> <ScrollArea className="h-[400px]">
@@ -197,7 +197,7 @@ export default function Lots() {
</> </>
) : ( ) : (
<TableBody> <TableBody>
{data?.map((lot: LotType) => ( {lotdata.map((lot: LotType) => (
<TableRow key={lot.LabelOnlineID}> <TableRow key={lot.LabelOnlineID}>
<TableCell className="font-medium"> <TableCell className="font-medium">
{lot.MachineLocation} {lot.MachineLocation}

View File

@@ -10,6 +10,7 @@ export default function OCPPage() {
const { settings } = useSettingStore(); const { settings } = useSettingStore();
const server = settings.filter((n) => n.plantToken === "usday1"); const server = settings.filter((n) => n.plantToken === "usday1");
console.log(server);
return ( return (
<div className="h-screen w-full "> <div className="h-screen w-full ">
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
@@ -40,7 +41,7 @@ export default function OCPPage() {
</div> </div>
</div> </div>
<div className="w-1/6 flex flex-col"> <div className="w-1/6 flex flex-col">
{server && ( {server.length >= 1 && (
<div> <div>
<WrapperManualTrigger /> <WrapperManualTrigger />
</div> </div>

View File

@@ -9,12 +9,10 @@ import {
TableHeader, TableHeader,
TableRow, TableRow,
} from "@/components/ui/table"; } from "@/components/ui/table";
import { getPrinters } from "@/utils/querys/production/printers";
import { useQuery } from "@tanstack/react-query";
let printerCols = [ let printerCols = [
{
key: "status",
label: "Status",
},
{ {
key: "printer", key: "printer",
label: "Printer", label: "Printer",
@@ -25,10 +23,12 @@ let printerCols = [
}, },
]; ];
export default function PrinterStatus() { export default function PrinterStatus() {
return ( const { data, isError, isLoading } = useQuery(getPrinters());
<LstCard className="m-2 p-2">
<ScrollArea className="max-h-[300px]"> if (isError) {
<p className="text-center">Printer Status</p> return (
<ScrollArea className="h-[400px]">
<p className="text-center">Printer Staus error</p>
<Table> <Table>
<TableHeader> <TableHeader>
@@ -50,14 +50,65 @@ export default function PrinterStatus() {
<TableCell> <TableCell>
<Skeleton className="h-4" /> <Skeleton className="h-4" />
</TableCell> </TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow> </TableRow>
))} ))}
</TableBody> </TableBody>
</Table> </Table>
</ScrollArea> </ScrollArea>
);
}
/**
* only show the assigned printers
*/
const assigned = data?.filter((a: any) => a.assigned) || [];
return (
<LstCard className="m-2 p-2">
<ScrollArea className="max-h-[800px]">
<p className="text-center">
{isLoading ? (
<span>Printers status loading...</span>
) : (
<span>Printer Status</span>
)}
</p>
<Table>
<TableHeader>
<TableRow>
{printerCols.map((l) => (
<TableHead key={l.key}>{l.label}</TableHead>
))}
</TableRow>
</TableHeader>{" "}
{isLoading ? (
<TableBody>
{Array(5)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
) : (
<TableBody>
{assigned?.map((p: any) => (
<TableRow key={p.printer_id}>
<TableCell>{p.name}</TableCell>
<TableCell>{p.statusText}</TableCell>
</TableRow>
))}
</TableBody>
)}
</Table>
</ScrollArea>
</LstCard> </LstCard>
); );
} }

View File

@@ -0,0 +1,20 @@
import { queryOptions } from "@tanstack/react-query";
import axios from "axios";
export function getPrinters() {
return queryOptions({
queryKey: ["printers"],
queryFn: () => fetchSettings(),
staleTime: 1000,
refetchInterval: 2 * 2000,
refetchOnWindowFocus: true,
});
}
const fetchSettings = async () => {
const { data } = await axios.get(`/api/ocp/getprinters`);
// if we are not localhost ignore the devDir setting.
//const url: string = window.location.host.split(":")[0];
return data.data ?? [];
};

View File

@@ -4,13 +4,23 @@ import { settings } from "../../../../../database/schema/settings.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js"; import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { createLog } from "../../../logger/logger.js"; import { createLog } from "../../../logger/logger.js";
import { getPrinters } from "./getPrinters.js"; import { getPrinters } from "./getPrinters.js";
import { printerStatus } from "./printerStatus.js"; import { autoLabelingStats, printerStatus } from "./printerStatus.js";
let isPrinterCycling = false;
let actualPrinterCycle: any;
export const printerCycle = async () => { export const printerCycle = async () => {
/** /**
* We will cycle through the printers to check there states. * We will cycle through the printers to check there states.
*/ */
if (isPrinterCycling)
return {
success: false,
message: "Printers are already being cycled.",
};
createLog("info", "ocp", "ocp", "Printer cycle has started.");
// get the printers // get the printers
const { data: s, error: se } = await tryCatch( const { data: s, error: se } = await tryCatch(
db.select().from(settings).where(eq(settings.name, "ocpCycleDelay")) db.select().from(settings).where(eq(settings.name, "ocpCycleDelay"))
@@ -29,9 +39,9 @@ export const printerCycle = async () => {
} }
const ocpDelay: any = s; const ocpDelay: any = s;
isPrinterCycling = true;
// start the actual printer cycle // start the actual printer cycle
const actualPrinterCycle = setInterval(async () => { actualPrinterCycle = setInterval(async () => {
const { data, error } = await tryCatch(getPrinters()); const { data, error } = await tryCatch(getPrinters());
if (error) { if (error) {
@@ -51,10 +61,8 @@ export const printerCycle = async () => {
// only keep the assigned ones // only keep the assigned ones
printers = printers.filter((p: any) => p.assigned === true); printers = printers.filter((p: any) => p.assigned === true);
// for autolabelers like dayton and MCD we want to ignore them from the loop as well. // for printers we want to ignore there must be a remark stateing to ignore.
printers = printers.filter( printers = printers.filter((p: any) => !p.remark.includes("ignore"));
(p: any) => p.name != "Autolabeler" && !p.remark.includes("ignore")
);
printers.forEach(async (p: any) => { printers.forEach(async (p: any) => {
/** /**
@@ -75,7 +83,31 @@ export const printerCycle = async () => {
return; return;
} }
if (p.name === "Autolabeler") {
await autoLabelingStats(p);
return;
}
// for all other printers
await printerStatus(p); await printerStatus(p);
}); });
}, parseInt(ocpDelay[0]?.value) * 1000); }, parseInt(ocpDelay[0]?.value) * 1000);
return { success: true, message: "Printer cycle has been started." };
};
export const stopPrinterCycle = async () => {
/**
* We will stop the print cylce this is more an emergancy thing.
*/
if (actualPrinterCycle && !actualPrinterCycle._destroyed) {
createLog("info", "ocp", "ocp", "Printer cycle is being stopped.");
clearInterval(actualPrinterCycle);
isPrinterCycling = false;
return { success: true, message: "Printer cycle has been stopped." };
} else {
createLog("info", "ocp", "ocp", "Printer cycle is already stopped.");
isPrinterCycling = false;
return { success: true, message: "Printer cycle is already Stopped." };
}
}; };

View File

@@ -8,6 +8,7 @@ export const printStatus = [
{ code: 2, text: "Pending labels" }, { code: 2, text: "Pending labels" },
{ code: 3, text: "Printing to fast" }, { code: 3, text: "Printing to fast" },
{ code: 4, text: "Creating label" }, { code: 4, text: "Creating label" },
{ code: 5, text: "Waiting" },
{ code: 6, text: "Printer Paused" }, { code: 6, text: "Printer Paused" },
{ code: 7, text: "Printer error" }, { code: 7, text: "Printer error" },
{ {

View File

@@ -68,9 +68,9 @@ export const printerStatus = async (p: any) => {
"debug", "debug",
"ocp", "ocp",
"ocp", "ocp",
`${p.name}: timeBetween: ${timeBetween}, delay ${ `${p.name}: timeBetween: ${timeBetween}, delay ${parseInt(
p.printDelay || 90 p.printDelay
}, ${currentTime}... ${lastTime}` )}, ${currentTime}... ${lastTime}`
); );
if (tmp[2] === "0" && tmp[4] !== "000") { if (tmp[2] === "0" && tmp[4] !== "000") {
@@ -80,7 +80,7 @@ export const printerStatus = async (p: any) => {
"ocp", "ocp",
"ocp", "ocp",
`Unpaused and printing labels, time remaing ${differenceInSeconds( `Unpaused and printing labels, time remaing ${differenceInSeconds(
p.printDelay || 90, parseInt(p.printDelay),
timeBetween timeBetween
)}` )}`
); );
@@ -96,7 +96,7 @@ export const printerStatus = async (p: any) => {
`${ `${
p.name p.name
} paused to soon, unpausing, remaining time: ${differenceInSeconds( } paused to soon, unpausing, remaining time: ${differenceInSeconds(
p.printDelay || 90, parseInt(p.printDelay),
timeBetween timeBetween
)}` )}`
); );
@@ -105,20 +105,20 @@ export const printerStatus = async (p: any) => {
printerUpdate(p, 2); printerUpdate(p, 2);
unPausePrinter(p); unPausePrinter(p);
} else if ((tmp[2] === "0" && timeBetween < p.printDelay) || 90) { } else if (tmp[2] === "0" && timeBetween < parseInt(p.printDelay)) {
// was unpaused to soon so repause it // was unpaused to soon so repause it
createLog( createLog(
"debug", "debug",
"ocp", "ocp",
"ocp", "ocp",
`${p.name} Unpaused before the time allowed, time left ${ `${p.name} Unpaused before the time allowed, time left ${
differenceInSeconds(p.printDelay || 90, timeBetween) //seconds differenceInSeconds(parseInt(p.printDelay), timeBetween) //seconds
}` }`
); );
printerUpdate(p, 3); printerUpdate(p, 3);
pausePrinter(p); pausePrinter(p);
} else if ((tmp[2] === "0" && timeBetween > p.printDelay) || 90) { } else if (tmp[2] === "0" && timeBetween > parseInt(p.printDelay)) {
// its been long enough we can print a label // its been long enough we can print a label
createLog( createLog(
"debug", "debug",
@@ -188,3 +188,68 @@ export const printerStatus = async (p: any) => {
}); });
}); });
}; };
export const autoLabelingStats = async (p: any) => {
/**
* Checks autolabeling printers just to see what they are doing.
*/
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(",");
if (tmp[4] !== "000") {
// unpaused and printing labels - reset timer
createLog("debug", "ocp", "ocp", `Printing Labels`);
// update last time printed in the array
printerUpdate(p, 1);
}
if (tmp[4] === "000") {
// unpaused and printing labels - reset timer
createLog("debug", "ocp", "ocp", `Printing Labels`);
// update last time printed in the array
printerUpdate(p, 5);
}
});
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.",
});
});
});
};

View File

@@ -57,6 +57,7 @@ export const updatePrinters = async () => {
port: prodPrinterInfo[i].port, port: prodPrinterInfo[i].port,
remark: prodPrinterInfo[i].remark, remark: prodPrinterInfo[i].remark,
upd_date: sql`NOW()`, upd_date: sql`NOW()`,
printDelay: "90", // need to remove in a couple weeks
}, },
}) })
); );

View File

@@ -15,7 +15,8 @@ import dycoClose from "./routes/specialProcesses/dyco/closeConnection.js";
import manualprint from "./routes/labeling/manualPrint.js"; import manualprint from "./routes/labeling/manualPrint.js";
import { assignedPrinters } from "./utils/checkAssignments.js"; import { assignedPrinters } from "./utils/checkAssignments.js";
import { printerCycle } from "./controller/printers/printerCycle.js"; import { printerCycle } from "./controller/printers/printerCycle.js";
import { tryCatch } from "../../globalUtils/tryCatch.js"; import stopPrinterCycle from "./routes/printers/stopCycle.js";
import startPrinterCycle from "./routes/printers/startCycle.js";
const app = new OpenAPIHono(); const app = new OpenAPIHono();
@@ -24,6 +25,8 @@ const routes = [
//printer //printer
getPrinters, getPrinters,
updateprinters, updateprinters,
startPrinterCycle,
stopPrinterCycle,
// lots // lots
getLots, getLots,
// labeling // labeling
@@ -55,21 +58,21 @@ const ocpActive = setting.filter((n) => n.name === "ocpActive");
// do the intnal connection to the dyco // do the intnal connection to the dyco
setTimeout(() => { setTimeout(() => {
if (dycoActive[0].value === "1") { if (dycoActive[0]?.value === "1") {
dycoConnect(); dycoConnect();
} }
}, 3 * 1000); }, 3 * 1000);
// check for printers being assigned // check for printers being assigned
setInterval(() => { setInterval(() => {
if (ocpActive[0].value === "1") { if (ocpActive[0]?.value === "1") {
assignedPrinters(); assignedPrinters();
} }
}, 60 * 1000); }, 60 * 1000);
// start the printer process after everything else is up ad running // start the printer process after everything else is up ad running
setTimeout(async () => { setTimeout(async () => {
if (ocpActive[0].value === "1") { if (ocpActive[0]?.value === "1") {
await updatePrinters(); await updatePrinters();
await assignedPrinters(); await assignedPrinters();
printerCycle(); printerCycle();

View File

@@ -0,0 +1,41 @@
// an external way to creating logs
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { authMiddleware } from "../../../auth/middleware/authMiddleware.js";
import { responses } from "../../../../globalUtils/routeDefs/responses.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { printerCycle } from "../../controller/printers/printerCycle.js";
const app = new OpenAPIHono({ strict: false });
app.openapi(
createRoute({
tags: ["ocp:printers"],
summary: "starts the printers cycling.",
method: "get",
path: "/startsprintercycle",
middleware: authMiddleware,
//description: "This might be a temp soltuin during the transtion between versions",
// request: {
// body: {content: {"application/json": {schema: CreateLog}}},
// },
responses: responses(),
}),
async (c) => {
const { data, error } = await tryCatch(printerCycle());
const dataError: any = error;
if (error) {
return c.json({
success: false,
message: "Error in stopping the printer cycle",
data: dataError?.data,
});
}
const getData: any = data;
return c.json({
success: getData?.success,
message: getData?.message,
data: getData.data ?? [],
});
}
);
export default app;

View File

@@ -0,0 +1,41 @@
// an external way to creating logs
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { authMiddleware } from "../../../auth/middleware/authMiddleware.js";
import { responses } from "../../../../globalUtils/routeDefs/responses.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { stopPrinterCycle } from "../../controller/printers/printerCycle.js";
const app = new OpenAPIHono({ strict: false });
app.openapi(
createRoute({
tags: ["ocp:printers"],
summary: "Stops the printers cycling.",
method: "get",
path: "/stopprintercycle",
middleware: authMiddleware,
//description: "This might be a temp soltuin during the transtion between versions",
// request: {
// body: {content: {"application/json": {schema: CreateLog}}},
// },
responses: responses(),
}),
async (c) => {
const { data, error } = await tryCatch(stopPrinterCycle());
const dataError: any = error;
if (error) {
return c.json({
success: false,
message: "Error in stopping the printer cycle",
data: dataError?.data,
});
}
const getData: any = data;
return c.json({
success: getData?.success,
message: getData?.message,
data: getData.data ?? [],
});
}
);
export default app;

View File

@@ -8,7 +8,7 @@ import { getPrinters } from "../controller/printers/getPrinters.js";
import { createLog } from "../../logger/logger.js"; import { createLog } from "../../logger/logger.js";
export const assignedPrinters = async () => { export const assignedPrinters = async () => {
createLog("info", "ocp", "ocp", "Lot assignment check"); createLog("debug", "ocp", "ocp", "Lot assignment check");
const { data: l, error: lotError } = await tryCatch(getLots()); const { data: l, error: lotError } = await tryCatch(getLots());
if (lotError) { if (lotError) {

View File

@@ -194,7 +194,7 @@ const newSettings = [
// ocp // ocp
{ {
name: "acpActive", name: "ocpActive",
value: `1`, value: `1`,
description: "Are we pritning on demand?", description: "Are we pritning on demand?",
serviceBelowsTo: "ocp", serviceBelowsTo: "ocp",