feat(ocp): added zechettis stuff in

This commit is contained in:
2025-09-22 22:39:57 -05:00
parent bc6485ca9a
commit 4ab43d91b9
5 changed files with 244 additions and 225 deletions

View File

@@ -78,6 +78,7 @@ export const labelingProcess = async ({
// if we are running the zechettii // if we are running the zechettii
if (zechette) { if (zechette) {
if (zechette.line === "0") return;
const macId = await getMac(zechette.line); const macId = await getMac(zechette.line);
// filter out the lot for the line // filter out the lot for the line
filteredLot = lots.data.filter( filteredLot = lots.data.filter(
@@ -163,7 +164,11 @@ export const labelingProcess = async ({
} }
// if there are more than 2 lots it might be an auto labeler, autolabeler will be defined by its id for now only dayton // if there are more than 2 lots it might be an auto labeler, autolabeler will be defined by its id for now only dayton
if (filteredLot?.length > 2 && plantToken[0].value !== "usday1") { const plantsCanHaveMultiLots = ["usday1", "usmcd1"];
if (
filteredLot?.length > 2 &&
!plantsCanHaveMultiLots.includes(plantToken[0].value)
) {
createLog( createLog(
"error", "error",
"labeling", "labeling",
@@ -205,6 +210,8 @@ export const labelingProcess = async ({
}; };
} }
// as we want to allow zechetti to print no matter what if we zechettii is true skip all this and just print the label
if (!zechette) {
// check the material... mm,color (auto and manual combined), pkg // check the material... mm,color (auto and manual combined), pkg
const mmStaged = await isMainMatStaged(filteredLot[0]); const mmStaged = await isMainMatStaged(filteredLot[0]);
@@ -226,7 +233,10 @@ export const labelingProcess = async ({
); );
// do we want to over run // do we want to over run
if (filteredLot[0].overPrinting === "no" && filteredLot[0].Remaining <= 0) { if (
filteredLot[0].overPrinting === "no" &&
filteredLot[0].Remaining <= 0
) {
createLog( createLog(
"error", "error",
"labeling", "labeling",
@@ -258,6 +268,7 @@ export const labelingProcess = async ({
}; };
} }
createLog("info", "labeling", "ocp", `Is prolink good? ${prolink}`); createLog("info", "labeling", "ocp", `Is prolink good? ${prolink}`);
}
// create the label // create the label
const label = await createLabel(filteredLot[0], userPrinted); const label = await createLabel(filteredLot[0], userPrinted);
@@ -273,9 +284,12 @@ export const labelingProcess = async ({
} }
// send over to be booked in if we can do it. // send over to be booked in if we can do it.
// same here if we are passing zechettii dont try to book in
const bookin = settingData.filter((s) => s.name === "bookin"); const bookin = settingData.filter((s) => s.name === "bookin");
let book: any = []; let book: any = [];
if (bookin[0].value === "1") { if (bookin[0].value === "1" && !zechette) {
book = await bookInLabel(label.data); book = await bookInLabel(label.data);
if (!book.success) { if (!book.success) {

View File

@@ -1,177 +0,0 @@
import { Controller, Tag } from "st-ethernet-ip";
import { labelingProcess } from "../../labeling/labelProcess.js";
import { createLog } from "../../../../logger/logger.js";
let plcAddress = "192.168.193.97"; // zechetti 2
let lastProcessedTimestamp = 0;
let PLC = new Controller() as any;
const labelerTag = new Tag("N7[0]"); // change the car to a or b depending on what zechetti.
//const t = new Tag("CONV_M01_SHTL_UNLD_IN_FROM_PREV_CONV_TRACK_CODE.PAL_ORIGIN_LINE_N") // this is for the new zechette to reach the pallet form
let pollingInterval: any = null;
let heartbeatInterval: any = null;
let reconnecting = false;
let lastTag = 0;
// Track last successful read
let lastHeartbeat: number = Date.now();
export async function zechitti1Connect() {
try {
createLog(
"info",
"zechitti1",
"ocp",
`Connecting to PLC at ${plcAddress}...`
);
await PLC.connect(plcAddress, 0);
createLog("info", "zechitti1", "ocp", "Zechetti 2 connected.");
// Start polling tags
startPolling();
// Start heartbeat
// startHeartbeat();
// Handle disconnects/errors
PLC.on("close", () => {
console.warn("PLC connection closed.");
handleReconnect();
});
PLC.on("error", (err: any) => {
createLog("error", "zechitti1", "ocp", `PLC error: ${err.message}`);
handleReconnect();
});
} catch (err: any) {
createLog(
"error",
"zechitti1",
"ocp",
`Initial connection failed: ${err.message}`
);
handleReconnect();
}
}
function startPolling() {
if (pollingInterval) clearInterval(pollingInterval);
pollingInterval = setInterval(async () => {
try {
await PLC.readTag(labelerTag);
//lastHeartbeat = Date.now();
const tagTime: any = new Date(labelerTag.timestamp);
// so we make sure we are not missing a pallet remove it from the lastTag so we can get this next label correctly
if (
labelerTag.value == 0 &&
Date.now() - lastProcessedTimestamp >= 45000
) {
lastTag = labelerTag.value;
}
// if the tag is not zero and its been longer than 30 seconds and the last tag is not equal to the current tag we can print
if (
labelerTag.value !== 0 &&
lastTag !== labelerTag.value &&
tagTime !== lastProcessedTimestamp &&
Date.now() - lastProcessedTimestamp >= 30000
) {
lastProcessedTimestamp = tagTime;
lastTag = labelerTag.value;
console.log(
`Time since last check: ${
Date.now() - tagTime
}, greater than 30000, ${
Date.now() - lastProcessedTimestamp >= 30000
}, the line to be printed is ${labelerTag.value}`
);
//console.log(labelerTag);
const zechette = {
line: labelerTag.value.toString(),
printer: 22, // this is the id of the zechetti 2 to print we should move this to the db
printerName: "Zechetti1",
};
labelingProcess({ zechette: zechette });
}
} catch (err: any) {
createLog(
"error",
"zechitti1",
"ocp",
`Polling error: ${err.message}`
);
handleReconnect();
}
}, 1000);
}
// function startHeartbeat() {
// if (heartbeatInterval) clearInterval(heartbeatInterval);
// heartbeatInterval = setInterval(() => {
// const diff = Date.now() - lastHeartbeat;
// if (diff > 60000) {
// // 1 minute
// console.warn(`⚠️ Heartbeat timeout: no data for ${diff / 1000}s`);
// handleReconnect();
// }
// }, 10000); // check every 10s
// }
async function handleReconnect() {
if (reconnecting) return;
reconnecting = true;
if (pollingInterval) {
clearInterval(pollingInterval);
pollingInterval = null;
}
let delay = 2000; // start at 2s
let attempts = 0;
const maxAttempts = 10; // or limit by time, e.g. 2 min total
while (!PLC.connected && attempts < maxAttempts) {
attempts++;
createLog(
"info",
"zechitti1",
"ocp",
`Reconnect attempt ${attempts}/${maxAttempts} in ${
delay / 1000
}s...`
);
await new Promise((res) => setTimeout(res, delay));
try {
PLC = new Controller(); // fresh instance
await PLC.connect(plcAddress, 0);
createLog("info", "zechitti1", "ocp", "Reconnected to PLC!");
reconnecting = false;
startPolling();
return;
} catch (err: any) {
createLog(
"error",
"zechitti1",
"ocp",
`Reconnect attempt failed: ${err.message}`
);
delay = Math.min(delay * 2, 30000); // exponential backoff up to 30s
}
}
if (!PLC.connected) {
createLog(
"error",
"zechitti1",
"ocp",
"Max reconnect attempts reached. Stopping retries."
);
reconnecting = false;
// optional: exit process or alert someone here
// process.exit(1);
}
}

View File

@@ -0,0 +1,27 @@
import { createPlcMonitor } from "../../../utils/plcController.js";
export const zechettiConnect = () => {
const config: any = {
controllers: [
{
id: "Z1",
ip: "192.168.193.97",
slot: 0,
rpi: 250,
tags: ["N7[0]"],
},
{
id: "Z2",
ip: "192.168.193.111",
slot: 0,
rpi: 100,
tags: ["N8[0]"],
},
],
};
const monitor = createPlcMonitor(config);
// Start
monitor.start();
};

View File

@@ -17,7 +17,6 @@ import { assignedPrinters } from "./utils/checkAssignments.js";
import { printerCycle } from "./controller/printers/printerCycle.js"; import { printerCycle } from "./controller/printers/printerCycle.js";
import stopPrinterCycle from "./routes/printers/stopCycle.js"; import stopPrinterCycle from "./routes/printers/stopCycle.js";
import startPrinterCycle from "./routes/printers/startCycle.js"; import startPrinterCycle from "./routes/printers/startCycle.js";
import { printerCycleAutoLabelers } from "./controller/printers/printerCycleAutoLabelers.js";
import AutostartPrinterCycle from "./routes/printers/autoLabelerStart.js"; import AutostartPrinterCycle from "./routes/printers/autoLabelerStart.js";
import AutostopPrinterCycle from "./routes/printers/autoLabelerStop.js"; import AutostopPrinterCycle from "./routes/printers/autoLabelerStop.js";
import { deleteLabels } from "../../globalUtils/dbCleanUp/labelCleanUp.js"; import { deleteLabels } from "../../globalUtils/dbCleanUp/labelCleanUp.js";
@@ -26,7 +25,8 @@ import labelRatio from "./routes/labeling/getLabelRatio.js";
import resetRatio from "./routes/labeling/resetLabelRatio.js"; import resetRatio from "./routes/labeling/resetLabelRatio.js";
import materialTransferLot from "./routes/materials/lotTransfer.js"; import materialTransferLot from "./routes/materials/lotTransfer.js";
import pendingTransfers from "./routes/materials/currentPending.js"; import pendingTransfers from "./routes/materials/currentPending.js";
import { zechitti1Connect } from "./controller/specialProcesses/zechettis/zechetti1.js"; import { createPlcMonitor } from "./utils/plcController.js";
import { zechettiConnect } from "./controller/specialProcesses/zechettis/zechettiConnect.js";
const app = new OpenAPIHono(); const app = new OpenAPIHono();
@@ -85,7 +85,7 @@ setTimeout(() => {
// if zechetti plc is wanted we will connect // if zechetti plc is wanted we will connect
setTimeout(() => { setTimeout(() => {
if (zechetti[0]?.value === "1") { if (zechetti[0]?.value === "1") {
zechitti1Connect(); zechettiConnect();
} }
}, 3 * 1000); }, 3 * 1000);

View File

@@ -0,0 +1,155 @@
import { ControllerManager } from "st-ethernet-ip";
import { getMac } from "./getMachineId.js";
import { format } from "date-fns-tz";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { getCurrentLabel } from "../../sqlServer/querys/ocp/getLabel.js";
import { query } from "../../sqlServer/prodSqlServer.js";
import { createLog } from "../../logger/logger.js";
export const createPlcMonitor = (config: any) => {
let cm: any;
let controllers: any = {};
let stats: any = {};
let isRunning = false;
const nowISO = () => {
return new Date().toISOString();
};
const start = () => {
if (isRunning) return;
cm = new ControllerManager();
config.controllers.forEach((cfg: any) => {
const plc: any = cm.addController(
cfg.ip,
cfg.slot,
cfg.rpi,
true,
cfg.retrySP || 3000
);
plc.connect();
controllers[cfg.id] = plc;
// initialize stats
stats[cfg.id] = {
id: cfg.id,
ip: cfg.ip,
slot: cfg.slot,
scanRate: cfg.rpi,
connected: false,
lastConnectedAt: null,
lastDisconnectedAt: null,
reconnectCount: 0,
};
// Add tags
cfg.tags.forEach((tag: any) => plc.addTag(tag));
// Events
plc.on("Connected", () => {
const s = stats[cfg.id];
s.connected = true;
s.lastConnectedAt = nowISO();
if (s.lastDisconnectedAt) {
s.reconnectCount++;
}
console.log(`[${cfg.id}] Connected @ ${cfg.ip}:${cfg.slot}`);
});
plc.on("Disconnected", () => {
const s = stats[cfg.id];
s.connected = false;
s.lastDisconnectedAt = nowISO();
console.log(`[${cfg.id}] Disconnected`);
});
plc.on("error", (err: any) => {
console.error(`[${cfg.id}] Error:`, err.message);
});
plc.on("TagChanged", async (tag: any, prevVal: any) => {
if (tag.value !== 0) {
const time = nowISO();
if (tag.value === 0) return;
setTimeout(async () => {
if (tag.value === 0) return;
const macId = await getMac(tag.value);
console.log(macId);
const { data, error } = (await tryCatch(
query(
getCurrentLabel
.replace(
"[macId]",
macId[0]?.HumanReadableId
)
.replace(
"[time]",
format(time, "yyyy-MM-dd HH:mm")
),
"Current label data"
)
)) as any;
createLog(
"info",
"zechettii",
"zechettii",
`${format(time, "yyyy-MM-dd HH:mm")} [${cfg.id}] ${
tag.name
}: ${prevVal} -> ${
tag.value
}, the running number is ${
error ? null : data.data[0]?.LfdNr
}}`
);
}, 1000);
}
});
});
isRunning = true;
};
const stop = () => {
if (!isRunning) return;
Object.values(controllers).forEach((plc: any) => {
try {
plc.disconnect();
} catch {}
});
controllers = {};
cm = null;
isRunning = false;
console.log("Monitor stopped");
};
const restart = () => {
console.log("Restarting the plc(s)");
stop();
new Promise((resolve) => setTimeout(resolve, 1500));
start();
};
const status = () => {
const result: any = {};
for (const [id, s] of Object.entries(stats)) {
let s: any;
let uptimeMs = null,
downtimeMs = null;
if (s.connected && s.lastConnectedAt) {
uptimeMs = Date.now() - new Date(s.lastConnectedAt).getTime();
} else if (!s.connected && s.lastDisconnectedAt) {
downtimeMs =
Date.now() - new Date(s.lastDisconnectedAt).getTime();
}
result[id] = { ...s, uptimeMs, downtimeMs };
}
return result;
};
return { start, stop, restart, status };
};