feat(lstv2 move): moved lstv2 into this app to keep them combined and easier to maintain
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
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";
|
||||
|
||||
const st = 5;
|
||||
const sm = 55;
|
||||
const et = 6;
|
||||
const em = 5;
|
||||
|
||||
export const billingCheck = async () => {
|
||||
const now = new Date();
|
||||
const startTime = new Date();
|
||||
const endTime = new Date();
|
||||
|
||||
let isOutsideBilling = false;
|
||||
const { data, error } = await tryCatch(db.select().from(settings));
|
||||
if (error) {
|
||||
return { success: false, message: "Error in getting settings." };
|
||||
}
|
||||
const plant = data.filter((n) => n.name === "plantToken");
|
||||
// set everything up
|
||||
startTime.setHours(st, sm, 0, 0);
|
||||
endTime.setHours(et, em, 0, 0);
|
||||
|
||||
if (plant[0].value === "usflo1") {
|
||||
if (now >= startTime && now <= endTime) {
|
||||
createLog(
|
||||
"warn",
|
||||
"specialProcess",
|
||||
"ocp",
|
||||
`You are inside the billing window no labels will print! please wait`
|
||||
);
|
||||
isOutsideBilling = true;
|
||||
} else {
|
||||
createLog(
|
||||
"info",
|
||||
"specialProcess",
|
||||
"ocp",
|
||||
"Out side billing window ok to print"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
createLog(
|
||||
"debug",
|
||||
"specialProcess",
|
||||
"ocp",
|
||||
"This plant dose not check for billing"
|
||||
);
|
||||
}
|
||||
|
||||
return isOutsideBilling;
|
||||
};
|
||||
@@ -0,0 +1,147 @@
|
||||
import { createLog } from "../../../../logger/logger.js";
|
||||
import { query } from "../../../../sqlServer/prodSqlServer.js";
|
||||
|
||||
export const dualPrintingProcess = async (lotInfo: any) => {
|
||||
// currently we will only allow for 2 printers to be linked only crazy people want more than 2
|
||||
createLog(
|
||||
"info",
|
||||
"ocp",
|
||||
"ocp",
|
||||
"Dual printing running logic here to see what to print"
|
||||
);
|
||||
// each check
|
||||
let lastPrinted;
|
||||
let firstLine;
|
||||
let secondLine;
|
||||
|
||||
// this query checks the last line to print a label
|
||||
const printedQuery = `SELECT TOP(1) IdProdPlanung,
|
||||
IdArtikelvarianten,
|
||||
IdMaschine,
|
||||
LfdNr,
|
||||
ArtikelVariantenBez,
|
||||
Add_User,
|
||||
Add_Date,
|
||||
Upd_User,
|
||||
Upd_Date,
|
||||
IdProdBereich
|
||||
FROM AlplaPROD_test1.dbo.T_EtikettenGedruckt (nolock)
|
||||
where IdMaschine in (${lotInfo[0].machineID},${lotInfo[1].machineID}) order by Add_Date desc`;
|
||||
|
||||
const fisrtLineDT = `SELECT top(1) IdMaschine,
|
||||
case when Endzeit ='1900-01-01 00:00:00.000' and DATEDIFF(MINUTE, Startzeit, GETDATE()) >= 3 Then 1 else 0 end as 'LineCheck'
|
||||
FROM AlplaPROD_test1.dbo.T_HistoryStillstandsereignis (nolock) where IdMaschine = ${lotInfo[0].machineID} order by Add_Date desc`;
|
||||
|
||||
const secondLineDT = `SELECT top(1) IdMaschine,
|
||||
case when Endzeit ='1900-01-01 00:00:00.000' and DATEDIFF(MINUTE, Startzeit, GETDATE()) >= 3 Then 1 else 0 end as 'LineCheck'
|
||||
FROM AlplaPROD_test1.dbo.T_HistoryStillstandsereignis (nolock) where IdMaschine = ${lotInfo[1].machineID} order by Add_Date desc`;
|
||||
|
||||
try {
|
||||
// get what was last printed
|
||||
const result: any = await query(printedQuery, "Last Printed Query");
|
||||
lastPrinted = result.data[0].IdMaschine;
|
||||
} catch (err) {
|
||||
createLog(
|
||||
"error",
|
||||
"ocp",
|
||||
"ocp",
|
||||
`Error: getting last printed querty: ${err}`
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
// get if if running or down
|
||||
const first: any = await query(fisrtLineDT, "First line DT Check");
|
||||
firstLine = first.data[0].LineCheck;
|
||||
} catch (err) {
|
||||
createLog(
|
||||
"error",
|
||||
"ocp",
|
||||
"ocp",
|
||||
`Error: with getting ${lotInfo[0].machineID} data query: ${err}`
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const second: any = await query(secondLineDT, "Second line DT Check");
|
||||
secondLine = second.data[0].LineCheck;
|
||||
} catch (err) {
|
||||
createLog(
|
||||
"error",
|
||||
"ocp",
|
||||
"ocp",
|
||||
`Error: with getting ${lotInfo[1].machineID} data query: ${err}`
|
||||
);
|
||||
}
|
||||
|
||||
// first check if both are up and running
|
||||
if (firstLine === 0 && secondLine === 0) {
|
||||
createLog("info", "ocp", "ocp", "Both lines are up");
|
||||
// what line last printed
|
||||
if (lastPrinted === lotInfo[0].machineID) {
|
||||
// IE 7 then print 8, usslc was the main example for all of this
|
||||
let whatToPrint = lotInfo.filter(
|
||||
(m: any) => m.machineID === lotInfo[1].machineID
|
||||
);
|
||||
// send to label
|
||||
createLog(
|
||||
"info",
|
||||
"ocp",
|
||||
"ocp",
|
||||
`Printing label for ${whatToPrint[0].MachineDescription}`
|
||||
);
|
||||
return whatToPrint;
|
||||
}
|
||||
|
||||
if (lastPrinted === lotInfo[1].machineID) {
|
||||
// IE 8 then print 7, usslc was the main example for all of this
|
||||
let whatToPrint = lotInfo.filter(
|
||||
(m: any) => m.machineID === lotInfo[0].machineID
|
||||
);
|
||||
// send to label
|
||||
createLog(
|
||||
"info",
|
||||
"ocp",
|
||||
"ocp",
|
||||
`Printing label for ${whatToPrint[0].MachineDescription}`
|
||||
);
|
||||
return whatToPrint;
|
||||
}
|
||||
}
|
||||
|
||||
// as we are only allowing 2 lines if one is down the other must be up... still going to conditional it to be sure
|
||||
createLog(
|
||||
"info",
|
||||
"ocp",
|
||||
"ocp",
|
||||
"Looking at what line is down and printing the other one!"
|
||||
);
|
||||
if (firstLine === 1 && secondLine === 0) {
|
||||
// print the other line
|
||||
let whatToPrint = lotInfo.filter(
|
||||
(m: any) => m.machineID === lotInfo[1].machineID
|
||||
);
|
||||
|
||||
// send to label
|
||||
createLog(
|
||||
"info",
|
||||
"ocp",
|
||||
"ocp",
|
||||
`Printing label for ${whatToPrint.MachineDescription}`
|
||||
);
|
||||
return whatToPrint;
|
||||
} else if (firstLine === 0 && secondLine === 1) {
|
||||
// print the other line
|
||||
let whatToPrint = lotInfo.filter(
|
||||
(m: any) => m.machineID === lotInfo[0].machineID
|
||||
);
|
||||
// send to label
|
||||
createLog(
|
||||
"info",
|
||||
"ocp",
|
||||
"ocp",
|
||||
`Printing label for ${whatToPrint.MachineDescription}`
|
||||
);
|
||||
return whatToPrint;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
import { Controller, Tag } from "st-ethernet-ip";
|
||||
import { createLog } from "../../../../logger/logger.js";
|
||||
import { labelerTagRead } from "./plcTags/labelerTag.js";
|
||||
import { palletSendTag } from "./plcTags/palletSendTag.js";
|
||||
import { strapperFaults } from "./plcTags/strapperFault.js";
|
||||
|
||||
let PLC = new Controller();
|
||||
let isDycoRunning = false;
|
||||
|
||||
// PLC address
|
||||
let plcAddress = "10.44.5.4";
|
||||
let isReading = false;
|
||||
// Initialize the interval variable outside the function
|
||||
let plcCycle: any;
|
||||
let plcInterval = 500;
|
||||
|
||||
// Create Tag Instances
|
||||
const labelerTag: any = new Tag("labeler.line_info");
|
||||
const palletSend = new Tag("Zone_6.Ready_to_Send");
|
||||
const strapperError = new Tag("Zone_3.Strapper_Faulted");
|
||||
|
||||
export const dycoConnect = async () => {
|
||||
// if we crash or start over reset the timers so we dont get duplicates
|
||||
clearInterval(plcCycle);
|
||||
if (isDycoRunning)
|
||||
return { success: false, message: "Dyco is already connected." };
|
||||
|
||||
// Remove all listeners before adding a new one to prevent memory leaks
|
||||
PLC.removeAllListeners("error");
|
||||
|
||||
try {
|
||||
await PLC.connect(plcAddress, 0).then(async () => {
|
||||
createLog("info", "dyco", "ocp", `We are connected to the dyco.`);
|
||||
isDycoRunning = true;
|
||||
|
||||
plcCycle = setInterval(async () => {
|
||||
if (isReading) {
|
||||
createLog(
|
||||
"debug",
|
||||
"dyco",
|
||||
"ocp",
|
||||
"Skipping cycle: previous read still in progress."
|
||||
);
|
||||
return;
|
||||
}
|
||||
isReading = true; // Set flag
|
||||
try {
|
||||
await PLC.readTag(labelerTag);
|
||||
await PLC.readTag(palletSend);
|
||||
await PLC.readTag(strapperError);
|
||||
|
||||
// strapper check
|
||||
strapperFaults(strapperError);
|
||||
|
||||
// send the labeler tag data over
|
||||
labelerTagRead(labelerTag);
|
||||
|
||||
// send the end of line check over.
|
||||
palletSendTag(palletSend);
|
||||
} catch (error: any) {
|
||||
createLog(
|
||||
"error",
|
||||
"dyco",
|
||||
"ocp",
|
||||
`Error reading PLC tag: ${error.message}`
|
||||
);
|
||||
} finally {
|
||||
isReading = false; // Reset flag
|
||||
}
|
||||
}, plcInterval);
|
||||
});
|
||||
} catch (error) {
|
||||
createLog(
|
||||
"error",
|
||||
"dyco",
|
||||
"ocp",
|
||||
`There was an error in the dyco: ${error}`
|
||||
);
|
||||
await PLC.disconnect();
|
||||
isDycoRunning = false;
|
||||
}
|
||||
};
|
||||
|
||||
export const closeDyco = async () => {
|
||||
if (!isDycoRunning)
|
||||
return { success: false, message: "Dyco is not connected." };
|
||||
|
||||
console.log(`Closing the connection`);
|
||||
try {
|
||||
await PLC.disconnect();
|
||||
isDycoRunning = false;
|
||||
return {
|
||||
success: true,
|
||||
message: "Dyco Connection is now closed.",
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return {
|
||||
success: false,
|
||||
message: "There was an error closing the dyco connection.",
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,119 @@
|
||||
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 { readTags } from "../../../../../rfid/controller/readTags.js";
|
||||
import { labelingProcess } from "../../../labeling/labelProcess.js";
|
||||
import { autoLabelCreated } from "../../../labeling/labelRatio.js";
|
||||
import { stapperFaulted, strapperFaults } from "./strapperFault.js";
|
||||
|
||||
export let cameraPalletCheck = 20;
|
||||
export let currentPalletCheck = 0;
|
||||
let lastProcessedTimestamp = 0;
|
||||
|
||||
export const labelerTagRead = async (tagData: any) => {
|
||||
/**
|
||||
* Reads the tag data from the Dyco PLC and processes it based on the feedback.
|
||||
*/
|
||||
// Convert tag data buffer to a string and extract numeric values
|
||||
const buffer = Buffer.from(tagData.value);
|
||||
const numericString = buffer.toString("utf8").replace(/[^0-9#]/g, "");
|
||||
|
||||
// Ignore empty or invalid tag data
|
||||
if (numericString === "#") {
|
||||
return;
|
||||
}
|
||||
|
||||
const tagTime = new Date(tagData.state.timestamp).getTime();
|
||||
// get the settings
|
||||
const { data: settingData, error: settingError } = await tryCatch(
|
||||
db.select().from(settings)
|
||||
);
|
||||
|
||||
if (settingError) {
|
||||
createLog(
|
||||
"error",
|
||||
"dyco",
|
||||
"ocp",
|
||||
"There was an error getting the settings"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// check the dyco settings
|
||||
const dycoPrint = settingData.filter((n) => n.name === "dycoPrint");
|
||||
// Only process if this is a new timestamp within the last 5 seconds
|
||||
if (tagTime !== lastProcessedTimestamp && Date.now() - tagTime <= 8000) {
|
||||
lastProcessedTimestamp = tagTime;
|
||||
/**
|
||||
* add logic in to see if this is the first time we run this so we return an error to validate we are in sync.
|
||||
*/
|
||||
createLog(
|
||||
"info",
|
||||
"dyco",
|
||||
"ocp",
|
||||
`Current pallet at the wrapper is: ${numericString}`
|
||||
);
|
||||
if (dycoPrint[0].value === "1") {
|
||||
createLog("info", "dyco", "ocp", "Dyco will be printing the label");
|
||||
// if (!dycoControlCheck) {
|
||||
// createLog(
|
||||
// "error",
|
||||
// "dyco",
|
||||
// "ocp",
|
||||
// `Dyco was switch to be the printer guys. please validate the line is in sync, Current line is ${numericString}`
|
||||
// );
|
||||
// dycoControlCheck = true;
|
||||
// return;
|
||||
// }
|
||||
|
||||
// check the stapper error logic.
|
||||
|
||||
if (stapperFaulted) {
|
||||
createLog("error", "dyco", "ocp", `Strapper is faulted.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if we need to manual check due to 20 pallets.
|
||||
if (currentPalletCheck <= cameraPalletCheck) {
|
||||
currentPalletCheck++;
|
||||
labelingProcess({ line: numericString });
|
||||
createLog(
|
||||
"info",
|
||||
"dyco",
|
||||
"ocp",
|
||||
`You have printed ${currentPalletCheck} pallets, remaining until ${
|
||||
cameraPalletCheck - currentPalletCheck
|
||||
}.`
|
||||
);
|
||||
autoLabelCreated();
|
||||
} else {
|
||||
currentPalletCheck = 0;
|
||||
createLog(
|
||||
"warn",
|
||||
"dyco",
|
||||
"ocp",
|
||||
`You have reached 20 pallets since the last check please validate the labeler is still in sync.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (dycoPrint[0].value === "0") {
|
||||
createLog(
|
||||
"info",
|
||||
"dyco",
|
||||
"ocp",
|
||||
"Rfid system is contorlling the printing"
|
||||
);
|
||||
// trigger the reader so we can get the label from the tag readers.
|
||||
setTimeout(async () => {
|
||||
await readTags("wrapper1");
|
||||
}, 500); // half second delay on this guy
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* setting to switch between rfid and dyco labeling
|
||||
*/
|
||||
@@ -0,0 +1,59 @@
|
||||
import { createLog } from "../../../../../logger/logger.js";
|
||||
import { pickedup } from "../../../../../ocme/controller/pickedup.js";
|
||||
import { triggerScanner } from "../../../../../ocme/controller/triggerCamera.js";
|
||||
import { serverSettings } from "../../../../../server/controller/settings/getSettings.js";
|
||||
|
||||
let lastProcessedTimestamp = 0;
|
||||
|
||||
export const palletSendTag = async (tagData: any) => {
|
||||
/**
|
||||
* Reads the tag data from the Dyco PLC and processes it based on the feedback.
|
||||
* We will only trigger the camera and removal of pending tags
|
||||
*/
|
||||
|
||||
const ocmeActive = serverSettings.filter((n) => n.name === "ocmeService");
|
||||
|
||||
const tagTime = new Date(tagData.state.timestamp).getTime();
|
||||
|
||||
// Only process if this is a new timestamp within the last 5 seconds
|
||||
if (
|
||||
tagTime !== lastProcessedTimestamp &&
|
||||
Date.now() - tagTime <= 5000 &&
|
||||
tagData.value &&
|
||||
ocmeActive[0].value === "1"
|
||||
) {
|
||||
lastProcessedTimestamp = tagTime;
|
||||
//console.log(tagData.state.timestamp);
|
||||
createLog(
|
||||
"info",
|
||||
"dyco",
|
||||
"ocp",
|
||||
`Station 6 is ${tagData.value ? "full" : "empty"}`
|
||||
);
|
||||
|
||||
// take the picture
|
||||
setTimeout(async () => {
|
||||
const scan: any = await triggerScanner();
|
||||
if (!scan.success) {
|
||||
createLog(
|
||||
"error",
|
||||
"dyco",
|
||||
"ocp",
|
||||
`Scanner failed to take a picture trying one more time in 10 seconds`
|
||||
);
|
||||
setTimeout(async () => {
|
||||
await triggerScanner();
|
||||
}, 10 * 1000);
|
||||
}
|
||||
}, 15 * 1000);
|
||||
}
|
||||
|
||||
if (
|
||||
tagTime !== lastProcessedTimestamp &&
|
||||
Date.now() - tagTime <= 5000 &&
|
||||
!tagData.value &&
|
||||
ocmeActive[0].value === "1"
|
||||
) {
|
||||
await pickedup({ runningNr: 1234, all: true, areaFrom: "wrapper_1" });
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,86 @@
|
||||
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";
|
||||
|
||||
// strapper related issues
|
||||
export let strapperActive = false;
|
||||
export let stapperFaulted = false;
|
||||
export let strapperFaultCount = 3; // move to db so we can control it outside the app
|
||||
|
||||
export const strapperFaults = async (tagData: any) => {
|
||||
const { data, error } = await tryCatch(db.select().from(settings));
|
||||
|
||||
// failed to get settings
|
||||
if (error) {
|
||||
return { success: false, message: "Failed to get settings." };
|
||||
}
|
||||
const strapperCheckSetting = data.filter((n) => n.name === "strapperCheck");
|
||||
|
||||
// strapper error is off
|
||||
if (strapperCheckSetting[0]?.value === "0") {
|
||||
return;
|
||||
}
|
||||
|
||||
// strapper error is on
|
||||
if (strapperCheckSetting[0]?.value === "1") {
|
||||
// faulted and still has a check or 2 to go
|
||||
if (stapperFaulted && strapperFaultCount > 0) {
|
||||
createLog(
|
||||
"warn",
|
||||
"dyco",
|
||||
"ocp",
|
||||
`There was a strapper error, remaining pallets to check ${strapperFaultCount}.`
|
||||
);
|
||||
strapperFaultCount = strapperFaultCount - 1;
|
||||
return {
|
||||
success: true,
|
||||
message: `There was a strapper error, remaining pallets to check ${strapperFaultCount}.`,
|
||||
};
|
||||
} else {
|
||||
// no more checks needed clearing everything
|
||||
createLog(
|
||||
"debug",
|
||||
"dyco",
|
||||
"ocp",
|
||||
`Strapper check is active but not faulted, remaining pallets to check ${strapperFaultCount}.`
|
||||
);
|
||||
|
||||
// reset everything
|
||||
stapperFaulted = false;
|
||||
strapperFaultCount = 3; // move to db as well
|
||||
|
||||
return {
|
||||
success: false,
|
||||
message: `Strapper check is active but not faulted, remaining pallets to check ${strapperFaultCount}.`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// strapper was triggered turning on the counter.
|
||||
//console.log(`Strapper fault is ${strapperError.value}`);
|
||||
if (tagData.value && strapperFaultCount > 0) {
|
||||
// strapper faulted we want to start the trigger to force the check
|
||||
if (!stapperFaulted) {
|
||||
createLog(
|
||||
"error",
|
||||
"dyco",
|
||||
"ocp",
|
||||
`Strapper errored triggering, manual checks will be required for the next ${strapperFaultCount}`
|
||||
);
|
||||
stapperFaulted = true;
|
||||
// change move fault count to db....
|
||||
strapperFaultCount = 3;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `Strapper errored triggering, manual checks will be required for the next ${strapperFaultCount}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
message: `Some how we made it here and just going to say we are good. :)`,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
import axios from "axios";
|
||||
import { prodEndpointCreation } from "../../../../../globalUtils/createUrl.js";
|
||||
import { lstAuth } from "../../../../../index.js";
|
||||
import { createLog } from "../../../../logger/logger.js";
|
||||
import { db } from "../../../../../../database/dbclient.js";
|
||||
import { prodlabels } from "../../../../../../database/schema/prodLabels.js";
|
||||
import { eq, sql } from "drizzle-orm";
|
||||
|
||||
export const delieryInhouse = async (data: any) => {
|
||||
// update sscc so we can book in
|
||||
const SSCC = data.SSCC.slice(2);
|
||||
// api url
|
||||
const url = await prodEndpointCreation(
|
||||
"/public/v1.0/Warehousing/InhouseDelivery"
|
||||
);
|
||||
|
||||
// create bookin
|
||||
const newDelivery = {
|
||||
scannerId: 99,
|
||||
sscc: SSCC,
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await axios.post(url, newDelivery, {
|
||||
headers: {
|
||||
Authorization: `Basic ${lstAuth}`,
|
||||
accept: "text/plain",
|
||||
},
|
||||
});
|
||||
|
||||
if (res.data.Result !== 0) {
|
||||
createLog(
|
||||
"error",
|
||||
"labeling",
|
||||
"ocp",
|
||||
`${data.printer?.name}, Error:${res.data.Message}`
|
||||
);
|
||||
//printerUpdate(data.printer, 7, "Error while deliverying inhouse.");
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `${data.printer?.name} had an error while trying to deliver.`,
|
||||
data: res.data,
|
||||
};
|
||||
} // label was just delivered
|
||||
createLog(
|
||||
"info",
|
||||
"labeling",
|
||||
"ocp",
|
||||
`${parseInt(data.SSCC.slice(10, -1))}, was just delivered`
|
||||
);
|
||||
|
||||
try {
|
||||
await db
|
||||
.update(prodlabels)
|
||||
.set({
|
||||
status: "Delivered",
|
||||
upd_date: sql`NOW()`,
|
||||
})
|
||||
.where(
|
||||
eq(prodlabels.runningNr, parseInt(data.SSCC.slice(10, -1)))
|
||||
);
|
||||
} catch (error) {
|
||||
createLog(
|
||||
"error",
|
||||
"labeling",
|
||||
"ocp",
|
||||
`Error updating ${parseInt(data.SSCC.slice(10, -1))} in the DB.`
|
||||
);
|
||||
return {
|
||||
success: true,
|
||||
message: `Error updating ${parseInt(
|
||||
data.SSCC.slice(10, -1)
|
||||
)} in the DB.`,
|
||||
data: error,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
createLog(
|
||||
"error",
|
||||
"labeling",
|
||||
"ocp",
|
||||
`${data.printer.name}, "Error: ${error}`
|
||||
);
|
||||
return {
|
||||
success: true,
|
||||
message: `Error deliverying ${parseInt(data.SSCC.slice(10, -1))}.`,
|
||||
data: error,
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
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 { query } from "../../../../sqlServer/prodSqlServer.js";
|
||||
|
||||
export const firstLotLabel = async (lot: any) => {
|
||||
/*
|
||||
currently this is only requested by slc
|
||||
|
||||
when a lot is finished and not set to over run we will trigger this function to insert data into the custom T_firstLotLabel table.
|
||||
|
||||
in nice label we look for unique id to run the process and then if the add date is older than 7 days we delete it for tracablility purpose.
|
||||
|
||||
we will also only do this for specific customers currently henkel is the requested.
|
||||
*/
|
||||
|
||||
/* work on the server side
|
||||
new table created in the _cus db
|
||||
CREATE TABLE T_firstLotLabel
|
||||
(
|
||||
ID INT IDENTITY(1,1) PRIMARY KEY,
|
||||
printerName varchar(max),
|
||||
add_date datetime
|
||||
-- Add other columns here as needed
|
||||
);
|
||||
the nicelabel trigger to be activated.
|
||||
*/
|
||||
const { data: settingData, error: settingError } = await tryCatch(
|
||||
db.select().from(settings)
|
||||
);
|
||||
|
||||
if (settingError) {
|
||||
return {
|
||||
success: false,
|
||||
message: "There was an error getting the settings.",
|
||||
settingError,
|
||||
};
|
||||
}
|
||||
// get the plantToken
|
||||
const plantToken = settingData.filter((n) => n.name === "plantToken");
|
||||
|
||||
createLog(
|
||||
"info",
|
||||
"ocp",
|
||||
"ocp",
|
||||
`Checking if we can create the first label lot.`
|
||||
);
|
||||
|
||||
if (plantToken[0].value === "usslc1") {
|
||||
const newLabel = `insert into T_firstLotLabel (printerName, add_date) VALUES('${lot.PrinterName}', getdate())`;
|
||||
|
||||
// if (lot.CustomerId === 40) {
|
||||
createLog(
|
||||
"info",
|
||||
"ocp",
|
||||
"ocp",
|
||||
`Creating first lot label for ${lot.MachineDescription}`
|
||||
);
|
||||
await query(newLabel, "newLotLabel");
|
||||
|
||||
createLog(
|
||||
"info",
|
||||
"ocp",
|
||||
"ocp",
|
||||
`Was created for ${lot.MachineDescription}`
|
||||
);
|
||||
//}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user