diff --git a/frontend/src/components/logistics/siloAdjustments/AttachSilo.tsx b/frontend/src/components/logistics/siloAdjustments/AttachSilo.tsx index 564a7e3..63dd35a 100644 --- a/frontend/src/components/logistics/siloAdjustments/AttachSilo.tsx +++ b/frontend/src/components/logistics/siloAdjustments/AttachSilo.tsx @@ -40,7 +40,6 @@ export function AttachSilo(props: any) { machineId: "", }, onSubmit: async ({ value }) => { - console.log(value); try { const res = await axios.post( "/api/logistics/attachsilo", diff --git a/server/services/ocp/controller/specialProcesses/zechettis/zechetti1.ts b/server/services/ocp/controller/specialProcesses/zechettis/zechetti1.ts new file mode 100644 index 0000000..b541af8 --- /dev/null +++ b/server/services/ocp/controller/specialProcesses/zechettis/zechetti1.ts @@ -0,0 +1,177 @@ +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); + } +} diff --git a/server/services/ocp/ocpService.ts b/server/services/ocp/ocpService.ts index 0cc18ac..c895e2b 100644 --- a/server/services/ocp/ocpService.ts +++ b/server/services/ocp/ocpService.ts @@ -25,6 +25,7 @@ import bookInLabel from "./routes/labeling/bookIn.js"; import labelRatio from "./routes/labeling/getLabelRatio.js"; import resetRatio from "./routes/labeling/resetLabelRatio.js"; import materialTransferLot from "./routes/materials/lotTransfer.js"; +import { zechitti1Connect } from "./controller/specialProcesses/zechettis/zechetti1.js"; const app = new OpenAPIHono(); @@ -69,6 +70,7 @@ app.all("/ocp/*", (c) => { */ const dycoActive = setting.filter((n) => n.name == "dycoConnect"); const ocpActive = setting.filter((n) => n.name === "ocpActive"); +const zechetti = setting.filter((n) => n.name == "zechetti"); // run the printer update on restart just to keep everything good // do the intnal connection to the dyco @@ -78,6 +80,13 @@ setTimeout(() => { } }, 3 * 1000); +// if zechetti plc is wanted we will connect +setTimeout(() => { + if (zechetti[0]?.value === "1") { + zechitti1Connect(); + } +}, 3 * 1000); + // check for printers being assigned setInterval(() => { if (ocpActive[0]?.value === "1") {