feat(lstv2 move): moved lstv2 into this app to keep them combined and easier to maintain

This commit is contained in:
2025-09-19 22:22:05 -05:00
parent caf2315191
commit e4477402ad
847 changed files with 165801 additions and 0 deletions

View File

@@ -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.",
};
}
};

View File

@@ -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
*/

View File

@@ -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" });
}
};

View File

@@ -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. :)`,
};
};