Compare commits

...

30 Commits

Author SHA1 Message Date
ba3d721940 refactor(ocp): lots of work for rfid and dyco contorl 2025-03-27 21:12:22 -05:00
27d6b6e884 refactor(ocme): added new error in posting where we know when the pallet is not instock 2025-03-27 21:11:42 -05:00
2c8d1fb710 fix(logger): changes to get the most recent verse aged 2025-03-27 21:10:57 -05:00
b5de6445b3 feat(rfid): work on the readers and there functions 2025-03-27 21:08:05 -05:00
f9f68ce969 refactor(logger): changed log level to be in the env file vs hardcoded 2025-03-27 21:07:15 -05:00
0ced135ec3 feat(updater): added in a delete function for the server side 2025-03-27 21:06:45 -05:00
7b1c6e1361 refactor(ocp): finished the dashboard and move logs and labels to a tab style 2025-03-27 21:06:25 -05:00
e3ba45ae13 fix(ocme): fixed to make sure we can always just update a runnning nunmber 2025-03-27 21:05:49 -05:00
ac7859fda3 chore(release): bump build number to 115 2025-03-27 20:21:24 -05:00
fb31ae79d1 chore(release): bump build number to 114 2025-03-27 18:50:04 -05:00
ff1dfdde68 chore(release): bump build number to 113 2025-03-27 18:44:11 -05:00
f0b9bd599a chore(release): bump build number to 112 2025-03-27 18:42:43 -05:00
f3103d8c1a chore(release): bump build number to 111 2025-03-27 18:22:13 -05:00
d557728fa2 chore(release): bump build number to 110 2025-03-27 17:26:30 -05:00
d58cb5286e chore(release): bump build number to 109 2025-03-27 17:03:39 -05:00
7d4733896e chore(release): bump build number to 108 2025-03-27 16:48:14 -05:00
175c7226ed chore(release): bump build number to 107 2025-03-27 15:00:51 -05:00
c32547ceb8 chore(release): bump build number to 106 2025-03-27 14:47:42 -05:00
a01c0566c2 chore(release): bump build number to 105 2025-03-27 14:46:43 -05:00
ca4106945b chore(release): bump build number to 104 2025-03-27 14:45:41 -05:00
1386e0f00f chore(release): bump build number to 103 2025-03-27 14:44:10 -05:00
290f20b86b chore(release): bump build number to 102 2025-03-27 14:33:34 -05:00
52171c87fc chore(release): bump build number to 101 2025-03-27 14:31:22 -05:00
c474536992 chore(release): bump build number to 100 2025-03-27 14:07:33 -05:00
600a989226 chore(release): bump build number to 99 2025-03-27 11:55:35 -05:00
ea7801fccf chore(release): bump build number to 98 2025-03-27 10:59:53 -05:00
c03b61f48a chore(release): bump build number to 97 2025-03-27 10:33:59 -05:00
ca552d5587 chore(release): bump build number to 96 2025-03-27 10:12:23 -05:00
278c5538bc chore(release): bump build number to 95 2025-03-27 09:21:15 -05:00
f39ae0f590 chore(release): bump build number to 94 2025-03-27 09:10:01 -05:00
46 changed files with 2337 additions and 428 deletions

View File

@@ -0,0 +1,4 @@
ALTER TABLE "prodlabels" ALTER COLUMN "add_date" SET DEFAULT now();--> statement-breakpoint
ALTER TABLE "prodlabels" ALTER COLUMN "upd_date" SET DEFAULT now();--> statement-breakpoint
ALTER TABLE "prodlabels" ADD COLUMN "add_user" text DEFAULT 'lst';--> statement-breakpoint
CREATE UNIQUE INDEX "ocme_runningNr" ON "ocmeData" USING btree ("runningNr");

File diff suppressed because it is too large Load Diff

View File

@@ -225,6 +225,13 @@
"when": 1742939306614, "when": 1742939306614,
"tag": "0031_loud_alex_power", "tag": "0031_loud_alex_power",
"breakpoints": true "breakpoints": true
},
{
"idx": 32,
"version": "7",
"when": 1743124980863,
"tag": "0032_tough_iron_monger",
"breakpoints": true
} }
] ]
} }

View File

@@ -1,6 +1,15 @@
import {text, pgTable, numeric, index, timestamp, boolean, uuid, uniqueIndex} from "drizzle-orm/pg-core"; import {
import {createInsertSchema, createSelectSchema} from "drizzle-zod"; text,
import {z} from "zod"; pgTable,
numeric,
index,
timestamp,
boolean,
uuid,
uniqueIndex,
} from "drizzle-orm/pg-core";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import { z } from "zod";
export const ocmeData = pgTable( export const ocmeData = pgTable(
"ocmeData", "ocmeData",
@@ -20,6 +29,7 @@ export const ocmeData = pgTable(
(table) => [ (table) => [
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`), // uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
// uniqueIndex("role_name").on(table.name), // uniqueIndex("role_name").on(table.name),
uniqueIndex("ocme_runningNr").on(table.runningNr),
] ]
); );

View File

@@ -125,7 +125,10 @@ export default function LabelLog() {
{label.runningNr} {label.runningNr}
</TableCell> </TableCell>
<TableCell className="font-medium"> <TableCell className="font-medium">
{format(label.upd_date, "M/d/yyyy hh:mm")} {format(
label?.upd_date.replace("Z", ""),
"M/d/yyyy hh:mm"
)}
</TableCell> </TableCell>
<TableCell className="font-medium"> <TableCell className="font-medium">
{label.status} {label.status}

View File

@@ -70,8 +70,6 @@ export default function Lots() {
const { settings } = useSettingStore(); const { settings } = useSettingStore();
const server = settings.filter((n) => n.name === "server")[0]?.value || ""; const server = settings.filter((n) => n.name === "server")[0]?.value || "";
console.log(data);
const roles = ["admin", "manager", "operator"]; const roles = ["admin", "manager", "operator"];
if (user && roles.includes(user.role)) { if (user && roles.includes(user.role)) {
@@ -234,9 +232,7 @@ export default function Lots() {
server === "localhost" ? ( server === "localhost" ? (
<> <>
<TableCell className="flex justify-center"> <TableCell className="flex justify-center">
<ManualPrintForm <ManualPrintForm />
lot={lot}
/>
</TableCell> </TableCell>
</> </>
) : ( ) : (

View File

@@ -1,4 +1,4 @@
import {Button} from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { import {
Dialog, Dialog,
DialogContent, DialogContent,
@@ -8,8 +8,8 @@ import {
DialogTitle, DialogTitle,
DialogTrigger, DialogTrigger,
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import {Input} from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import {Label} from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { import {
Select, Select,
SelectContent, SelectContent,
@@ -19,81 +19,81 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import {Textarea} from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
import {useSessionStore} from "@/lib/store/sessionStore"; import { useSettingStore } from "@/lib/store/useSettings";
import {useSettingStore} from "@/lib/store/useSettings";
import {LotType} from "@/types/lots";
import axios from "axios"; import axios from "axios";
import {Tag} from "lucide-react"; import { Tag } from "lucide-react";
import {useState} from "react"; import { useState } from "react";
import {Controller, useForm} from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import {toast} from "sonner"; import { toast } from "sonner";
import {manualPrintLabels} from "./ManualPrintLabel";
const printReason = [ const printReason = [
{key: "printerIssue", label: "Printer Related"}, { key: "printerIssue", label: "Printer Related" },
{key: "strapper", label: "Strapper Error"}, { key: "missingRfidTag", label: "Missing or incorrect tag" },
{key: "manualCheck", label: "20th pallet check"}, { key: "strapper", label: "Strapper Error" },
{key: "outOfSync", label: "Labeler Out of Sync"}, { key: "manualCheck", label: "20th pallet check" },
{ key: "outOfSync", label: "Labeler Out of Sync" },
]; ];
export default function ManualPrintForm({lot}: {lot: LotType}) { export default function ManualPrintForm() {
const {user} = useSessionStore();
const token = localStorage.getItem("auth_token"); const token = localStorage.getItem("auth_token");
const {settings} = useSettingStore(); const { settings } = useSettingStore();
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const server = settings.filter((n) => n.name === "server")[0]?.value; const server = settings.filter((n) => n.name === "server")[0]?.value;
// const serverPort = settings.filter((n) => n.name === "serverPort")[0]?.value; // const serverPort = settings.filter((n) => n.name === "serverPort")[0]?.value;
// const serverUrl = `http://${server}:${serverPort}`; // const serverUrl = `http://${server}:${serverPort}`;
// what is the dyco set to? rfid or dyco
const dyco = settings.filter((n) => n.name === "dycoPrint");
const { const {
register, register,
handleSubmit, handleSubmit,
//watch, //watch,
formState: {errors}, formState: { errors },
reset, reset,
control, control,
} = useForm(); } = useForm();
const handlePrintLabel = async (lot: LotType) => { const handleManualPrintLog = async (logData: any) => {
//console.log(lot);
const labels: any = await manualPrintLabels(lot, user);
if (labels.success) {
toast.success(labels.message);
} else {
toast.error(labels.message);
}
};
const handleManualPrintLog = async (logData: any, lot: LotType) => {
// toast.success(`A new label was sent to printer: ${lot.PrinterName} for line ${lot.MachineDescription} `); // toast.success(`A new label was sent to printer: ${lot.PrinterName} for line ${lot.MachineDescription} `);
const logdataUrl = `/api/ocp/manualLabelLog`; const logdataUrl = `/api/ocp/manuallabellog`;
axios axios
.post(logdataUrl, logData, {headers: {Authorization: `Bearer ${token}`}}) .post(logdataUrl, logData, {
.then((d) => { headers: { Authorization: `Bearer ${token}` },
//console.log(d); })
toast.success(d.data.message); .then((d) => {
handlePrintLabel(lot); console.log(d);
reset(); if (d.data.success) {
}) toast.success(d.data.message);
.catch((e) => { } else {
if (e.response.status === 500) { toast.error(d.data.message);
toast.error(`Internal Server error please try again.`); }
return {sucess: false}; reset();
} setOpen(false);
})
.catch((e) => {
if (e.response.status === 500) {
toast.error(`Internal Server error please try again.`);
return { sucess: false };
}
if (e.response.status === 401) { if (e.response.status === 401) {
//console.log(e.response); //console.log(e.response);
toast.error(`You are not authorized to do this.`); toast.error(`You are not authorized to do this.`);
return {sucess: false}; return { sucess: false };
} }
}); });
}; };
const onSubmit = (data: any) => { const onSubmit = (data: any) => {
console.log(data); //console.log(data);
handleManualPrintLog(data, lot); handleManualPrintLog(data);
};
const closeForm = () => {
reset();
setOpen(false);
}; };
return ( return (
<Dialog <Dialog
@@ -117,12 +117,14 @@ export default function ManualPrintForm({lot}: {lot: LotType}) {
<DialogHeader> <DialogHeader>
<DialogTitle>Edit profile</DialogTitle> <DialogTitle>Edit profile</DialogTitle>
<DialogDescription> <DialogDescription>
Make changes to your profile here. Click save when you're done. Make changes to your profile here. Click save when
you're done.
</DialogDescription> </DialogDescription>
</DialogHeader> </DialogHeader>
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
<p> <p>
To manually print a label you must complete all the required fields below. To manually print a label you must complete all the
required fields below.
<br /> <br />
If you clicked this in error just click close If you clicked this in error just click close
</p> </p>
@@ -133,7 +135,7 @@ export default function ManualPrintForm({lot}: {lot: LotType}) {
name="printReason" name="printReason"
defaultValue={""} defaultValue={""}
render={({ render={({
field: {onChange}, field: { onChange },
fieldState: {}, fieldState: {},
//formState, //formState,
}) => ( }) => (
@@ -143,35 +145,46 @@ export default function ManualPrintForm({lot}: {lot: LotType}) {
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectGroup> <SelectGroup>
<SelectLabel>Print Reasons</SelectLabel> <SelectLabel>
{printReason.map((printReason: any) => ( Print Reasons
<SelectItem value={printReason.key}>{printReason.label}</SelectItem> </SelectLabel>
))} {printReason.map(
(printReason: any) => (
<SelectItem
value={printReason.key}
>
{printReason.label}
</SelectItem>
)
)}
</SelectGroup> </SelectGroup>
</SelectContent> </SelectContent>
</Select> </Select>
)} )}
/> />
) : ( ) : (
<div> <div className="m-2">
<Label htmlFor="printRason" className="m-1"> <Label htmlFor="printRason" className="m-1">
Why are you manually printing? Why are you manually printing?
</Label> </Label>
<Input <Input
type="text" type="text"
className={errors.printReason ? "border-red-500" : ""} className={
errors.printReason ? "border-red-500" : ""
}
aria-invalid={!!errors.printReason} aria-invalid={!!errors.printReason}
{...register("printReason", { {...register("printReason", {
required: true, required: true,
minLength: { minLength: {
value: 5, value: 5,
message: "To short of a reason please try again!", message:
"To short of a reason please try again!",
}, },
})} })}
/> />
</div> </div>
)} )}
<div> <div className="m-2">
<Label htmlFor="line" className="m-1"> <Label htmlFor="line" className="m-1">
"What is the line number you are printing?" "What is the line number you are printing?"
</Label> </Label>
@@ -180,11 +193,11 @@ export default function ManualPrintForm({lot}: {lot: LotType}) {
type="number" type="number"
className={errors.line ? "border-red-500" : ""} className={errors.line ? "border-red-500" : ""}
aria-invalid={!!errors.line} aria-invalid={!!errors.line}
{...register("line", {required: true})} {...register("line", { required: true })}
/> />
</div> </div>
<div> <div className="m-2">
<Label htmlFor="initials" className="m-1"> <Label htmlFor="initials" className="m-1">
Enter intials Enter intials
</Label> </Label>
@@ -192,23 +205,55 @@ export default function ManualPrintForm({lot}: {lot: LotType}) {
//variant="underlined" //variant="underlined"
//label="Enter intials" //label="Enter intials"
{...register("initials", {required: true})} {...register("initials", { required: true })}
/>
</div>
<hr />
{dyco[0].value === "0" && (
<div>
<p>Enter the missing tag number.</p>
<hr />
<Label htmlFor="rfidTag" className="m-1">
Enter the tag number only Example
ALPLA000002541. only enter 2541
</Label>
<Input
type="text"
className={
errors.printReason ? "border-red-500" : ""
}
aria-invalid={!!errors.printReason}
{...register("rfidTag", {
required: true,
minLength: {
value: 1,
message: "Tag number is to short!",
},
})}
/>
</div>
)}
<div className="m-2">
<Textarea
//label="Comments"
placeholder="add more info as needed."
{...register("additionalComments")}
/> />
</div> </div>
<Textarea
//label="Comments"
placeholder="add more info as needed."
{...register("additionalComments")}
/>
<DialogFooter> <DialogFooter>
<Button color="danger" variant="default" onClick={() => setOpen(!open)}> <div className="mt-3">
Close <Button
</Button> color="danger"
<Button color="primary" type="submit"> variant="default"
Print onClick={closeForm}
</Button> >
Close
</Button>
<Button color="primary" type="submit">
Print
</Button>
</div>
</DialogFooter> </DialogFooter>
</form> </form>
</DialogContent> </DialogContent>

View File

@@ -1,15 +1,15 @@
import {LotType} from "@/types/lots"; import { LotType } from "@/types/lots";
import axios from "axios"; import axios from "axios";
export const manualPrintLabels = async (lot: LotType, user: any) => { export const manualPrintLabels = async (lot: LotType, user: any) => {
//console.log(lot); //console.log(lot);
const labelUrl = `/ocp/manualPrintAndFollow`; const labelUrl = `/api/ocp/manualprintandfollow`;
try { try {
const res = await axios.post( const res = await axios.post(
labelUrl, labelUrl,
{line: lot.MachineLocation, printerName: lot.PrinterName}, { line: lot.MachineLocation, printerName: lot.PrinterName },
{headers: {Authorization: `Basic ${user?.prod}`}} { headers: { Authorization: `Basic ${user?.prod}` } }
); );
if (res.data.success) { if (res.data.success) {
@@ -19,7 +19,7 @@ export const manualPrintLabels = async (lot: LotType, user: any) => {
}; };
} else { } else {
return { return {
success: true, success: false,
message: `Line ${lot.MachineDescription} encountered an error printing labels: ${res.data.message}`, message: `Line ${lot.MachineDescription} encountered an error printing labels: ${res.data.message}`,
}; };
} }

View File

@@ -1,5 +1,154 @@
import {LstCard} from "@/components/extendedUI/LstCard"; import { LstCard } from "@/components/extendedUI/LstCard";
import { Button } from "@/components/ui/button";
import { Skeleton } from "@/components/ui/skeleton";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { getOcpLogs } from "@/utils/querys/production/ocpLogs";
import { useQuery } from "@tanstack/react-query";
import axios from "axios";
import { format } from "date-fns";
import { Trash } from "lucide-react";
import { toast } from "sonner";
const labelLogs = [
{ key: "message", label: "Error Message" },
{ key: "created_at", label: "ErrorDat" },
{ key: "clear", label: "Clear" },
//{key: "reprint", label: "Reprint"}, // removing the reprint button for now until repritning is working as intended
];
export default function OcpLogs() { export default function OcpLogs() {
return <LstCard className="m-2 p-2">Ocp Logs</LstCard>; const { data, isError, isLoading } = useQuery(getOcpLogs("4"));
const clearLog = async (log: any) => {
try {
const res = await axios.patch(`/api/logger/logs/${log.log_id}`);
if (res.data.success) {
toast.success(`Log message: ${log.message}, was just cleared`);
} else {
console.log(res);
toast.error(`There was an error clearing the message.`);
}
} catch (error) {
toast.error(`There was an error trying to clearing the message.`);
}
};
const logData = data ? data : [];
if (isError) {
return (
<div className="m-2 p-2 min-h-2/5">
<LstCard>
<p className="text-center">Labels for the last 2 hours</p>
<Table>
<TableHeader>
<TableRow>
{labelLogs.map((l) => (
<TableHead key={l.key}>{l.label}</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{Array(7)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</LstCard>
</div>
);
}
return (
<LstCard className="m-2 p-2 min-h-2/5">
<p className="text-center">Labels for the last 2 hours</p>
<Table>
<TableHeader>
<TableRow>
{labelLogs.map((l) => (
<TableHead key={l.key}>{l.label}</TableHead>
))}
</TableRow>
</TableHeader>
{isLoading ? (
<>
<TableBody>
{Array(7)
.fill(0)
.map((_, i) => (
<TableRow key={i}>
<TableCell className="font-medium">
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
<TableCell>
<Skeleton className="h-4" />
</TableCell>
</TableRow>
))}
</TableBody>
</>
) : (
<TableBody>
{logData.map((label: any) => (
<TableRow key={label.log_id}>
<TableCell className="font-medium max-w-5/6">
<p className="text-balance">
{label.message}
</p>
</TableCell>
<TableCell className="font-medium">
{format(
label?.created_at.replace("Z", ""),
"M/d/yyyy hh:mm"
)}
</TableCell>
<TableCell className="font-medium">
<Button
size="icon"
onClick={() => clearLog(label)}
>
<Trash />
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
)}
</Table>
</LstCard>
);
} }

View File

@@ -4,6 +4,7 @@ import Lots from "./Lots";
import OcpLogs from "./OcpLogs"; import OcpLogs from "./OcpLogs";
import PrinterStatus from "./PrinterStatus"; import PrinterStatus from "./PrinterStatus";
import { useSettingStore } from "@/lib/store/useSettings"; import { useSettingStore } from "@/lib/store/useSettings";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
export default function OCPPage() { export default function OCPPage() {
const { settings } = useSettingStore(); const { settings } = useSettingStore();
@@ -17,13 +18,25 @@ export default function OCPPage() {
<Lots /> <Lots />
</div> </div>
<div className="flex flex-row"> <div className="w-5/6">
<div className="w-1/2"> <Tabs defaultValue="ocplogs" className="w-full">
<LabelLog /> <TabsList className="grid w-full grid-cols-2">
</div> <TabsTrigger value="ocplogs">
<div className="w-1/2"> OcpLogs
<OcpLogs /> </TabsTrigger>
</div> <TabsTrigger value="labels">Labels</TabsTrigger>
</TabsList>
<TabsContent value="ocplogs">
<div className="w-full">
<OcpLogs />
</div>
</TabsContent>
<TabsContent value="labels">
<div className="w-full">
<LabelLog />
</div>
</TabsContent>
</Tabs>
</div> </div>
</div> </div>
<div className="w-1/6 flex flex-col"> <div className="w-1/6 flex flex-col">

View File

@@ -7,7 +7,7 @@ export function getlabels(hours: string) {
queryFn: () => fetchSettings(hours), queryFn: () => fetchSettings(hours),
staleTime: 1000, staleTime: 1000,
//refetchInterval: 2500, refetchInterval: 2 * 2000,
refetchOnWindowFocus: true, refetchOnWindowFocus: true,
}); });
} }

View File

@@ -7,7 +7,7 @@ export function getlots() {
queryFn: () => fetchSettings(), queryFn: () => fetchSettings(),
staleTime: 10 * 1000, staleTime: 10 * 1000,
//refetchInterval: 10 * 1000, refetchInterval: 10 * 1000,
refetchOnWindowFocus: true, refetchOnWindowFocus: true,
}); });
} }

View File

@@ -0,0 +1,22 @@
import { queryOptions } from "@tanstack/react-query";
import axios from "axios";
export function getOcpLogs(hours: string) {
return queryOptions({
queryKey: ["ocpLogs"],
queryFn: () => fetchSettings(hours),
staleTime: 1000,
refetchInterval: 2 * 1000,
refetchOnWindowFocus: true,
});
}
const fetchSettings = async (hours: string) => {
const { data } = await axios.get(
`/api/logger/logs?service=ocp&service=rfid&level=error&level=warn&hours=${hours}`
);
// if we are not localhost ignore the devDir setting.
//const url: string = window.location.host.split(":")[0];
return data.data ?? [];
};

View File

@@ -21,8 +21,8 @@
"deploy": "standard-version --conventional-commits && npm run prodBuild", "deploy": "standard-version --conventional-commits && npm run prodBuild",
"zipServer": "dotenvx run -f .env -- tsx server/scripts/zipUpBuild.ts \"C:\\Users\\matthes01\\Documents\\lstv2\"", "zipServer": "dotenvx run -f .env -- tsx server/scripts/zipUpBuild.ts \"C:\\Users\\matthes01\\Documents\\lstv2\"",
"v1Build": "cd C:\\Users\\matthes01\\Documents\\logisticsSupportTool && npm run oldBuilder", "v1Build": "cd C:\\Users\\matthes01\\Documents\\logisticsSupportTool && npm run oldBuilder",
"scriptBuild": "powershell -ExecutionPolicy Bypass -File server/scripts/build.ps1 -dir \"C:\\Users\\matthes01\\Documents\\lstv2-dev\"", "scriptBuild": "powershell -ExecutionPolicy Bypass -File server/scripts/build.ps1 -dir \"C:\\Users\\matthes01\\Documents\\lstv2\"",
"prodBuild": "npm run v1Build && npm run zipServer", "prodBuild": "npm run v1Build && npm run build && npm run zipServer",
"commit": "cz", "commit": "cz",
"prodinstall": "npm i --omit=dev && npm run db:migrate", "prodinstall": "npm i --omit=dev && npm run db:migrate",
"checkupdates": "npx npm-check-updates" "checkupdates": "npx npm-check-updates"
@@ -33,7 +33,7 @@
} }
}, },
"admConfig": { "admConfig": {
"build": 93, "build": 115,
"oldBuild": "backend-0.1.3.zip" "oldBuild": "backend-0.1.3.zip"
}, },
"devDependencies": { "devDependencies": {

View File

@@ -86,7 +86,33 @@ $plantFunness = {
$serverFile = "$($localPath)\$buildFile" $serverFile = "$($localPath)\$buildFile"
$serverPath = "$($localPath)" $serverPath = "$($localPath)"
Write-Host "In the plant we go!!!!!" Write-Host "In the plant we go!!!!!"
######################################################################################
# Removing the fist and frontend folder to make sure we keep them the same and clean.
######################################################################################
try {
# Delete the directories after extraction
Write-Host "Deleting Dist and Frontend..."
$distPath = "$serverPath\dist\"
$frontendPath = "$serverPath\frontend\"
if (Test-Path $distPath) {
Remove-Item -Path $distPath -Recurse -Force
}
if (Test-Path $frontendPath) {
Remove-Item -Path $frontendPath -Recurse -Force
}
} catch {
Write-Host "Error: $_"
exit 1 # Exit with a non-zero code if there's an error
}
Write-Host "Unzipping the folder..." Write-Host "Unzipping the folder..."
$extractedFolderPath = $serverPath $extractedFolderPath = $serverPath

View File

@@ -1,28 +1,41 @@
import {and, eq, inArray, lte, sql} from "drizzle-orm"; import { and, eq, gte, inArray, lte, sql } from "drizzle-orm";
import {db} from "../../../../database/dbclient.js"; import { db } from "../../../../database/dbclient.js";
import {logs} from "../../../../database/schema/logs.js"; import { logs } from "../../../../database/schema/logs.js";
import {createLog} from "../logger.js"; import { createLog } from "../logger.js";
export const getLogs = async (data: any) => { export const getLogs = async (data: any) => {
try { try {
// clear all remaining logs ne to info. // clear all remaining logs ne to info.
const checked = data.checked && data.checked[0] === "true" ? true : false || false; const checked =
data.checked && data.checked[0] === "true" ? true : false || false;
const logData = await db const logData = await db
.select() .select()
.from(logs) .from(logs)
.where( .where(
and( and(
lte(logs.created_at, sql.raw(`NOW() - INTERVAL '${data.hours} hours'`)), gte(
inArray(logs.service, data.service), logs.created_at,
inArray(logs.level, data.level), sql.raw(`NOW() - INTERVAL '${data.hours ?? "4"} hours'`)
eq(logs.checked, checked) ),
) inArray(logs.service, data.service),
); inArray(logs.level, data.level),
eq(logs.checked, checked)
)
);
return {success: true, message: "logs returned", data: logData}; return { success: true, message: "logs returned", data: logData };
} catch (error) { } catch (error) {
console.log(error); console.log(error);
createLog("error", "lst", "logger", `There was an error deleteing server logs. ${error}`); createLog(
return {success: false, message: "An error occured while trying to get the logs", error}; "error",
"lst",
"logger",
`There was an error deleteing server logs. ${error}`
);
return {
success: false,
message: "An error occured while trying to get the logs",
error,
};
} }
}; };

View File

@@ -1,6 +1,6 @@
import {pino, type LogFn, type Logger} from "pino"; import { pino, type LogFn, type Logger } from "pino";
export let logLevel = "info"; export let logLevel = process.env.LOGLEVEL || "info";
const transport = pino.transport({ const transport = pino.transport({
targets: [ targets: [
@@ -31,7 +31,7 @@ const log: Logger = pino(
// }, // },
//customLevels: {death: 70}, //customLevels: {death: 70},
// removes data from the logs that we dont want to be shown :D // removes data from the logs that we dont want to be shown :D
redact: {paths: ["email", "password"], remove: true}, redact: { paths: ["email", "password"], remove: true },
}, },
transport transport
); );
@@ -43,8 +43,11 @@ export const createLog = (
message: string message: string
) => { ) => {
if (level in log) { if (level in log) {
log[level]({username, service}, message); log[level]({ username, service }, message);
} else { } else {
log.warn({username, service}, `Invalid log level '${level}', falling back to warn: ${message}`); log.warn(
{ username, service },
`Invalid log level '${level}', falling back to warn: ${message}`
);
} }
}; };

View File

@@ -38,6 +38,13 @@ export const postLabelData = async (data: any) => {
"There was an error getting the labelData" "There was an error getting the labelData"
); );
} }
if (label.length === 0) {
return {
success: false,
message: "The label you scanned dose not exist in stock.",
};
}
const newPost = { const newPost = {
sscc: newData.sscc ? newData.sscc : await createSSCC(newData.runningNr), sscc: newData.sscc ? newData.sscc : await createSSCC(newData.runningNr),
runningNr: newData.runningNr, runningNr: newData.runningNr,
@@ -50,6 +57,7 @@ export const postLabelData = async (data: any) => {
const enterNewData = await db const enterNewData = await db
.insert(ocmeData) .insert(ocmeData)
.values(newPost) .values(newPost)
.onConflictDoUpdate({ target: ocmeData.runningNr, set: newPost })
.returning({ .returning({
sscc: ocmeData.sscc, sscc: ocmeData.sscc,
runningNr: ocmeData.runningNr, runningNr: ocmeData.runningNr,
@@ -69,8 +77,8 @@ export const postLabelData = async (data: any) => {
//console.log(error); //console.log(error);
return { return {
success: false, success: false,
message: "Data was posted to ocme info", message: "Was not posted",
data: [], data: [error],
}; };
} }
}; };

View File

@@ -10,7 +10,9 @@ export const bookInLabel = async (data: any) => {
// update sscc so we can book in // update sscc so we can book in
const SSCC = data.SSCC.slice(2); const SSCC = data.SSCC.slice(2);
// api url // api url
const url = await prodEndpointCreation("public/v1.0/Warehousing/BookIn"); const url = await prodEndpointCreation(
"/public/v1.1/Manufacturing/ProductionControlling/BookIn"
);
// create bookin // create bookin
const newBookin = { const newBookin = {
@@ -26,12 +28,12 @@ export const bookInLabel = async (data: any) => {
}, },
}); });
if (res.data.Result !== 0) { if (res.status != 200) {
createLog( createLog(
"error", "error",
"labeling", "labeling",
"ocp", "ocp",
`${data.printer.name}, Error:${res.data.Message}` `${data.printer[0].name}, Error:${res.data}`
); );
//printerUpdate(data.printer, 7, "Error while booking in."); //printerUpdate(data.printer, 7, "Error while booking in.");
@@ -44,7 +46,7 @@ export const bookInLabel = async (data: any) => {
// update the label. // update the label.
try { try {
await db const booked = await db
.update(prodlabels) .update(prodlabels)
.set({ .set({
status: "Booked in", status: "Booked in",
@@ -52,7 +54,22 @@ export const bookInLabel = async (data: any) => {
}) })
.where( .where(
eq(prodlabels.runningNr, parseInt(data.SSCC.slice(10, -1))) eq(prodlabels.runningNr, parseInt(data.SSCC.slice(10, -1)))
); )
.returning({ runningNr: prodlabels.runningNr });
createLog(
"info",
"labeling",
"ocp",
`${booked[0].runningNr} , was just booked in.`
);
return {
success: true,
message: `${parseInt(
data.SSCC.slice(10, -1)
)}, was just booked in`,
};
} catch (error) { } catch (error) {
createLog( createLog(
"error", "error",
@@ -61,24 +78,12 @@ export const bookInLabel = async (data: any) => {
`Error creating new runningNumber in the DB.` `Error creating new runningNumber in the DB.`
); );
} }
// label was booked in
createLog(
"info",
"labeling",
"ocp",
`${parseInt(data.SSCC.slice(10, -1))}, was just booked in`
);
return {
success: true,
message: `${parseInt(data.SSCC.slice(10, -1))}, was just booked in`,
};
} catch (error) { } catch (error) {
createLog( createLog(
"error", "error",
"labeling", "labeling",
"ocp", "ocp",
`${data.printer.name}, "Error: ${error}` `${data.printer[0].name}, "Error: ${error}`
); );
return { return {
success: false, success: false,

View File

@@ -43,7 +43,7 @@ export const createLabel = async (data: any, userPrinted: any) => {
const plantToken = settingsData.filter((n) => n.name === "plantToken"); const plantToken = settingsData.filter((n) => n.name === "plantToken");
const newLabel = { const newLabel = {
scannerId: 99, scannerId: 99,
lotNr: data.LOT, lotNr: data.lot,
machineId: data.machineID, machineId: data.machineID,
printerId: data.printerID, printerId: data.printerID,
//layoutId: cartonCustomers.includes(data.CustomerId.toString()) ? data.cartonLabel : data.palletLabel, //layoutId: cartonCustomers.includes(data.CustomerId.toString()) ? data.cartonLabel : data.palletLabel,
@@ -87,14 +87,24 @@ export const createLabel = async (data: any, userPrinted: any) => {
let newlabel = res.data; let newlabel = res.data;
try { try {
await db.insert(prodlabels).values({ const insertLabel = await db
printerID: parseInt(printer[0]?.humanReadableId!, 10), .insert(prodlabels)
runningNr: parseInt(newlabel.SSCC.slice(10, -1)), .values({
printerName: printer[0].name.toLowerCase(), printerID: parseInt(printer[0]?.humanReadableId!, 10),
line: data.MachineLocation, runningNr: parseInt(newlabel.SSCC.slice(10, -1)),
status: "printed", printerName: printer[0].name.toLowerCase(),
add_user: userPrinted || "LST_System", line: data.MachineLocation,
}); status: "printed",
add_user: userPrinted || "LST_System",
})
.returning({ runningNr: prodlabels.runningNr });
createLog(
"info",
"labeling",
"ocp",
`${insertLabel[0]?.runningNr} was just inserted into the db.`
);
} catch (error) { } catch (error) {
createLog( createLog(
"error", "error",
@@ -119,7 +129,7 @@ export const createLabel = async (data: any, userPrinted: any) => {
}; };
// check if we can remove labels or not // check if we can remove labels or not
deleteLabels(); //deleteLabels();
return { sucess: true, message: "Label created", data: returnData }; // returning label data to be able to book in if active return { sucess: true, message: "Label created", data: returnData }; // returning label data to be able to book in if active
} catch (error) { } catch (error) {
createLog( createLog(

View File

@@ -1,4 +1,4 @@
import { desc, lte, sql } from "drizzle-orm"; import { desc, gte, lte, sql } from "drizzle-orm";
import { db } from "../../../../../database/dbclient.js"; import { db } from "../../../../../database/dbclient.js";
import { prodlabels } from "../../../../../database/schema/prodLabels.js"; import { prodlabels } from "../../../../../database/schema/prodLabels.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js"; import { tryCatch } from "../../../../globalUtils/tryCatch.js";
@@ -8,7 +8,7 @@ export const getLabels = async (hours: string) => {
.select() .select()
.from(prodlabels) .from(prodlabels)
.where( .where(
lte( gte(
prodlabels.upd_date, prodlabels.upd_date,
sql.raw(`NOW() - INTERVAL '${hours} hours'`) sql.raw(`NOW() - INTERVAL '${hours} hours'`)
) )
@@ -27,6 +27,7 @@ export const getLabels = async (hours: string) => {
return { return {
success: true, success: true,
message: "Current labels order by upd_Date.", message: "Current labels order by upd_Date.",
count: labelInfo.length,
data: labelInfo, data: labelInfo,
}; };
}; };

View File

@@ -50,9 +50,10 @@ export const labelingProcess = async ({
// if we got a line passed over we need to get the machine id from this. // if we got a line passed over we need to get the machine id from this.
if (line) { if (line) {
const macId = await getMac(line); const macId = await getMac(line);
// filter out the lot for the line // filter out the lot for the line
filteredLot = lots.data.filter((l: any) => l.machineId === macId); filteredLot = lots.data.filter(
(l: any) => l.MachineID === macId[0].HumanReadableId
);
if (filteredLot.length === 0) { if (filteredLot.length === 0) {
createLog( createLog(
@@ -160,7 +161,10 @@ export const labelingProcess = async ({
`Main material is not prepaired for lot ${filteredLot[0].lot}` `Main material is not prepaired for lot ${filteredLot[0].lot}`
); );
return; return {
success: false,
message: `Main material is not prepaired for lot ${filteredLot[0].lot}`,
};
} }
// comment only but will check for color // comment only but will check for color
@@ -198,16 +202,19 @@ export const labelingProcess = async ({
"ocp", "ocp",
`Prolink does not match for ${filteredLot[0].MachineDescription}` `Prolink does not match for ${filteredLot[0].MachineDescription}`
); );
return; return {
success: false,
message: `Prolink does not match for ${filteredLot[0].MachineDescription}`,
};
} }
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);
if (!label.success) { // if (!label.success) {
return { sucess: false, message: label.message, data: label.data }; // return { sucess: false, message: label.message, data: label.data };
} // }
// send over to be booked in if we can do it. // send over to be booked in if we can do it.
const bookin = settingData.filter((s) => s.name === "bookin"); const bookin = settingData.filter((s) => s.name === "bookin");

View File

@@ -0,0 +1,52 @@
import { db } from "../../../../../database/dbclient.js";
import { manualPrinting } from "../../../../../database/schema/ocpManualPrint.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { manualTag } from "../../../rfid/controller/tags/manualTag.js";
import { labelingProcess } from "./labelProcess.js";
export const manualPrint = async (manualPrint: any) => {
/**
* add the reason we did a manual print.
*/
const manualPrintData = {
line: manualPrint.line,
printReason: manualPrint.printReason,
initials: manualPrint.initials,
additionalComments: manualPrint?.additionalComments,
add_user: "lst",
};
const { data, error } = await tryCatch(
db.insert(manualPrinting).values(manualPrintData).returning({
line: manualPrinting.line,
printReason: manualPrinting.printReason,
initials: manualPrinting.initials,
additionalComments: manualPrinting?.additionalComments,
add_user: manualPrinting.add_user,
})
);
if (error) {
return {
success: false,
message: "There was an error posting the manualPrintData",
data: error,
};
}
let label = await labelingProcess({ line: manualPrint.line });
if (manualPrint.rfidTag) {
manualTag(
manualPrint.rfidTag,
"wrapper1",
parseInt(label.data.SSCC.slice(10, -1))
);
}
return {
success: true,
message: "Log Entered label will be coming soon.",
data,
};
};

View File

@@ -43,8 +43,6 @@ export const prolinkCheck = async (lot: any) => {
// run the query // run the query
try { try {
const prolink = await query(prolinkQuery, "Prolink Checks"); const prolink = await query(prolinkQuery, "Prolink Checks");
//console.log(lot);
// filter out the lot // filter out the lot
const filterdLot = prolink.filter( const filterdLot = prolink.filter(
(p: any) => p.AlplaLabelOnline === lot (p: any) => p.AlplaLabelOnline === lot

View File

@@ -1,44 +0,0 @@
import { db } from "../../../../database/dbclient.js";
import { manualPrinting } from "../../../../database/schema/ocpManualPrint.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
export const manualPrint = async (manualPrint: any) => {
/**
* add the reason we did a manual print.
*/
const manualPrintData = {
line: manualPrint.line,
printReason: manualPrint.printReason,
initials: manualPrint.initials,
additionalComments: manualPrint?.additionalComments,
add_user: "lst",
};
const { data, error } = await tryCatch(
db
.insert(manualPrinting)
.values(manualPrintData)
.returning({
line: manualPrinting.line,
printReason: manualPrinting.printReason,
initials: manualPrinting.initials,
additionalComments: manualPrinting?.additionalComments,
add_user: manualPrinting.add_user,
})
);
if (error) {
return {
success: false,
message: "There was an error posting the manualPrintData",
data: error,
};
}
return {
success: true,
message: "There was an error posting the manualPrintData",
data,
};
};

View File

@@ -2,13 +2,14 @@ import { Controller, Tag } from "st-ethernet-ip";
import { createLog } from "../../../../logger/logger.js"; import { createLog } from "../../../../logger/logger.js";
import { labelerTagRead } from "./plcTags/labelerTag.js"; import { labelerTagRead } from "./plcTags/labelerTag.js";
import { palletSendTag } from "./plcTags/palletSendTag.js"; import { palletSendTag } from "./plcTags/palletSendTag.js";
import { strapperFaults } from "./plcTags/strapperFault.js";
let PLC = new Controller(); let PLC = new Controller();
let isDycoRunning = false; let isDycoRunning = false;
// PLC address // PLC address
let plcAddress = "10.44.5.4"; let plcAddress = "10.44.5.4";
let isReading = false;
// Initialize the interval variable outside the function // Initialize the interval variable outside the function
let plcCycle: any; let plcCycle: any;
let plcInterval = 500; let plcInterval = 500;
@@ -31,17 +32,42 @@ export const dycoConnect = async () => {
await PLC.connect(plcAddress, 0).then(async () => { await PLC.connect(plcAddress, 0).then(async () => {
createLog("info", "dyco", "ocp", `We are connected to the dyco.`); createLog("info", "dyco", "ocp", `We are connected to the dyco.`);
isDycoRunning = true; isDycoRunning = true;
let buffer = "";
plcCycle = setInterval(async () => { plcCycle = setInterval(async () => {
await PLC.readTag(labelerTag); if (isReading) {
await PLC.readTag(palletSend); createLog(
"warn",
"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);
// send the labeler tag data over // strapper check
labelerTagRead(labelerTag); strapperFaults(strapperError);
// send the end of line check over. // send the labeler tag data over
palletSendTag(palletSend); labelerTagRead(labelerTag);
}, 500);
// 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) { } catch (error) {
createLog( createLog(
@@ -50,6 +76,7 @@ export const dycoConnect = async () => {
"ocp", "ocp",
`There was an error in the dyco: ${error}` `There was an error in the dyco: ${error}`
); );
await PLC.disconnect();
isDycoRunning = false; isDycoRunning = false;
} }
}; };

View File

@@ -4,7 +4,10 @@ import { tryCatch } from "../../../../../../globalUtils/tryCatch.js";
import { createLog } from "../../../../../logger/logger.js"; import { createLog } from "../../../../../logger/logger.js";
import { readTags } from "../../../../../rfid/controller/readTags.js"; import { readTags } from "../../../../../rfid/controller/readTags.js";
import { labelingProcess } from "../../../labeling/labelProcess.js"; import { labelingProcess } from "../../../labeling/labelProcess.js";
import { stapperFaulted, strapperFaults } from "./strapperFault.js";
export let cameraPalletCheck = 20;
export let currentPalletCheck = 0;
let lastProcessedTimestamp = 0; let lastProcessedTimestamp = 0;
export const labelerTagRead = async (tagData: any) => { export const labelerTagRead = async (tagData: any) => {
@@ -41,11 +44,48 @@ export const labelerTagRead = async (tagData: any) => {
// Only process if this is a new timestamp within the last 5 seconds // Only process if this is a new timestamp within the last 5 seconds
if (tagTime !== lastProcessedTimestamp && Date.now() - tagTime <= 5000) { if (tagTime !== lastProcessedTimestamp && Date.now() - tagTime <= 5000) {
lastProcessedTimestamp = tagTime; lastProcessedTimestamp = tagTime;
//console.log(numericString, tagData.state.timestamp); /**
* 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") { if (dycoPrint[0].value === "1") {
createLog("info", "dyco", "ocp", "Dyco will be printing the label"); createLog("info", "dyco", "ocp", "Dyco will be printing the label");
// send over to print. // if (!dycoControlCheck) {
labelingProcess({ line: numericString }); // 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 = currentPalletCheck + 1;
labelingProcess({ line: numericString });
} else {
currentPalletCheck = 0;
createLog(
"error",
"dyco",
"ocp",
`You have reached 20 pallets since the last check please validate the labeler is still in sync.`
);
}
} }
if (dycoPrint[0].value === "0") { if (dycoPrint[0].value === "0") {
@@ -56,7 +96,9 @@ export const labelerTagRead = async (tagData: any) => {
"Rfid system is contorlling the printing" "Rfid system is contorlling the printing"
); );
// trigger the reader so we can get the label from the tag readers. // trigger the reader so we can get the label from the tag readers.
await readTags("wrapper1"); setTimeout(async () => {
await readTags("wrapper1");
}, 2 * 1000);
} }
} }
}; };

View File

@@ -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";
// strapper related issues
export let strapperActive = true;
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));
if (error) {
return { success: false, message: "Failed to get settings." };
}
if (strapperActive) {
// monitor strapper
//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;
}
}
const strapperCheckSetting = data.filter((n) => n.name === "strapperCheck");
if (strapperCheckSetting[0]?.value === "1") {
if (stapperFaulted && strapperFaultCount > 0) {
createLog(
"warn",
"dyco",
"ocp",
`There was a strapper error, remaining pallets to check ${strapperFaultCount}.`
);
strapperFaultCount = strapperFaultCount - 1;
return {
success: false,
message: `There was a strapper error, remaining pallets to check ${strapperFaultCount}.`,
};
} else {
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: true,
message: `Strapper check is active but not faulted, remaining pallets to check ${strapperFaultCount}.`,
};
}
}
};

View File

@@ -1,7 +1,7 @@
import { OpenAPIHono } from "@hono/zod-openapi"; import { OpenAPIHono } from "@hono/zod-openapi";
// routes // routes
import manualLabelLog from "./routes/manualPrintLog.js"; import manualLabelLog from "./routes/labeling/manualPrintLog.js";
import getPrinters from "./routes/printers/getPritners.js"; import getPrinters from "./routes/printers/getPritners.js";
import { db } from "../../../database/dbclient.js"; import { db } from "../../../database/dbclient.js";
import { settings } from "../../../database/schema/settings.js"; import { settings } from "../../../database/schema/settings.js";
@@ -12,6 +12,7 @@ import getLabels from "./routes/labeling/getLabels.js";
import { dycoConnect } from "./controller/specialProcesses/dyco/plcConnection.js"; import { dycoConnect } from "./controller/specialProcesses/dyco/plcConnection.js";
import dycoCon from "./routes/specialProcesses/dyco/connection.js"; import dycoCon from "./routes/specialProcesses/dyco/connection.js";
import dycoClose from "./routes/specialProcesses/dyco/closeConnection.js"; import dycoClose from "./routes/specialProcesses/dyco/closeConnection.js";
import manualprint from "./routes/labeling/manualPrint.js";
const app = new OpenAPIHono(); const app = new OpenAPIHono();
@@ -24,6 +25,7 @@ const routes = [
getLots, getLots,
// labeling // labeling
getLabels, getLabels,
manualprint,
//dyco //dyco
dycoCon, dycoCon,
dycoClose, dycoClose,

View File

@@ -30,6 +30,7 @@ app.openapi(
return c.json({ return c.json({
success: labelData.success, success: labelData.success,
message: labelData.message, message: labelData.message,
count: labelData.count,
data: labelData.data, data: labelData.data,
}); });
} }

View File

@@ -0,0 +1,50 @@
// an external way to creating logs
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { responses } from "../../../../globalUtils/routeDefs/responses.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { labelingProcess } from "../../controller/labeling/labelProcess.js";
const app = new OpenAPIHono({ strict: false });
app.openapi(
createRoute({
tags: ["ocp"],
summary: "Manual print a label by line and printer name",
method: "post",
path: "/manualprintandfollow",
responses: responses(),
}),
async (c) => {
//const hours = c.req.query("hours");
const { data: bodyData, error: bodyError } = await tryCatch(
c.req.json()
);
if (bodyError) {
return c.json({
success: false,
message: "You are missing data",
});
}
const { data: createLabel, error: labelError } = await tryCatch(
labelingProcess({ line: bodyData.line })
);
if (labelError) {
return c.json({
success: false,
message: "There was an error creating the label.",
data: labelError,
});
}
const newLabel: any = createLabel;
return c.json({
success: newLabel.success,
message: newLabel.message,
data: newLabel.data,
});
}
);
export default app;

View File

@@ -1,11 +1,12 @@
// an external way to creating logs // an external way to creating logs
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi"; import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import { apiHit } from "../../../globalUtils/apiHits.js"; import { apiHit } from "../../../../globalUtils/apiHits.js";
import { responses } from "../../../globalUtils/routeDefs/responses.js"; import { responses } from "../../../../globalUtils/routeDefs/responses.js";
import type { User } from "../../../types/users.js"; import type { User } from "../../../../types/users.js";
import { verify } from "hono/jwt"; import { verify } from "hono/jwt";
import { manualPrint } from "../controller/manualLabelLog.js"; import { manualPrint } from "../../controller/labeling/manualLabelLog.js";
import { authMiddleware } from "../../auth/middleware/authMiddleware.js"; import { authMiddleware } from "../../../auth/middleware/authMiddleware.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
const app = new OpenAPIHono({ strict: false }); const app = new OpenAPIHono({ strict: false });
const CreateLog = z.object({ const CreateLog = z.object({
@@ -32,7 +33,17 @@ app.openapi(
responses: responses(), responses: responses(),
}), }),
async (c) => { async (c) => {
const body = await c.req.json(); const { data: body, error } = await tryCatch(c.req.json());
if (error) {
return c.json(
{
success: false,
message: "Missing Data.",
},
400
);
}
apiHit(c, { endpoint: `api/logger/logs/id` }); apiHit(c, { endpoint: `api/logger/logs/id` });
try { try {
//const data = {...body, add_user: user.username}; //const data = {...body, add_user: user.username};

View File

@@ -1,52 +0,0 @@
// an external way to creating logs
import {createRoute, OpenAPIHono, z} from "@hono/zod-openapi";
import {apiHit} from "../../../globalUtils/apiHits.js";
import {responses} from "../../../globalUtils/routeDefs/responses.js";
const app = new OpenAPIHono({strict: false});
const CreateLog = z.object({
line: z.string().openapi({example: "info"}),
initials: z.string().openapi({example: "server"}),
printReason: z.string().openapi({example: "This is a new log posted"}),
additionalComments: z.string().optional().openapi({example: "Some reason why we did this."}),
});
app.openapi(
createRoute({
tags: ["ocp"],
summary: "Prints a label.",
method: "post",
path: "/printlabel",
//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 body = await c.req.json();
apiHit(c, {endpoint: `api/logger/logs/id`});
// const authHeader = c.req.header("Authorization");
// const token = authHeader?.split("Bearer ")[1] || "";
// let user: User;
// try {
// const payload = await verify(token, process.env.JWT_SECRET!);
// user = payload.user as User;
// } catch (error) {
// console.log(error);
// return c.json({message: "Unauthorized"}, 401);
// }
try {
//const data = {...body, add_user: user.username};
return c.json({success: true, message: "Label was printed.", data: []}, 200);
} catch (error) {
return c.json({success: false, message: "There was an error printing a label.", data: error}, 400);
}
}
);
export default app;

View File

@@ -2,6 +2,13 @@
* For a no read we just want to put up a notification to the rfid dashboard stating this reader did not respond with any tag data. * For a no read we just want to put up a notification to the rfid dashboard stating this reader did not respond with any tag data.
*/ */
import { createLog } from "../../logger/logger.js";
export const noRead = async (reader: string) => { export const noRead = async (reader: string) => {
console.log(`${reader} just had a no read please check for a tag and manually trigger a read.`); createLog(
"error",
"rfid",
"rifd",
`${reader} just had a no read please check for a tag and manually trigger a read.`
);
}; };

View File

@@ -29,15 +29,18 @@ export const readTags = async (reader: string) => {
// get the auth token // get the auth token
ip = readers.find((r) => r.reader === reader)?.readerIP as string; ip = readers.find((r) => r.reader === reader)?.readerIP as string;
// start the read
startRead();
// start the read
};
const getReaderToken = async () => {
try { try {
const res = await axios.get(`https://${ip}/cloud/localRestLogin`, { const res = await axios.get(`https://${ip}/cloud/localRestLogin`, {
headers: { Authorization: `Basic ${authData}` }, headers: { Authorization: `Basic ${authData}` },
}); });
token = res.data.message; token = res.data.message;
// start the read
startRead();
} catch (error: any) { } catch (error: any) {
console.log(error);
createLog( createLog(
"error", "error",
"rfid", "rfid",
@@ -45,11 +48,10 @@ export const readTags = async (reader: string) => {
`There was an error Getting the token the read: ${error.response?.data.message}` `There was an error Getting the token the read: ${error.response?.data.message}`
); );
} }
// start the read
}; };
const startRead = async () => { const startRead = async () => {
await getReaderToken();
try { try {
const res = await axios.put( const res = await axios.put(
`https://${ip}/cloud/start`, `https://${ip}/cloud/start`,
@@ -64,12 +66,12 @@ const startRead = async () => {
if (res.status === 200) { if (res.status === 200) {
setTimeout(() => { setTimeout(() => {
stopRead(); stopRead();
}, 5 * 1000); }, 2 * 1000);
} }
// stop after 5 seconds // stop after 5 seconds
} catch (error: any) { } catch (error: any) {
if (error.response.data.code === 3) { if (error.response?.data.code === 3) {
stopRead(); stopRead();
setTimeout(() => { setTimeout(() => {
startRead(); startRead();
@@ -79,11 +81,13 @@ const startRead = async () => {
"error", "error",
"rfid", "rfid",
"rfid", "rfid",
`There was an error Starting the read: ${error.response.data.message}` `There was an error Starting the read: ${error.response?.data.message}`
); );
} }
}; };
const stopRead = async () => {
export const stopRead = async () => {
await getReaderToken();
try { try {
const res = await axios.put( const res = await axios.put(
`https://${ip}/cloud/stop`, `https://${ip}/cloud/stop`,
@@ -97,7 +101,7 @@ const stopRead = async () => {
"error", "error",
"rfid", "rfid",
"rfid", "rfid",
`There was an error Stopping the read: ${error.response.data.message}` `There was an error Stopping the read: ${JSON.stringify(error)}`
); );
} }
}; };

View File

@@ -2,10 +2,10 @@
* While in production we will monitor the readers if we have not gotten a heartbeat in the last 5 min we will send a reboot command along with an email. * While in production we will monitor the readers if we have not gotten a heartbeat in the last 5 min we will send a reboot command along with an email.
*/ */
import {eq, sql} from "drizzle-orm"; import { eq, sql } from "drizzle-orm";
import {db} from "../../../../database/dbclient.js"; import { db } from "../../../../database/dbclient.js";
import {rfidReaders} from "../../../../database/schema/rfidReaders.js"; import { rfidReaders } from "../../../../database/schema/rfidReaders.js";
import {createLog} from "../../logger/logger.js"; import { createLog } from "../../logger/logger.js";
export const newHeartBeat = async (reader: string) => { export const newHeartBeat = async (reader: string) => {
/** /**
@@ -14,14 +14,30 @@ export const newHeartBeat = async (reader: string) => {
try { try {
const heatBeat = await db const heatBeat = await db
.update(rfidReaders) .update(rfidReaders)
.set({lastHeartBeat: sql`NOW()`}) .set({ lastHeartBeat: sql`NOW()` })
.where(eq(rfidReaders.reader, reader)); .where(eq(rfidReaders.reader, reader));
createLog("info", "rfid", "rfid", `${reader} just updated its heatBeat.`); createLog(
return {success: true, message: `${reader} just updated its heatBeat.`}; "debug",
"rfid",
"rfid",
`${reader} just updated its heatBeat.`
);
return {
success: true,
message: `${reader} just updated its heatBeat.`,
};
} catch (error) { } catch (error) {
createLog("error", "rfid", "rfid", `${reader} encountered an error while updating the heatbeat, ${error}`); createLog(
return {success: false, message: `${reader} encountered an error while updating the heatbeat, ${error}`}; "error",
"rfid",
"rfid",
`${reader} encountered an error while updating the heatbeat, ${error}`
);
return {
success: false,
message: `${reader} encountered an error while updating the heatbeat, ${error}`,
};
} }
}; };
@@ -31,14 +47,30 @@ export const badRead = async (reader: string) => {
*/ */
try { try {
const badRead = await db const badRead = await db
.update(rfidReaders) .update(rfidReaders)
.set({lastTrigger: sql`NOW()`, lastTriggerGood: false}) .set({ lastTrigger: sql`NOW()`, lastTriggerGood: false })
.where(eq(rfidReaders.reader, reader)); .where(eq(rfidReaders.reader, reader));
createLog("info", "rfid", "rfid", `${reader} just Triggered a bad read.`); createLog(
return {success: true, message: `${reader} just Triggered a bad read.`}; "info",
"rfid",
"rfid",
`${reader} just Triggered a bad read.`
);
return {
success: true,
message: `${reader} just Triggered a bad read.`,
};
} catch (error) { } catch (error) {
createLog("error", "rfid", "rfid", `${reader} encountered an error while updating the heatbeat, ${error}`); createLog(
return {success: false, message: `${reader} encountered an error while updating the heatbeat, ${error}`}; "error",
"rfid",
"rfid",
`${reader} encountered an error while updating the heatbeat, ${error}`
);
return {
success: false,
message: `${reader} encountered an error while updating the heatbeat, ${error}`,
};
} }
}; };
@@ -48,13 +80,29 @@ export const goodRead = async (reader: string) => {
*/ */
try { try {
const goodRead = await db const goodRead = await db
.update(rfidReaders) .update(rfidReaders)
.set({lastTrigger: sql`NOW()`, lastTriggerGood: true}) .set({ lastTrigger: sql`NOW()`, lastTriggerGood: true })
.where(eq(rfidReaders.reader, reader)); .where(eq(rfidReaders.reader, reader));
createLog("info", "rfid", "rfid", `${reader} just Triggered a good read.`); createLog(
return {success: true, message: `${reader} just Triggered a good read.`}; "info",
"rfid",
"rfid",
`${reader} just Triggered a good read.`
);
return {
success: true,
message: `${reader} just Triggered a good read.`,
};
} catch (error) { } catch (error) {
createLog("error", "rfid", "rfid", `${reader} encountered an error while updating the heatbeat, ${error}`); createLog(
return {success: false, message: `${reader} encountered an error while updating the heatbeat, ${error}`}; "error",
"rfid",
"rfid",
`${reader} encountered an error while updating the heatbeat, ${error}`
);
return {
success: false,
message: `${reader} encountered an error while updating the heatbeat, ${error}`,
};
} }
}; };

View File

@@ -8,6 +8,12 @@ import type { TagData } from "../tagData.js";
import { tagStuff } from "../tags/crudTag.js"; import { tagStuff } from "../tags/crudTag.js";
export const station3Tags = async (tagData: TagData[]) => { export const station3Tags = async (tagData: TagData[]) => {
createLog(
"info",
"rfid",
"rfid",
`${tagData[0].reader} has a ${tagData[0].tag} will post it :)`
);
// make sure we only have one tag or dont update // make sure we only have one tag or dont update
if (tagData.length != 1) { if (tagData.length != 1) {
createLog( createLog(

View File

@@ -8,28 +8,14 @@ import { labelingProcess } from "../../../ocp/controller/labeling/labelProcess.j
import type { TagData } from "../tagData.js"; import type { TagData } from "../tagData.js";
import { tagStuff } from "../tags/crudTag.js"; import { tagStuff } from "../tags/crudTag.js";
import { sendEmail } from "../../../notifications/controller/sendMail.js"; import { sendEmail } from "../../../notifications/controller/sendMail.js";
import { tryCatch } from "../../../../globalUtils/tryCatch.js";
import { db } from "../../../../../database/dbclient.js";
import { rfidTags } from "../../../../../database/schema/rfidTags.js";
import { eq } from "drizzle-orm";
export const wrapperStuff = async (tagData: TagData[]) => { export const wrapperStuff = async (tagData: any) => {
if (tagData[0]?.lastareaIn === "NeedsChecked") { console.log("WrapperTag", tagData[0].tag);
createLog(
"error",
"rfid",
"rfid",
`The tags on this pallet need to be checked as it was flagged as more than 1 tag number. please validate and looks at both sides.`
);
// just making sure we clear out the running number if one really came over.
for (let i = 0; i < tagData.length; i++) {
const tag = { ...tagData[i], runningNr: 0 };
tagStuff([tag]);
}
monitorChecks();
return {
success: false,
message:
"The tags on this pallet need to be checked as it was flagged as more than 1 tag number. please validate and looks at both sides.",
};
}
if (tagData.length != 1) { if (tagData.length != 1) {
createLog( createLog(
"error", "error",
@@ -38,39 +24,55 @@ export const wrapperStuff = async (tagData: TagData[]) => {
`There are ${tagData.length} tags and this ${tagData[0].reader} only allows 1 tag to create a label.` `There are ${tagData.length} tags and this ${tagData[0].reader} only allows 1 tag to create a label.`
); );
const tag = { ...tagData[0], runningNr: 0 }; const tag = { ...tagData[0], runningNr: 0 };
tagStuff([tag]); //tagStuff([tag]);
monitorChecks(); monitorChecks();
} else { } else {
if (!tagData) { if (!tagData) {
createLog("error", "rfid", "rfid", `No tagData was grabbed.`); createLog("error", "rfid", "rfid", `No tagData was grabbed.`);
monitorChecks(); monitorChecks();
} }
const tagdata = await tagStuff(tagData); const { data: tagdata, error: tagError } = await tryCatch(
/** db.select().from(rfidTags).where(eq(rfidTags.tag, tagData[0].tag))
* we want to make sure this pallet came from a line as its last spot if not we need to have a manual check. );
*/ if (tagError) {
return {
const lines = tagdata[0]?.lastareaIn.includes("line3"); success: false,
message: `There was an error getting the tag data for ${tagData[0].tag}.`,
};
}
const checkTag: any = tagdata;
if (checkTag[0]?.lastareaIn === "NeedsChecked") {
createLog(
"error",
"rfid",
"rfid",
`The tags on this pallet need to be checked as it was flagged as more than 1 tag number. please validate and looks at both sides.`
);
for (let i = 0; i < tagData.length; i++) {
const tag = { ...tagData[i], runningNr: 0 };
tagStuff([tag]);
}
monitorChecks();
return {
success: false,
message:
"The tags on this pallet need to be checked as it was flagged as more than 1 tag number. please validate and looks at both sides.",
};
}
const lines = checkTag[0]?.lastareaIn.includes("line3");
if (!lines) { if (!lines) {
createLog( createLog(
"error", "error",
"rfid", "rfid",
"rfid", "rfid",
`${tagdata[0].tag}, Did not come from a line please check the pallet and manually print the label.` `${tagData[0].tag}, Did not come from a line please check the pallet and manually print the label.`
); );
monitorChecks(); monitorChecks();
return { return {
success: false, success: false,
message: `${tagdata[0].tag}, Did not come from a line please check the pallet and manually print the label.`, message: `${tagData[0].tag}, Did not come from a line please check the pallet and manually print the label.`,
}; };
// when we manually run again we want to make sure we read from the 3rd antenna this way we do not get the wrong info.
// more testing will need to be done on this.
} }
// check if a running number exists
if (lines[0].runningNumber) { if (lines[0].runningNumber) {
createLog( createLog(
"info", "info",
@@ -83,12 +85,10 @@ export const wrapperStuff = async (tagData: TagData[]) => {
"info", "info",
"rfid", "rfid",
"rfid", "rfid",
`A new label will be created and linked to this ${tagdata[0].tag} tag` `A new label will be created and linked to this ${tagData[0].tag} tag`
); );
// get the actaul line number from the last area in
const lineNum = parseInt( const lineNum = parseInt(
tagdata[0]?.lastareaIn.repalceAll("line3", "") checkTag[0]?.lastareaIn.repalceAll("line3", "")
); );
createLog( createLog(
"info", "info",
@@ -96,17 +96,16 @@ export const wrapperStuff = async (tagData: TagData[]) => {
"rfid", "rfid",
`Line to be checked for printing: ${lineNum}` `Line to be checked for printing: ${lineNum}`
); );
const genlabel = await labelingProcess({ const genlabel = await labelingProcess({
line: lineNum.toString(), line: lineNum.toString(),
}); });
if (genlabel?.success) { if (genlabel?.success) {
// update the tag and add the label into it
const createPrintData = { const createPrintData = {
...tagData[0], ...tagData[0],
runnungNr: parseInt(genlabel.data?.SSCC.slice(10, -1)), runnungNr: parseInt(genlabel.data?.SSCC.slice(10, -1)),
}; };
tagStuff([createPrintData]);
} }
} }
} }

View File

@@ -15,6 +15,9 @@ export const tagData = async (data: TagData[]) => {
* We will always update a tag * We will always update a tag
*/ */
if (monitorTagsdata.includes(data[0].tag)) {
}
// dyco wall makes sure we have 10 tags // dyco wall makes sure we have 10 tags
const station1 = data.some((n) => n.reader.includes("reader1")); const station1 = data.some((n) => n.reader.includes("reader1"));
@@ -44,3 +47,21 @@ export const tagData = async (data: TagData[]) => {
wrapperStuff(data); wrapperStuff(data);
} }
}; };
const monitorTagsdata: any = [];
const monitorTags = (tag: string) => {
/**
* If we have to check more than 10 tags in an hour send an email to alert everyone.
*/
const now = new Date(Date.now()).getTime();
monitorTagsdata.push({ timestamp: now, tag: tag });
// remove if creater than 1 hour
const removalTiming = now - 2 * 60 * 1000; // 2 min
while (
monitorTagsdata > 0 &&
monitorTagsdata[0].timestamp < removalTiming
) {
monitorTagsdata.shift();
}
};

View File

@@ -1,8 +1,12 @@
import {db} from "../../../../../database/dbclient.js"; import { db } from "../../../../../database/dbclient.js";
import {rfidTags} from "../../../../../database/schema/rfidTags.js"; import { rfidTags } from "../../../../../database/schema/rfidTags.js";
import {createLog} from "../../../logger/logger.js"; import { createLog } from "../../../logger/logger.js";
export const manualTag = async (tag: string, area: string) => { export const manualTag = async (
tag: string,
area: string,
runningNr?: any | null
) => {
/** /**
* we only allow tags to be manually added from the wrappers * we only allow tags to be manually added from the wrappers
*/ */
@@ -13,24 +17,40 @@ export const manualTag = async (tag: string, area: string) => {
tagHex: Buffer.from(tagString, "utf8").toString("hex").toUpperCase(), tagHex: Buffer.from(tagString, "utf8").toString("hex").toUpperCase(),
tag: tagString, tag: tagString,
lastRead: new Date(Date.now()), lastRead: new Date(Date.now()),
counts: [{area: area, timesHere: 1}], //jsonb("counts").notNull(), //.default([{area: 1, timesHere: 5}]).notNull(), counts: [{ area: area, timesHere: 1 }], //jsonb("counts").notNull(), //.default([{area: 1, timesHere: 5}]).notNull(),
lastareaIn: area, lastareaIn: area,
antenna: 0, antenna: 0,
tagStrength: -1, tagStrength: -1,
}; };
try { try {
// insert the tag with the onConflict update the tag // insert the tag with the onConflict update the tag
const tag = await db.insert(rfidTags).values(newTag).returning({ const tag = await db
tag: rfidTags.tag, .insert(rfidTags)
runningNumber: rfidTags.runningNumber, .values(newTag)
counts: rfidTags.counts, .returning({
lastareaIn: rfidTags.lastareaIn, tag: rfidTags.tag,
}); runningNumber: runningNr ? runningNr : rfidTags.runningNumber,
createLog("info", "rfid", "rfid", `Tags were just added, and label printed.`); counts: rfidTags.counts,
lastareaIn: rfidTags.lastareaIn,
});
createLog(
"info",
"rfid",
"rfid",
`Tags were just added, and label printed.`
);
// do the label thing here // do the label thing here
return {success: true, message: `${tagString} was just added, and label printed.`, data: tag}; return {
success: true,
message: `${tagString} was just added, and label printed.`,
data: tag,
};
} catch (error) { } catch (error) {
createLog("error", "rfid", "rfid", `${JSON.stringify(error)}`); createLog("error", "rfid", "rfid", `${JSON.stringify(error)}`);
return {success: false, message: `Error creating a new tag`, data: error}; return {
success: false,
message: `Error creating a new tag`,
data: error,
};
} }
}; };

View File

@@ -1,24 +1,24 @@
//http://usday1vms006:4000/api/v1/zebra/wrapper1 //http://usday1vms006:4000/api/v1/zebra/wrapper1
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi"; import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
import {readTags} from "../controller/readTags.js"; import { readTags } from "../controller/readTags.js";
import {createLog} from "../../logger/logger.js"; import { createLog } from "../../logger/logger.js";
import {responses} from "../../../globalUtils/routeDefs/responses.js"; import { responses } from "../../../globalUtils/routeDefs/responses.js";
import {newHeartBeat} from "../controller/readerControl.js"; import { newHeartBeat } from "../controller/readerControl.js";
const app = new OpenAPIHono(); const app = new OpenAPIHono();
let lastGpiTimestamp = 0; let lastGpiTimestamp = 0;
const ParamsSchema = z.object({ const ParamsSchema = z.object({
reader: z reader: z
.string() .string()
.min(3) .min(3)
.openapi({ .openapi({
param: { param: {
name: "reader", name: "reader",
in: "path", in: "path",
}, },
example: "1212121", example: "1212121",
}), }),
}); });
app.openapi( app.openapi(
@@ -33,31 +33,47 @@ app.openapi(
responses: responses(), responses: responses(),
}), }),
async (c) => { async (c) => {
const {reader} = c.req.valid("param"); const { reader } = c.req.valid("param");
const body = await c.req.json(); const body = await c.req.json();
if (body.type === "heartbeat") { if (body.type === "heartbeat") {
const heart = await newHeartBeat(reader); const heart = await newHeartBeat(reader);
return c.json({success: heart.success, message: heart.message}, 200); return c.json(
{ success: heart.success, message: heart.message },
200
);
} }
if (body.type === "gpi" && body.data.state === "HIGH") { if (body.type === "gpi" && body.data.state === "HIGH") {
const eventTimestamp = new Date(body.timestamp).getTime(); // Convert ISO timestamp to milliseconds const eventTimestamp = new Date(body.timestamp).getTime(); // Convert ISO timestamp to milliseconds
if (eventTimestamp - lastGpiTimestamp > 5 * 1000) { if (eventTimestamp - lastGpiTimestamp > 30 * 1000) {
// Check if it's been more than 2ms // Check if it's been more than 2ms
lastGpiTimestamp = eventTimestamp; // Update last seen timestamp lastGpiTimestamp = eventTimestamp; // Update last seen timestamp
createLog("info", "rfid", "rfid", `${reader} is reading a tag.`); createLog(
"info",
"rfid",
"rfid",
`${reader} is reading a tag.`
);
await readTags(reader); await readTags(reader);
} else { } else {
createLog("info", "rfid", "rfid", `A new trigger from ${reader} was to soon`); createLog(
"info",
"rfid",
"rfid",
`A new trigger from ${reader} was to soon`
);
lastGpiTimestamp = eventTimestamp; lastGpiTimestamp = eventTimestamp;
} }
//console.log(body); //console.log(body);
} }
return c.json({success: true, message: `New info from ${reader}`}, 200); return c.json(
{ success: true, message: `New info from ${reader}` },
200
);
} }
); );

View File

@@ -1,24 +1,27 @@
//http://usday1vms006:4000/api/v1/zebra/wrapper1 //http://usday1vms006:4000/api/v1/zebra/wrapper1
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi"; import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
import {ConsoleLogWriter} from "drizzle-orm"; import { ConsoleLogWriter } from "drizzle-orm";
import {tagData} from "../controller/tagData.js"; import { tagData } from "../controller/tagData.js";
import {responses} from "../../../globalUtils/routeDefs/responses.js"; import { responses } from "../../../globalUtils/routeDefs/responses.js";
import {noRead} from "../controller/noRead.js"; import { noRead } from "../controller/noRead.js";
import {badRead, goodRead} from "../controller/readerControl.js"; import { badRead, goodRead } from "../controller/readerControl.js";
import { createLog } from "../../logger/logger.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { stopRead } from "../controller/readTags.js";
const app = new OpenAPIHono(); const app = new OpenAPIHono();
const ParamsSchema = z.object({ const ParamsSchema = z.object({
reader: z reader: z
.string() .string()
.min(3) .min(3)
.openapi({ .openapi({
param: { param: {
name: "reader", name: "reader",
in: "path", in: "path",
}, },
example: "1212121", example: "1212121",
}), }),
}); });
app.openapi( app.openapi(
@@ -33,15 +36,25 @@ app.openapi(
responses: responses(), responses: responses(),
}), }),
async (c) => { async (c) => {
const {reader} = c.req.valid("param"); const { reader } = c.req.valid("param");
createLog("info", "rfid", "rfid", `${reader} is sending us data.`);
let tagdata: any = []; let tagdata: any = [];
const body = await c.req.json(); const { data: body, error: bodyError } = await tryCatch(c.req.json());
if (bodyError) {
return c.json({ success: false, message: "missing data" }, 400);
}
//console.log(`Tag: ${Buffer.from(body.idHex, "hex").toString("utf-8")}, ${body[key].data.idHex}`); //console.log(`Tag: ${Buffer.from(body.idHex, "hex").toString("utf-8")}, ${body[key].data.idHex}`);
for (let i = 0; i < body.length; i++) { for (let i = 0; i < body.length; i++) {
const tag = Buffer.from(body[i].data.idHex, "hex").toString("utf-8"); const tag = Buffer.from(body[i].data.idHex, "hex").toString(
"utf-8"
);
//console.log("Raw value:", body[i].data.peakRssi, "Parsed:", parseInt(body[i].data.peakRssi)); //console.log("Raw value:", body[i].data.peakRssi, "Parsed:", parseInt(body[i].data.peakRssi));
if (tag.includes("ALPLA") && parseInt(body[i].data.peakRssi) < -50) { if (
tag.includes("ALPLA") &&
parseInt(body[i].data.peakRssi) < -50
) {
tagdata = [ tagdata = [
...tagdata, ...tagdata,
{ {
@@ -59,11 +72,18 @@ app.openapi(
if (tagdata.length === 0) { if (tagdata.length === 0) {
noRead(reader); noRead(reader);
badRead(reader); badRead(reader);
return c.json({success: false, message: `There were no tags scanned.`}, 200); return c.json(
{ success: false, message: `There were no tags scanned.` },
200
);
} else { } else {
tagData(tagdata); tagData(tagdata);
goodRead(reader); goodRead(reader);
return c.json({success: true, message: `New info from ${reader}`}, 200);
return c.json(
{ success: true, message: `New info from ${reader}` },
200
);
} }
} }
); );

View File

@@ -168,6 +168,13 @@ const newSettings = [
roles: "admin", roles: "admin",
module: "ocp", module: "ocp",
}, },
{
name: "strapperCheck",
value: "1",
description: "Are we monitoring the strapper for faults?",
roles: "admin",
module: "ocp",
},
]; ];
export const areSettingsIn = async () => { export const areSettingsIn = async () => {
// get the roles // get the roles

View File

@@ -16,5 +16,6 @@ left join
alplaprod_test1.dbo.T_Maschine as m on alplaprod_test1.dbo.T_Maschine as m on
e.IdMaschine = m.IdMaschine e.IdMaschine = m.IdMaschine
where x.lfdnr = [rn] and x.IdWarenlager not in(6) where x.lfdnr = [rn]
--and x.IdWarenlager not in(6)
`; `;

View File

@@ -3,7 +3,7 @@ select IdMaschinen_ProdPlanung as LabelOnlineID,
IdMaschine as machineID, IdMaschine as machineID,
MaschinenStandort as MachineLocation, MaschinenStandort as MachineLocation,
MaschinenBez as MachineDescription, MaschinenBez as MachineDescription,
IdProdPlanung as LOT, IdProdPlanung as lot,
prolink.lot as ProlinkLot, prolink.lot as ProlinkLot,
IdArtikelvarianten as AV, IdArtikelvarianten as AV,
ArtikelVariantenBez as Alias, ArtikelVariantenBez as Alias,

View File

@@ -14,6 +14,9 @@ let tcpServer: net.Server;
let tcpSockets: Set<net.Socket> = new Set(); let tcpSockets: Set<net.Socket> = new Set();
let isServerRunning = false; let isServerRunning = false;
/**
* add in proper logging
*/
const tcpPort = await db const tcpPort = await db
.select() .select()
.from(settings) .from(settings)
@@ -25,14 +28,19 @@ export const startTCPServer = () => {
return { success: false, message: "Server is already running" }; return { success: false, message: "Server is already running" };
tcpServer = net.createServer((socket) => { tcpServer = net.createServer((socket) => {
console.log("Client connected"); createLog("info", "tcp", "tcp", "Client connected");
tcpSockets.add(socket); tcpSockets.add(socket);
socket.on("data", (data: Buffer) => { socket.on("data", (data: Buffer) => {
console.log("Received:", data.toString());
const parseData = data.toString("utf-8").trimEnd().split(" "); const parseData = data.toString("utf-8").trimEnd().split(" ");
// hb from the scanners // hb from the scanners
if (parseData[0] === "HB") { if (parseData[0] === "HB") {
createLog(
"debug",
"tcp",
"tcp",
`Received:", ${data.toString()}`
);
return; return;
} }
@@ -46,12 +54,12 @@ export const startTCPServer = () => {
}); });
socket.on("end", () => { socket.on("end", () => {
console.log("Client disconnected"); createLog("info", "tcp", "tcp", "Client disconnected");
tcpSockets.delete(socket); tcpSockets.delete(socket);
}); });
socket.on("error", (err: Error) => { socket.on("error", (err: Error) => {
console.error("Socket error:", err); createLog("info", "tcp", "tcp", `Socket error:", ${err}`);
tcpSockets.delete(socket); tcpSockets.delete(socket);
}); });
}); });
@@ -78,7 +86,7 @@ export const stopTCPServer = () => {
} }
tcpSockets.clear(); tcpSockets.clear();
tcpServer.close(() => { tcpServer.close(() => {
console.log("TCP Server stopped"); createLog("info", "tcp", "tcp", "TCP Server stopped");
}); });
isServerRunning = false; isServerRunning = false;
return { success: true, message: "TCP Server stopped" }; return { success: true, message: "TCP Server stopped" };