Compare commits
12 Commits
a73c63cefa
...
cb59f58926
| Author | SHA1 | Date | |
|---|---|---|---|
| cb59f58926 | |||
| 1a79a97929 | |||
| 4b92a28dfa | |||
| 4aae659ee4 | |||
| 7bfb48b81f | |||
| 7432decd3c | |||
| 04a607d3bc | |||
| d178e04362 | |||
| 020fdc83af | |||
| 33803a69a6 | |||
| 3ea6dc5bc4 | |||
| b484a0c5ea |
41
CHANGELOG.md
41
CHANGELOG.md
@@ -1,5 +1,46 @@
|
||||
# All CHanges to LST can be found below.
|
||||
|
||||
## [2.7.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.6.0...v2.7.0) (2025-03-15)
|
||||
|
||||
|
||||
### 📝 Chore
|
||||
|
||||
* bump build number to 10 ([245ba19](https://git.tuffraid.net/cowch/lstV2/commits/245ba19cdc7e67fec9343bb9eba90287d8951854))
|
||||
* bump build number to 11 ([c9a5203](https://git.tuffraid.net/cowch/lstV2/commits/c9a520313160959ed929351f55bd18606b6500a9))
|
||||
* bump build number to 12 ([b1d25c7](https://git.tuffraid.net/cowch/lstV2/commits/b1d25c7ba27a72c42803a3b482234c41670a07a2))
|
||||
* bump build number to 13 ([bcd65b4](https://git.tuffraid.net/cowch/lstV2/commits/bcd65b4b91cf6cb24a32323ead5ff6a73d3c9d3d))
|
||||
* bump build number to 14 ([a2fb845](https://git.tuffraid.net/cowch/lstV2/commits/a2fb845e2efbeb8becf91082343770b2d730330c))
|
||||
* bump build number to 15 ([0b72ffa](https://git.tuffraid.net/cowch/lstV2/commits/0b72ffa935be81476a15166fd60ae8cabe29d297))
|
||||
* bump build number to 16 ([44da09d](https://git.tuffraid.net/cowch/lstV2/commits/44da09d22c4d946c981d408d797ea121d26690b6))
|
||||
* bump build number to 17 ([1ce5f9a](https://git.tuffraid.net/cowch/lstV2/commits/1ce5f9acf752f5f4bcb4b2ff1c71f54ffb9331f3))
|
||||
* bump build number to 18 ([b6f1cfd](https://git.tuffraid.net/cowch/lstV2/commits/b6f1cfdc6c71e351fb90ec7729e0d0f89322174f))
|
||||
|
||||
|
||||
### 🛠️ Code Refactor
|
||||
|
||||
* **frontend:** removed tanstack devTools ([3594278](https://git.tuffraid.net/cowch/lstV2/commits/359427824bae319b7f2f406eb52b8f9c43be198f))
|
||||
* **frontend:** removed the caption from settings table ([35acd2b](https://git.tuffraid.net/cowch/lstV2/commits/35acd2b0b3af7b9d010cb8f78f088ab3a539c54b))
|
||||
|
||||
|
||||
### 🌟 Enhancements
|
||||
|
||||
* **frontend:** added in proper links for settings and servers to the sidebar ([cbdd218](https://git.tuffraid.net/cowch/lstV2/commits/cbdd218fe454e38a7cf0c4d0ddf60d1f20e15ee2))
|
||||
* **frontend:** added in update server page only for sysAdmin ([625d596](https://git.tuffraid.net/cowch/lstV2/commits/625d5969be2dbde9e97f6607c33c5e5b14e3d192))
|
||||
* **new setting:** added in devDir ment for updating servers ([5b97d07](https://git.tuffraid.net/cowch/lstV2/commits/5b97d078c583f3e78d52dbc135da99a0175c8e54))
|
||||
* **server upgrade:** added in a catch incase we try to upgrade again ([ab16059](https://git.tuffraid.net/cowch/lstV2/commits/ab16059387b7cb46e2a3d86f6da09a31899bd5d6))
|
||||
* **server:** added in update server as well as get serverdata ([df252e7](https://git.tuffraid.net/cowch/lstV2/commits/df252e72b39d811ffbbb0af49aaf43ff22081f48))
|
||||
* **serverdata:** added catch if we are not on localhost we cant actaully see the devDir in set ([f3fa617](https://git.tuffraid.net/cowch/lstV2/commits/f3fa617aa53ed35f461b71f5e479ea521412936e))
|
||||
* **serverdata:** added in bowling green 2 ([7529cc5](https://git.tuffraid.net/cowch/lstV2/commits/7529cc5b0cc2c6542e8f4af07d465b6a9f4295b1))
|
||||
* **sql query:** added 2 catches if not connected dont run ([cb7a406](https://git.tuffraid.net/cowch/lstV2/commits/cb7a4068fcffc7a1d85c2e04f2eeaebdc264705c))
|
||||
* **sql server:** added in the ping check to not spam if we are not connected ([e4d15ef](https://git.tuffraid.net/cowch/lstV2/commits/e4d15ef051f6c72d2cca9bb9fb61ff78849db8c4))
|
||||
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
* **frontend:** if the modules returns and error we want to use an empty array ([2370d45](https://git.tuffraid.net/cowch/lstV2/commits/2370d45220c5e1c3215a3f2fce9582d8f2bbd3ed))
|
||||
* **rfid:** correction to the params and incorrect naming ([a73c63c](https://git.tuffraid.net/cowch/lstV2/commits/a73c63cefa67f43300f4695f40f2248bcab8f40e))
|
||||
* **zippaths:** corrected the paths to the src that were moved the the env ([246b5a1](https://git.tuffraid.net/cowch/lstV2/commits/246b5a17bd4ffe47654416fa4a1be446f8bffbd0))
|
||||
|
||||
## [2.6.0](https://git.tuffraid.net/cowch/lstV2/compare/v2.5.1...v2.6.0) (2025-03-14)
|
||||
|
||||
|
||||
|
||||
1
database/migrations/0017_bitter_brood.sql
Normal file
1
database/migrations/0017_bitter_brood.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE "rfidReaders" ADD COLUMN "lastTrigger" timestamp DEFAULT now();
|
||||
1
database/migrations/0018_lovely_landau.sql
Normal file
1
database/migrations/0018_lovely_landau.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE "rfidReaders" ADD COLUMN "active" boolean DEFAULT true;
|
||||
2
database/migrations/0019_greedy_justice.sql
Normal file
2
database/migrations/0019_greedy_justice.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE "rfidTags" ADD COLUMN "antenna" numeric;--> statement-breakpoint
|
||||
ALTER TABLE "rfidTags" ADD COLUMN "tagStrength" numeric;
|
||||
2
database/migrations/0020_empty_thundra.sql
Normal file
2
database/migrations/0020_empty_thundra.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE "rfidTags" ALTER COLUMN "counts" SET DEFAULT '[]'::jsonb;--> statement-breakpoint
|
||||
ALTER TABLE "rfidTags" ALTER COLUMN "counts" DROP NOT NULL;
|
||||
4
database/migrations/0021_premium_albert_cleary.sql
Normal file
4
database/migrations/0021_premium_albert_cleary.sql
Normal file
@@ -0,0 +1,4 @@
|
||||
ALTER TABLE "rfidTags" ALTER COLUMN "runningNumber" SET DATA TYPE integer;--> statement-breakpoint
|
||||
ALTER TABLE "rfidTags" ALTER COLUMN "runningNumber" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "rfidTags" ALTER COLUMN "antenna" SET DATA TYPE integer;--> statement-breakpoint
|
||||
ALTER TABLE "rfidTags" ALTER COLUMN "tagStrength" SET DATA TYPE integer;
|
||||
1
database/migrations/0022_amused_true_believers.sql
Normal file
1
database/migrations/0022_amused_true_believers.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE "rfidReaders" ADD COLUMN "lastTiggerGood" boolean DEFAULT true;
|
||||
1047
database/migrations/meta/0017_snapshot.json
Normal file
1047
database/migrations/meta/0017_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1054
database/migrations/meta/0018_snapshot.json
Normal file
1054
database/migrations/meta/0018_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1066
database/migrations/meta/0019_snapshot.json
Normal file
1066
database/migrations/meta/0019_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1067
database/migrations/meta/0020_snapshot.json
Normal file
1067
database/migrations/meta/0020_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1067
database/migrations/meta/0021_snapshot.json
Normal file
1067
database/migrations/meta/0021_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1074
database/migrations/meta/0022_snapshot.json
Normal file
1074
database/migrations/meta/0022_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -120,6 +120,48 @@
|
||||
"when": 1742051878587,
|
||||
"tag": "0016_wet_doctor_strange",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 17,
|
||||
"version": "7",
|
||||
"when": 1742133439717,
|
||||
"tag": "0017_bitter_brood",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 18,
|
||||
"version": "7",
|
||||
"when": 1742133828291,
|
||||
"tag": "0018_lovely_landau",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 19,
|
||||
"version": "7",
|
||||
"when": 1742139737945,
|
||||
"tag": "0019_greedy_justice",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 20,
|
||||
"version": "7",
|
||||
"when": 1742143798267,
|
||||
"tag": "0020_empty_thundra",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 21,
|
||||
"version": "7",
|
||||
"when": 1742144973347,
|
||||
"tag": "0021_premium_albert_cleary",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 22,
|
||||
"version": "7",
|
||||
"when": 1742156466912,
|
||||
"tag": "0022_amused_true_believers",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -9,6 +9,9 @@ export const rfidReaders = pgTable(
|
||||
reader: text("reader"),
|
||||
readerIP: text("readerIP"),
|
||||
lastHeartBeat: timestamp("lastHeartBeat").defaultNow(),
|
||||
lastTrigger: timestamp("lastTrigger").defaultNow(),
|
||||
lastTriggerGood: boolean("lastTiggerGood").default(true),
|
||||
active: boolean("active").default(true),
|
||||
},
|
||||
(table) => [
|
||||
// uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {text, pgTable, numeric, index, timestamp, boolean, uuid, uniqueIndex, jsonb} from "drizzle-orm/pg-core";
|
||||
import {text, pgTable, timestamp, uuid, uniqueIndex, jsonb, integer} from "drizzle-orm/pg-core";
|
||||
import {createInsertSchema, createSelectSchema} from "drizzle-zod";
|
||||
import {z} from "zod";
|
||||
|
||||
@@ -9,9 +9,11 @@ export const rfidTags = pgTable(
|
||||
tagHex: text("tagHex"),
|
||||
tag: text("tag"),
|
||||
lastRead: timestamp("timeStamp").defaultNow(),
|
||||
counts: jsonb("counts").notNull(), //.default([{area: 1, timesHere: 5}]).notNull(),
|
||||
counts: jsonb("counts").default([]), // example [{area: Line3.2, count: 1}, {area: line3.1, count: 6}]
|
||||
lastareaIn: text("lastareaIn").notNull(),
|
||||
runningNumber: numeric("runningNumber").notNull(),
|
||||
runningNumber: integer("runningNumber"),
|
||||
antenna: integer("antenna"),
|
||||
tagStrength: integer("tagStrength"),
|
||||
created_at: timestamp("created_at").defaultNow(),
|
||||
},
|
||||
(table) => [
|
||||
@@ -21,8 +23,8 @@ export const rfidTags = pgTable(
|
||||
);
|
||||
|
||||
// Schema for inserting a user - can be used to validate API requests
|
||||
// export const insertRolesSchema = createInsertSchema(roles, {
|
||||
// name: z.string().min(3, {message: "Role name must be more than 3 letters"}),
|
||||
// });
|
||||
export const insertRolesSchema = createInsertSchema(rfidTags, {
|
||||
tagHex: z.string().min(3, {message: "Tag Should have more than 3 characters"}),
|
||||
});
|
||||
// Schema for selecting a Expenses - can be used to validate API responses
|
||||
export const selectRolesSchema = createSelectSchema(rfidTags);
|
||||
|
||||
15
frontend/package-lock.json
generated
15
frontend/package-lock.json
generated
@@ -33,6 +33,7 @@
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lucide-react": "^0.476.0",
|
||||
"next-themes": "^0.4.4",
|
||||
"npm-check-updates": "^17.1.15",
|
||||
"react": "^19.0.0",
|
||||
"react-day-picker": "^8.10.1",
|
||||
"react-dom": "^19.0.0",
|
||||
@@ -4901,6 +4902,20 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/npm-check-updates": {
|
||||
"version": "17.1.15",
|
||||
"resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-17.1.15.tgz",
|
||||
"integrity": "sha512-miATvKu5rjec/1wxc5TGDjpsucgtCHwRVZorZpDkS6NzdWXfnUWlN4abZddWb7XSijAuBNzzYglIdTm9SbgMVg==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"ncu": "build/cli.js",
|
||||
"npm-check-updates": "build/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0",
|
||||
"npm": ">=8.12.1"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"build": "rimraf dist && tsc -b && vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview",
|
||||
"shad": "npx shadcn@canary add "
|
||||
"shad": "npx shadcn@canary add ",
|
||||
"checkupdates": "npm-check-updates"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^4.1.2",
|
||||
@@ -36,6 +37,7 @@
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"lucide-react": "^0.476.0",
|
||||
"next-themes": "^0.4.4",
|
||||
"npm-check-updates": "^17.1.15",
|
||||
"react": "^19.0.0",
|
||||
"react-day-picker": "^8.10.1",
|
||||
"react-dom": "^19.0.0",
|
||||
|
||||
23935
package-lock.json
generated
23935
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
148
package.json
148
package.json
@@ -1,75 +1,77 @@
|
||||
{
|
||||
"name": "lstv2",
|
||||
"version": "2.6.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "concurrently -n \"server,frontend\" -c \"#007755,#2f6da3\" \"npm run dev:server\" \"cd frontend && npm run dev\"",
|
||||
"dev:server": "dotenvx run -f .env -- tsx watch server/index.ts",
|
||||
"dev:frontend": "cd frontend && npm run dev",
|
||||
"dev:dbgen": " drizzle-kit generate --config=drizzle-dev.config.ts",
|
||||
"dev:dbmigrate": " drizzle-kit migrate --config=drizzle-dev.config.ts",
|
||||
"build": "npm run build:server && npm run build:frontend",
|
||||
"build:server": "rimraf build && tsc --build && xcopy server\\scripts dist\\server\\scripts /E /I /Y && xcopy server\\services\\server\\utils\\serverData.json dist\\server\\services\\server\\utils /E /I /Y ",
|
||||
"build:frontend": "cd frontend && npm run build",
|
||||
"start": "set NODE_ENV=production && npm run start:server",
|
||||
"start:server": "dotenvx run -f .env -- node dist/server/index.js",
|
||||
"db:generate": "npx drizzle-kit generate",
|
||||
"db:migrate": "npx drizzle-kit push",
|
||||
"deploy": "standard-version --conventional-commits && npm run prodBuild",
|
||||
"zipServer": "dotenvx run -f .env -- tsx server/scripts/zipUpBuild.ts \"C:\\Users\\matthes01\\Documents\\lstv2\"",
|
||||
"prodBuild": "powershell -ExecutionPolicy Bypass -File server/scripts/build.ps1 -dir \"C:\\Users\\matthes01\\Documents\\lstv2\" && npm run zipServer",
|
||||
"commit": "cz",
|
||||
"prodinstall": "npm i --omit=dev && npm run db:migrate"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dotenvx/dotenvx": "^1.38.3",
|
||||
"@hono/node-server": "^1.13.8",
|
||||
"@hono/zod-openapi": "^0.18.4",
|
||||
"@scalar/hono-api-reference": "^0.5.175",
|
||||
"@types/jsonwebtoken": "^9.0.8",
|
||||
"adm-zip": "^0.5.16",
|
||||
"axios": "^1.7.9",
|
||||
"bcrypt": "^5.1.1",
|
||||
"compression": "^1.8.0",
|
||||
"cookie": "^1.0.2",
|
||||
"date-fns": "^4.1.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"drizzle-kit": "^0.30.4",
|
||||
"drizzle-orm": "^0.39.3",
|
||||
"drizzle-zod": "^0.7.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mssql": "^11.0.1",
|
||||
"nodemailer": "^6.10.0",
|
||||
"nodemailer-express-handlebars": "^7.0.0",
|
||||
"pg": "^8.13.3",
|
||||
"pino": "^9.6.0",
|
||||
"pino-abstract-transport": "^2.0.0",
|
||||
"pino-pretty": "^13.0.0",
|
||||
"postgres": "^3.4.5",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/adm-zip": "^0.5.7",
|
||||
"@types/bcrypt": "^5.0.2",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/mssql": "^9.1.7",
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/pg": "^8.11.11",
|
||||
"concurrently": "^8.2.0",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"dotenv": "^16.3.1",
|
||||
"rimraf": "^6.0.1",
|
||||
"standard-version": "^9.5.0",
|
||||
"tsx": "^4.7.1",
|
||||
"typescript": "~5.7.3"
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
"path": "./node_modules/cz-conventional-changelog"
|
||||
"name": "lstv2",
|
||||
"version": "2.7.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "concurrently -n \"server,frontend\" -c \"#007755,#2f6da3\" \"npm run dev:server\" \"cd frontend && npm run dev\"",
|
||||
"dev:server": "dotenvx run -f .env -- tsx watch server/index.ts",
|
||||
"dev:frontend": "cd frontend && npm run dev",
|
||||
"dev:dbgen": " drizzle-kit generate --config=drizzle-dev.config.ts",
|
||||
"dev:dbmigrate": " drizzle-kit migrate --config=drizzle-dev.config.ts",
|
||||
"build": "npm run build:server && npm run build:frontend",
|
||||
"build:server": "rimraf build && tsc --build && xcopy server\\scripts dist\\server\\scripts /E /I /Y && xcopy server\\services\\server\\utils\\serverData.json dist\\server\\services\\server\\utils /E /I /Y ",
|
||||
"build:frontend": "cd frontend && npm run build",
|
||||
"start": "set NODE_ENV=production && npm run start:server",
|
||||
"start:server": "dotenvx run -f .env -- node dist/server/index.js",
|
||||
"db:generate": "npx drizzle-kit generate",
|
||||
"db:migrate": "npx drizzle-kit push",
|
||||
"db:dev": "npm run build && npm run db:generate && npm run db:migrate",
|
||||
"deploy": "standard-version --conventional-commits && npm run prodBuild",
|
||||
"zipServer": "dotenvx run -f .env -- tsx server/scripts/zipUpBuild.ts \"C:\\Users\\matthes01\\Documents\\lstv2\"",
|
||||
"prodBuild": "powershell -ExecutionPolicy Bypass -File server/scripts/build.ps1 -dir \"C:\\Users\\matthes01\\Documents\\lstv2\" && npm run zipServer",
|
||||
"commit": "cz",
|
||||
"prodinstall": "npm i --omit=dev && npm run db:migrate",
|
||||
"checkupdates": "npm-check-updates"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dotenvx/dotenvx": "^1.38.3",
|
||||
"@hono/node-server": "^1.13.8",
|
||||
"@hono/zod-openapi": "^0.18.4",
|
||||
"@scalar/hono-api-reference": "^0.5.175",
|
||||
"@types/jsonwebtoken": "^9.0.8",
|
||||
"adm-zip": "^0.5.16",
|
||||
"axios": "^1.7.9",
|
||||
"bcrypt": "^5.1.1",
|
||||
"compression": "^1.8.0",
|
||||
"cookie": "^1.0.2",
|
||||
"date-fns": "^4.1.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"drizzle-kit": "^0.30.4",
|
||||
"drizzle-orm": "^0.39.3",
|
||||
"drizzle-zod": "^0.7.0",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mssql": "^11.0.1",
|
||||
"nodemailer": "^6.10.0",
|
||||
"nodemailer-express-handlebars": "^7.0.0",
|
||||
"pg": "^8.13.3",
|
||||
"pino": "^9.6.0",
|
||||
"pino-abstract-transport": "^2.0.0",
|
||||
"pino-pretty": "^13.0.0",
|
||||
"postgres": "^3.4.5",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/adm-zip": "^0.5.7",
|
||||
"@types/bcrypt": "^5.0.2",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/mssql": "^9.1.7",
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/pg": "^8.11.11",
|
||||
"concurrently": "^8.2.0",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"dotenv": "^16.3.1",
|
||||
"rimraf": "^6.0.1",
|
||||
"standard-version": "^9.5.0",
|
||||
"tsx": "^4.7.1",
|
||||
"typescript": "~5.7.3"
|
||||
},
|
||||
"config": {
|
||||
"commitizen": {
|
||||
"path": "./node_modules/cz-conventional-changelog"
|
||||
}
|
||||
},
|
||||
"admConfig": {
|
||||
"build": 19,
|
||||
"oldBuild": "backend-0.1.2-217.zip"
|
||||
}
|
||||
},
|
||||
"admConfig": {
|
||||
"build": 18,
|
||||
"oldBuild": "backend-0.1.2-217.zip"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
8
server/globalUtils/routeDefs/options.ts
Normal file
8
server/globalUtils/routeDefs/options.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export const apiOptions = () => {
|
||||
return {
|
||||
tags: ["rfid"],
|
||||
summary: "Add new reader",
|
||||
method: "post",
|
||||
path: "/addreader",
|
||||
};
|
||||
};
|
||||
45
server/globalUtils/routeDefs/responses.ts
Normal file
45
server/globalUtils/routeDefs/responses.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import {z} from "@hono/zod-openapi";
|
||||
|
||||
const responseSchema = z.object({
|
||||
success: z.boolean().openapi({example: true}),
|
||||
message: z.string().optional(),
|
||||
data: z
|
||||
.array(z.object({}).optional())
|
||||
.optional()
|
||||
.openapi({example: [{data: "hi"}]}),
|
||||
});
|
||||
|
||||
export const responses = () => {
|
||||
return {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": {schema: responseSchema},
|
||||
},
|
||||
description: "Response message",
|
||||
},
|
||||
400: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
|
||||
},
|
||||
},
|
||||
description: "Internal Server Error",
|
||||
},
|
||||
401: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
|
||||
},
|
||||
},
|
||||
description: "Unauthorized",
|
||||
},
|
||||
500: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
|
||||
},
|
||||
},
|
||||
description: "Internal Server Error",
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -16,6 +16,7 @@ import ocme from "./services/ocme/ocmeService.js";
|
||||
import sqlService from "./services/sqlServer/sqlService.js";
|
||||
import logistics from "./services/logistics/logisticsService.js";
|
||||
import rfid from "./services/rfid/rfidService.js";
|
||||
import printers from "./services/printers/printerService.js";
|
||||
|
||||
import {db} from "../database/dbclient.js";
|
||||
import {settings} from "../database/schema/settings.js";
|
||||
@@ -83,6 +84,7 @@ const routes = [
|
||||
sqlService,
|
||||
logistics,
|
||||
rfid,
|
||||
printers,
|
||||
] as const;
|
||||
|
||||
const appRoutes = routes.forEach((route) => {
|
||||
|
||||
14
server/services/printers/printerService.ts
Normal file
14
server/services/printers/printerService.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import {OpenAPIHono} from "@hono/zod-openapi";
|
||||
|
||||
import alerts from "./route/printerAlert.js";
|
||||
const app = new OpenAPIHono();
|
||||
const port = 4000;
|
||||
|
||||
const routes = [alerts] as const;
|
||||
|
||||
// app.route("/server", modules);
|
||||
const appRoutes = routes.forEach((route) => {
|
||||
app.route("/printers", route);
|
||||
});
|
||||
|
||||
export default app;
|
||||
102
server/services/printers/route/printerAlert.ts
Normal file
102
server/services/printers/route/printerAlert.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
//http://usday1vms006:4000/api/v1/zebra/wrapper1
|
||||
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi";
|
||||
|
||||
// Define the response schema
|
||||
const responseSchema = z.object({
|
||||
success: z.boolean().openapi({example: true}),
|
||||
message: z.string().optional(),
|
||||
});
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
const ParamsSchema = z.object({
|
||||
printer: z
|
||||
.string()
|
||||
.min(3)
|
||||
.openapi({
|
||||
param: {
|
||||
name: "printer",
|
||||
in: "path",
|
||||
},
|
||||
example: "Line1",
|
||||
}),
|
||||
});
|
||||
|
||||
app.openapi(
|
||||
createRoute({
|
||||
tags: ["printer"],
|
||||
summary: "Printer Alert",
|
||||
method: "post",
|
||||
path: "/{printer}",
|
||||
request: {
|
||||
params: ParamsSchema,
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": {schema: responseSchema},
|
||||
},
|
||||
description: "Response message",
|
||||
},
|
||||
400: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
|
||||
},
|
||||
},
|
||||
description: "Internal Server Error",
|
||||
},
|
||||
401: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
|
||||
},
|
||||
},
|
||||
description: "Unauthorized",
|
||||
},
|
||||
500: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
|
||||
},
|
||||
},
|
||||
description: "Internal Server Error",
|
||||
},
|
||||
},
|
||||
}),
|
||||
async (c) => {
|
||||
const {printer} = c.req.valid("param");
|
||||
|
||||
const contentType = c.req.header("Content-Type") || "";
|
||||
const boundaryMatch = contentType.match(/boundary=(.*)$/);
|
||||
|
||||
if (!boundaryMatch) {
|
||||
return c.json({message: "No boundary found in Content-Type"}, 400);
|
||||
}
|
||||
|
||||
const boundary = boundaryMatch[1];
|
||||
const body = await c.req.text(); // Get the body of the request
|
||||
|
||||
// Split the body by the boundary (adding extra dashes before the boundary)
|
||||
const parts = body.split(`--${boundary}`);
|
||||
console.log(parts);
|
||||
// Remove the first and last empty parts (they are just before and after the boundaries)
|
||||
const formDataParts = parts.slice(1, parts.length - 1);
|
||||
|
||||
// console.log(formDataParts);
|
||||
|
||||
// formDataParts.forEach((part, index) => {
|
||||
// // Split the part into headers and body
|
||||
// const [headers, data] = part.split("\r\n\r\n");
|
||||
|
||||
// // Log the part index and data for debugging
|
||||
// console.log(`Part ${index + 1}:`);
|
||||
// console.log("Headers:", headers);
|
||||
// console.log("Data:", decodeURIComponent(data));
|
||||
// });
|
||||
|
||||
return c.json({success: true, message: `New info from ${printer}`}, 200);
|
||||
}
|
||||
);
|
||||
|
||||
export default app;
|
||||
34
server/services/rfid/controller/addReader.ts
Normal file
34
server/services/rfid/controller/addReader.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import {z} from "zod";
|
||||
import {createLog} from "../../logger/logger.js";
|
||||
import {db} from "../../../../database/dbclient.js";
|
||||
import {rfidReaders} from "../../../../database/schema/rfidReaders.js";
|
||||
|
||||
const ReaderData = z.object({
|
||||
reader: z.string(),
|
||||
readerIP: z.string(),
|
||||
});
|
||||
|
||||
type ReaderData = z.infer<typeof ReaderData>;
|
||||
|
||||
export const addReader = async (data: ReaderData, user: any) => {
|
||||
/**
|
||||
* add a new reader with name and ip.
|
||||
*/
|
||||
|
||||
ReaderData.parse(data);
|
||||
|
||||
if (!data.reader && !data.readerIP) {
|
||||
createLog("error", user.username, "rfid", "Missing data please check that you have both a name and ip.");
|
||||
return {success: false, message: "Missing data please check that you have both a name and ip."};
|
||||
}
|
||||
|
||||
// try to add the reader
|
||||
try {
|
||||
await db.insert(rfidReaders).values(data).onConflictDoUpdate({target: rfidReaders.reader, set: data});
|
||||
createLog("info", user.username, "rfid", `Just added ${data.reader}.`);
|
||||
return {success: true, message: `${data.reader} was just added.`};
|
||||
} catch (error) {
|
||||
createLog("error", user.username, "rfid", `there was an error adding ${data.reader}, ${error}`);
|
||||
return {success: false, message: `${data.reader} encountered and error: ${error}`};
|
||||
}
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
7
server/services/rfid/controller/noRead.ts
Normal file
7
server/services/rfid/controller/noRead.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export const noRead = async (reader: string) => {
|
||||
console.log(`${reader} just had a no read please check for a tag and manually trigger a read.`);
|
||||
};
|
||||
@@ -1,51 +1,85 @@
|
||||
import axios from "axios";
|
||||
import {createLog} from "../../logger/logger.js";
|
||||
import {db} from "../../../../database/dbclient.js";
|
||||
import {rfidReaders} from "../../../../database/schema/rfidReaders.js";
|
||||
import {eq} from "drizzle-orm";
|
||||
|
||||
const authData = btoa("admin:Zebra123!");
|
||||
let token: string;
|
||||
let ip: string;
|
||||
|
||||
export const readTags = async (reader: string) => {
|
||||
/**
|
||||
* Start the read for x seconds then auto stop it
|
||||
*/
|
||||
|
||||
let token: string;
|
||||
|
||||
const readers = [{reader: "reader1", readerIP: "10.10.1.222", lastHeartBeat: new Date()}];
|
||||
const readers = await db.select().from(rfidReaders).where(eq(rfidReaders.active, true));
|
||||
if (readers.length === 0) {
|
||||
createLog("error", "rfid", "rfid", `There are no active readers right now maybe one forgot to be activated`);
|
||||
return;
|
||||
}
|
||||
// get the auth token
|
||||
const ip = readers.find((r) => r.reader === reader)?.readerIP;
|
||||
ip = readers.find((r) => r.reader === reader)?.readerIP as string;
|
||||
|
||||
try {
|
||||
const res = await axios.get(`https://${ip}/cloud/localRestLogin`, {
|
||||
headers: {Authorization: `Basic ${btoa("admin:Zebra123!")}`},
|
||||
headers: {Authorization: `Basic ${authData}`},
|
||||
});
|
||||
token = res.data.message;
|
||||
// start the read
|
||||
try {
|
||||
const res = await axios.put(
|
||||
`https://${ip}/cloud/start`,
|
||||
{},
|
||||
{
|
||||
headers: {Authorization: `Bearer ${token}`},
|
||||
}
|
||||
);
|
||||
|
||||
// stop after 5 seconds
|
||||
|
||||
try {
|
||||
const res = await axios.put(
|
||||
`https://${ip}/cloud/stop`,
|
||||
{},
|
||||
{
|
||||
headers: {Authorization: `Bearer ${token}`},
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
createLog("error", "rfid", "rfid", `There was an error Stopping the read ${error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
createLog("error", "rfid", "rfid", `There was an error Starting the read ${error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
createLog("error", "rfid", "rfid", `There was an error Getting the token the read ${error}`);
|
||||
startRead();
|
||||
} catch (error: any) {
|
||||
console.log(error);
|
||||
createLog(
|
||||
"error",
|
||||
"rfid",
|
||||
"rfid",
|
||||
`There was an error Getting the token the read: ${error.response?.data.message}`
|
||||
);
|
||||
}
|
||||
|
||||
// start the read
|
||||
};
|
||||
|
||||
const startRead = async () => {
|
||||
try {
|
||||
const res = await axios.put(
|
||||
`https://${ip}/cloud/start`,
|
||||
{},
|
||||
{
|
||||
headers: {Authorization: `Bearer ${token}`},
|
||||
}
|
||||
);
|
||||
|
||||
//console.log(res.data);
|
||||
|
||||
if (res.status === 200) {
|
||||
setTimeout(() => {
|
||||
stopRead();
|
||||
}, 5 * 1000);
|
||||
}
|
||||
|
||||
// stop after 5 seconds
|
||||
} catch (error: any) {
|
||||
if (error.response.data.code === 3) {
|
||||
stopRead();
|
||||
setTimeout(() => {
|
||||
startRead();
|
||||
}, 1000);
|
||||
}
|
||||
createLog("error", "rfid", "rfid", `There was an error Starting the read: ${error.response.data.message}`);
|
||||
}
|
||||
};
|
||||
const stopRead = async () => {
|
||||
try {
|
||||
const res = await axios.put(
|
||||
`https://${ip}/cloud/stop`,
|
||||
{},
|
||||
{
|
||||
headers: {Authorization: `Bearer ${token}`},
|
||||
}
|
||||
);
|
||||
} catch (error: any) {
|
||||
createLog("error", "rfid", "rfid", `There was an error Stopping the read: ${error.response.data.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
60
server/services/rfid/controller/readerControl.ts
Normal file
60
server/services/rfid/controller/readerControl.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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 {db} from "../../../../database/dbclient.js";
|
||||
import {rfidReaders} from "../../../../database/schema/rfidReaders.js";
|
||||
import {createLog} from "../../logger/logger.js";
|
||||
|
||||
export const newHeartBeat = async (reader: string) => {
|
||||
/**
|
||||
* When a heat beat is sent over for a reader we want to update the reader.
|
||||
*/
|
||||
|
||||
try {
|
||||
const heatBeat = await db
|
||||
.update(rfidReaders)
|
||||
.set({lastHeartBeat: sql`NOW()`})
|
||||
.where(eq(rfidReaders.reader, reader));
|
||||
createLog("info", "rfid", "rfid", `${reader} just updated its heatBeat.`);
|
||||
return {success: true, message: `${reader} just updated its heatBeat.`};
|
||||
} catch (error) {
|
||||
createLog("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}`};
|
||||
}
|
||||
};
|
||||
|
||||
export const badRead = async (reader: string) => {
|
||||
/**
|
||||
* When we have a bad read we want to make sure the reader shows this was well.
|
||||
*/
|
||||
try {
|
||||
const badRead = await db
|
||||
.update(rfidReaders)
|
||||
.set({lastTrigger: sql`NOW()`, lastTriggerGood: false})
|
||||
.where(eq(rfidReaders.reader, reader));
|
||||
createLog("info", "rfid", "rfid", `${reader} just Triggered a bad read.`);
|
||||
return {success: true, message: `${reader} just Triggered a bad read.`};
|
||||
} catch (error) {
|
||||
createLog("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}`};
|
||||
}
|
||||
};
|
||||
|
||||
export const goodRead = async (reader: string) => {
|
||||
/**
|
||||
* When we have a bad read we want to make sure the reader shows this was well.
|
||||
*/
|
||||
try {
|
||||
const goodRead = await db
|
||||
.update(rfidReaders)
|
||||
.set({lastTrigger: sql`NOW()`, lastTriggerGood: true})
|
||||
.where(eq(rfidReaders.reader, reader));
|
||||
createLog("info", "rfid", "rfid", `${reader} just Triggered a good read.`);
|
||||
return {success: true, message: `${reader} just Triggered a good read.`};
|
||||
} catch (error) {
|
||||
createLog("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}`};
|
||||
}
|
||||
};
|
||||
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* Phase 1 we link the tag to the line only the line3.x where x is the line number
|
||||
* Phase 2 we will generate a label to be reprinted at staion 4
|
||||
*/
|
||||
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* Phase 1 we will just follow the logic of printing a label when we are told requested to based on this tag.
|
||||
* Phase 2 we will just reprint the tag that was generated at the line
|
||||
*/
|
||||
27
server/services/rfid/controller/stations/station3.ts
Normal file
27
server/services/rfid/controller/stations/station3.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Phase 1 we link the tag to the line only the line3.x where x is the line number
|
||||
* Phase 2 we will generate a label to be reprinted at staion 4
|
||||
*/
|
||||
|
||||
import {createLog} from "../../../logger/logger.js";
|
||||
import type {TagData} from "../tagData.js";
|
||||
import {tagStuff} from "../tags/crudTag.js";
|
||||
|
||||
export const station3Tags = async (tagData: TagData[]) => {
|
||||
// make sure we only have one tag or dont update
|
||||
if (tagData.length != 1) {
|
||||
createLog(
|
||||
"error",
|
||||
"rfid",
|
||||
"rfid",
|
||||
`There are ${tagData.length} tags, and ${tagData[0].reader} only allows 1 tag to create a label.`
|
||||
);
|
||||
// get tag data
|
||||
tagStuff(tagData);
|
||||
} else {
|
||||
//console.log("Generate the label and link it to the tag.");
|
||||
const tagdata = await tagStuff(tagData);
|
||||
|
||||
createLog("info", "rfid", "rfid", "Generate a label and link it to this tag.");
|
||||
}
|
||||
};
|
||||
43
server/services/rfid/controller/stations/wrappers.ts
Normal file
43
server/services/rfid/controller/stations/wrappers.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Phase 1 we will just follow the logic of printing a label when we are told requested to based on this tag.
|
||||
* Phase 2 we will just reprint the tag that was generated at the line
|
||||
*/
|
||||
|
||||
import {createLog} from "../../../logger/logger.js";
|
||||
import type {TagData} from "../tagData.js";
|
||||
import {tagStuff} from "../tags/crudTag.js";
|
||||
|
||||
export const wrapperStuff = async (tagData: TagData[]) => {
|
||||
if (tagData.length != 1) {
|
||||
createLog(
|
||||
"error",
|
||||
"rfid",
|
||||
"rfid",
|
||||
`There are ${tagData.length} tags and this ${tagData[0].reader} only allows 1 tag to create a label.`
|
||||
);
|
||||
tagStuff(tagData);
|
||||
} else {
|
||||
const tagdata = await tagStuff(tagData);
|
||||
|
||||
/**
|
||||
* we want to make sure this pallet came from a line as its last spot if not we need to have a manual check.
|
||||
*/
|
||||
const station3 = tagdata.some((n: any) => n.lastareaIn.includes("line3"));
|
||||
|
||||
if (!station3) {
|
||||
createLog(
|
||||
"error",
|
||||
"rfid",
|
||||
"rfid",
|
||||
`${tagdata.tag}, Did not come from a line please check the pallet and manually print the label.`
|
||||
);
|
||||
}
|
||||
|
||||
// check if a running number exists
|
||||
if (station3.runningNumber) {
|
||||
createLog("info", "rfid", "rfid", `Reprint label ${station3.runningNumber}`);
|
||||
} else {
|
||||
createLog("info", "rfid", "rfid", `A new labels will be created and linked to this ${tagdata.tag} tag`);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,4 +1,14 @@
|
||||
type TagData = {tagHex: string; reader: string; tag: string; timeStamp: Date};
|
||||
import {station3Tags} from "./stations/station3.js";
|
||||
import {wrapperStuff} from "./stations/wrappers.js";
|
||||
|
||||
export type TagData = {
|
||||
tagHex: string;
|
||||
reader: string;
|
||||
tag: string;
|
||||
timeStamp: Date;
|
||||
antenna: number;
|
||||
tagStrength: number;
|
||||
};
|
||||
export const tagData = async (data: TagData[]) => {
|
||||
/**
|
||||
* We will always update a tag
|
||||
@@ -14,7 +24,7 @@ export const tagData = async (data: TagData[]) => {
|
||||
const station3 = data.some((n) => n.reader.includes("line3"));
|
||||
|
||||
// at the wrapper
|
||||
const station4 = data.some((n) => n.reader.includes("wrapper"));
|
||||
const wrappers = data.some((n) => n.reader.includes("wrapper"));
|
||||
|
||||
// station checks
|
||||
if (station1 && data.length != 10) {
|
||||
@@ -26,23 +36,10 @@ export const tagData = async (data: TagData[]) => {
|
||||
}
|
||||
|
||||
if (station3) {
|
||||
// make sure we only have one tag or dont update
|
||||
if (data.length != 1) {
|
||||
console.log(`There are ${data.length} tags, and ${data[0].reader} only allows 1 tag to create a label.`);
|
||||
//throw new Error("There are more than 1 tag at this station and it is not allowed");
|
||||
} else {
|
||||
console.log("Generate the tag and link it to the tag.");
|
||||
}
|
||||
station3Tags(data);
|
||||
}
|
||||
|
||||
if (station4) {
|
||||
if (data.length != 1) {
|
||||
console.log(
|
||||
`There are ${data.length} tags and this ${data[0].reader} only allows 1 tag to create a label.`
|
||||
);
|
||||
//throw new Error("There are more than 1 tag at this station and it is not allowed");
|
||||
} else {
|
||||
console.log("reprint the label linked to the tag.");
|
||||
}
|
||||
if (wrappers) {
|
||||
wrapperStuff(data);
|
||||
}
|
||||
};
|
||||
|
||||
87
server/services/rfid/controller/tags/crudTag.ts
Normal file
87
server/services/rfid/controller/tags/crudTag.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import {eq} from "drizzle-orm";
|
||||
import {db} from "../../../../../database/dbclient.js";
|
||||
import {rfidTags} from "../../../../../database/schema/rfidTags.js";
|
||||
import type {TagData} from "../tagData.js";
|
||||
import {createLog} from "../../../logger/logger.js";
|
||||
|
||||
type ReturnTag = {
|
||||
success: boolean;
|
||||
tag: any;
|
||||
error: any;
|
||||
};
|
||||
export const tagStuff = async (tagData: TagData[]): Promise<any> => {
|
||||
const tags = await db.select().from(rfidTags);
|
||||
|
||||
// look through each tag and either add it to the db or update the area and other relevent data.
|
||||
for (let i = 0; i < tagData.length; i++) {
|
||||
// check if the tag already exists
|
||||
const tag = tags.filter((n) => n.tagHex === tagData[i].tagHex);
|
||||
if (tag.length === 0) {
|
||||
// add new tag
|
||||
const newTag = {
|
||||
tagHex: tagData[i].tagHex,
|
||||
tag: tagData[i].tag,
|
||||
lastRead: new Date(tagData[i].timeStamp),
|
||||
counts: [{area: tagData[i].reader, timesHere: 1}], //jsonb("counts").notNull(), //.default([{area: 1, timesHere: 5}]).notNull(),
|
||||
lastareaIn: tagData[i].reader,
|
||||
antenna: tagData[i].antenna,
|
||||
tagStrength: tagData[i].tagStrength,
|
||||
};
|
||||
try {
|
||||
// insert the tag with the onConflict update the tag
|
||||
const tag = await db.insert(rfidTags).values(newTag).returning({
|
||||
tag: rfidTags.tag,
|
||||
runningNumber: rfidTags.runningNumber,
|
||||
counts: rfidTags.counts,
|
||||
lastareaIn: rfidTags.lastareaIn,
|
||||
});
|
||||
createLog("info", "rfid", "rfid", `Tags were jusdt updated.`);
|
||||
return {success: true, tag};
|
||||
} catch (error) {
|
||||
createLog("error", "rfid", "rfid", `${JSON.stringify(error)}`);
|
||||
return {success: false, error};
|
||||
}
|
||||
} else {
|
||||
// update tag
|
||||
//console.log("Updating existing tag");
|
||||
// make sure we actually have an array here
|
||||
const countsArray = (tag[0]?.counts as {area: string; timesHere: number}[]) ?? [];
|
||||
|
||||
// check if the reader exists on the array
|
||||
const areaExists = countsArray.some((t) => t.area === tagData[0].reader);
|
||||
|
||||
// run the update on the array
|
||||
const updateCount = areaExists
|
||||
? countsArray.map((t) => {
|
||||
if (t.area === tagData[0].reader) {
|
||||
return {...t, timesHere: t.timesHere + 1};
|
||||
} else {
|
||||
return {...t, area: tagData[i].reader, timesHere: 1};
|
||||
}
|
||||
})
|
||||
: [...countsArray, {area: tagData[i].reader, timesHere: 1}];
|
||||
|
||||
const updateTag = {
|
||||
lastRead: new Date(tagData[i].timeStamp),
|
||||
counts: updateCount, //jsonb("counts").notNull(), //.default([{area: 1, timesHere: 5}]).notNull(),
|
||||
lastareaIn: tagData[i].reader,
|
||||
antenna: tagData[i].antenna,
|
||||
tagStrength: tagData[i].tagStrength,
|
||||
};
|
||||
|
||||
try {
|
||||
await db.update(rfidTags).set(updateTag).where(eq(rfidTags.tagHex, tagData[0].tagHex)).returning({
|
||||
tag: rfidTags.tag,
|
||||
runningNumber: rfidTags.runningNumber,
|
||||
counts: rfidTags.counts,
|
||||
lastareaIn: rfidTags.lastareaIn,
|
||||
});
|
||||
createLog("info", "rfid", "rfid", `Tags were jusdt updated.`);
|
||||
return {success: true, tag};
|
||||
} catch (error) {
|
||||
createLog("error", "rfid", "rfid", `${JSON.stringify(error)}`);
|
||||
return {success: false, error};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -2,13 +2,12 @@ import {OpenAPIHono} from "@hono/zod-openapi";
|
||||
|
||||
import mgtEvents from "./route/mgtEvents.js";
|
||||
import tagInfo from "./route/tagInfo.js";
|
||||
import addReader from "./route/addReader.js";
|
||||
import updateReader from "./route/updateReader.js";
|
||||
import manualTrigger from "./route/manualTagRead.js";
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
const routes = [
|
||||
mgtEvents,
|
||||
tagInfo,
|
||||
// settings
|
||||
] as const;
|
||||
const routes = [mgtEvents, tagInfo, addReader, updateReader, manualTrigger] as const;
|
||||
|
||||
// app.route("/server", modules);
|
||||
const appRoutes = routes.forEach((route) => {
|
||||
|
||||
51
server/services/rfid/route/addReader.ts
Normal file
51
server/services/rfid/route/addReader.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi";
|
||||
import {addReader} from "../controller/addReader.js";
|
||||
import {authMiddleware} from "../../auth/middleware/authMiddleware.js";
|
||||
import {responses} from "../../../globalUtils/routeDefs/responses.js";
|
||||
import type {User} from "../../../types/users.js";
|
||||
import {verify} from "hono/jwt";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
export const ReaderBody = z.object({
|
||||
reader: z.string().openapi({example: "wrapper1"}),
|
||||
readerIP: z.string().openapi({example: "192.168.1.52"}),
|
||||
});
|
||||
|
||||
app.openapi(
|
||||
createRoute({
|
||||
tags: ["rfid"],
|
||||
summary: "Add new reader",
|
||||
method: "post",
|
||||
path: "/addreader",
|
||||
middleware: authMiddleware,
|
||||
description: "Adding in a new reader to add to the network.",
|
||||
request: {
|
||||
body: {content: {"application/json": {schema: ReaderBody}}},
|
||||
},
|
||||
responses: responses(),
|
||||
}),
|
||||
async (c) => {
|
||||
const body = await c.req.json();
|
||||
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) {
|
||||
return c.json({message: "Unauthorized"}, 401);
|
||||
}
|
||||
|
||||
try {
|
||||
const addingReader = await addReader(body, user);
|
||||
return c.json({success: addingReader.success, message: addingReader.message}, 200);
|
||||
} catch (error) {
|
||||
return c.json({success: false, message: `${body.name} encountered an error while trying to be added`}, 400);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export default app;
|
||||
40
server/services/rfid/route/manualTagRead.ts
Normal file
40
server/services/rfid/route/manualTagRead.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
//http://usday1vms006:4000/api/v1/zebra/wrapper1
|
||||
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi";
|
||||
import {responses} from "../../../globalUtils/routeDefs/responses.js";
|
||||
import {readTags} from "../controller/readTags.js";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
const ParamsSchema = z.object({
|
||||
reader: z
|
||||
.string()
|
||||
.min(3)
|
||||
.openapi({
|
||||
param: {
|
||||
name: "reader",
|
||||
in: "path",
|
||||
},
|
||||
example: "1212121",
|
||||
}),
|
||||
});
|
||||
|
||||
app.openapi(
|
||||
createRoute({
|
||||
tags: ["rfid"],
|
||||
summary: "Manual triggers the read function",
|
||||
method: "post",
|
||||
path: "/manualtrigger/{reader}",
|
||||
request: {
|
||||
params: ParamsSchema,
|
||||
},
|
||||
responses: responses(),
|
||||
}),
|
||||
async (c) => {
|
||||
const {reader} = c.req.valid("param");
|
||||
const manualTrigger = await readTags(reader);
|
||||
|
||||
return c.json({success: true, message: `A Manaul trigger was done on ${reader}`}, 200);
|
||||
}
|
||||
);
|
||||
|
||||
export default app;
|
||||
@@ -2,12 +2,8 @@
|
||||
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi";
|
||||
import {readTags} from "../controller/readTags.js";
|
||||
import {createLog} from "../../logger/logger.js";
|
||||
|
||||
// Define the response schema
|
||||
const responseSchema = z.object({
|
||||
success: z.boolean().openapi({example: true}),
|
||||
message: z.string().optional(),
|
||||
});
|
||||
import {responses} from "../../../globalUtils/routeDefs/responses.js";
|
||||
import {newHeartBeat} from "../controller/readerControl.js";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
let lastGpiTimestamp = 0;
|
||||
@@ -28,64 +24,37 @@ const ParamsSchema = z.object({
|
||||
app.openapi(
|
||||
createRoute({
|
||||
tags: ["rfid"],
|
||||
summary: "Adds a new module",
|
||||
summary: "Post info from the reader",
|
||||
method: "post",
|
||||
path: "/mgtevents/{reader}",
|
||||
request: {
|
||||
params: ParamsSchema,
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": {schema: responseSchema},
|
||||
},
|
||||
description: "Response message",
|
||||
},
|
||||
400: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
|
||||
},
|
||||
},
|
||||
description: "Internal Server Error",
|
||||
},
|
||||
401: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
|
||||
},
|
||||
},
|
||||
description: "Unauthorized",
|
||||
},
|
||||
500: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
|
||||
},
|
||||
},
|
||||
description: "Internal Server Error",
|
||||
},
|
||||
},
|
||||
responses: responses(),
|
||||
}),
|
||||
async (c) => {
|
||||
const {reader} = c.req.valid("param");
|
||||
const body = await c.req.json();
|
||||
|
||||
if (body.type === "heartbeat") {
|
||||
console.log("Heartbeat");
|
||||
const heart = await newHeartBeat(reader);
|
||||
return c.json({success: heart.success, message: heart.message}, 200);
|
||||
}
|
||||
|
||||
if (body.type === "gpi" && body.data.state === "HIGH") {
|
||||
const eventTimestamp = new Date(body.timestamp).getTime(); // Convert ISO timestamp to milliseconds
|
||||
|
||||
if (eventTimestamp - lastGpiTimestamp > 10) {
|
||||
if (eventTimestamp - lastGpiTimestamp > 5 * 1000) {
|
||||
// Check if it's been more than 2ms
|
||||
lastGpiTimestamp = eventTimestamp; // Update last seen timestamp
|
||||
|
||||
createLog("info", "rfid", "rfid", `${reader} is reading a tag.`);
|
||||
readTags(reader);
|
||||
await readTags(reader);
|
||||
} else {
|
||||
console.log("Duplicate GPI event ignored.");
|
||||
createLog("info", "rfid", "rfid", `A new trigger from ${reader} was to soon`);
|
||||
lastGpiTimestamp = eventTimestamp;
|
||||
}
|
||||
|
||||
//console.log(body);
|
||||
}
|
||||
|
||||
return c.json({success: true, message: `New info from ${reader}`}, 200);
|
||||
|
||||
@@ -2,12 +2,9 @@
|
||||
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi";
|
||||
import {ConsoleLogWriter} from "drizzle-orm";
|
||||
import {tagData} from "../controller/tagData.js";
|
||||
|
||||
// Define the response schema
|
||||
const responseSchema = z.object({
|
||||
success: z.boolean().openapi({example: true}),
|
||||
message: z.string().optional(),
|
||||
});
|
||||
import {responses} from "../../../globalUtils/routeDefs/responses.js";
|
||||
import {noRead} from "../controller/noRead.js";
|
||||
import {badRead, goodRead} from "../controller/readerControl.js";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
@@ -27,44 +24,13 @@ const ParamsSchema = z.object({
|
||||
app.openapi(
|
||||
createRoute({
|
||||
tags: ["rfid"],
|
||||
summary: "Adds a new module",
|
||||
summary: "Tag info posted from the reader.",
|
||||
method: "post",
|
||||
path: "/taginfo/{reader}",
|
||||
request: {
|
||||
params: ParamsSchema,
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": {schema: responseSchema},
|
||||
},
|
||||
description: "Response message",
|
||||
},
|
||||
400: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
|
||||
},
|
||||
},
|
||||
description: "Internal Server Error",
|
||||
},
|
||||
401: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({message: z.string().optional().openapi({example: "Unauthenticated"})}),
|
||||
},
|
||||
},
|
||||
description: "Unauthorized",
|
||||
},
|
||||
500: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({message: z.string().optional().openapi({example: "Internal Server error"})}),
|
||||
},
|
||||
},
|
||||
description: "Internal Server Error",
|
||||
},
|
||||
},
|
||||
responses: responses(),
|
||||
}),
|
||||
async (c) => {
|
||||
const {reader} = c.req.valid("param");
|
||||
@@ -74,17 +40,31 @@ app.openapi(
|
||||
|
||||
for (let i = 0; i < body.length; i++) {
|
||||
const tag = Buffer.from(body[i].data.idHex, "hex").toString("utf-8");
|
||||
if (tag.includes("ALPLA")) {
|
||||
//console.log("Raw value:", body[i].data.peakRssi, "Parsed:", parseInt(body[i].data.peakRssi));
|
||||
if (tag.includes("ALPLA") && parseInt(body[i].data.peakRssi) < -50) {
|
||||
tagdata = [
|
||||
...tagdata,
|
||||
{tagHex: body[i].data.idHex, reader: reader, tag: tag, timeStamp: body[i].timestamp},
|
||||
{
|
||||
tagHex: body[i].data.idHex,
|
||||
reader: reader,
|
||||
tag: tag,
|
||||
timeStamp: body[i].timestamp,
|
||||
antenna: body[i].data.antenna,
|
||||
tagStrength: body[i].data.peakRssi,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
tagData(tagdata);
|
||||
|
||||
return c.json({success: true, message: `New info from ${reader}`}, 200);
|
||||
if (tagdata.length === 0) {
|
||||
noRead(reader);
|
||||
badRead(reader);
|
||||
return c.json({success: false, message: `There were no tags scanned.`}, 200);
|
||||
} else {
|
||||
tagData(tagdata);
|
||||
goodRead(reader);
|
||||
return c.json({success: true, message: `New info from ${reader}`}, 200);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
52
server/services/rfid/route/updateReader.ts
Normal file
52
server/services/rfid/route/updateReader.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi";
|
||||
import {addReader} from "../controller/addReader.js";
|
||||
import {authMiddleware} from "../../auth/middleware/authMiddleware.js";
|
||||
import {responses} from "../../../globalUtils/routeDefs/responses.js";
|
||||
import type {User} from "../../../types/users.js";
|
||||
import {verify} from "hono/jwt";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
export const ReaderBody = z.object({
|
||||
reader: z.string().openapi({example: "wrapper1"}),
|
||||
readerIP: z.string().openapi({example: "192.168.1.52"}),
|
||||
active: z.boolean().optional().openapi({example: true}),
|
||||
});
|
||||
|
||||
app.openapi(
|
||||
createRoute({
|
||||
tags: ["rfid"],
|
||||
summary: "Add new reader",
|
||||
method: "patch",
|
||||
path: "/updatereader",
|
||||
middleware: authMiddleware,
|
||||
description: "Updates the reader data..",
|
||||
request: {
|
||||
body: {content: {"application/json": {schema: ReaderBody}}},
|
||||
},
|
||||
responses: responses(),
|
||||
}),
|
||||
async (c) => {
|
||||
const body = await c.req.json();
|
||||
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) {
|
||||
return c.json({message: "Unauthorized"}, 401);
|
||||
}
|
||||
|
||||
try {
|
||||
const addingReader = await addReader(body, user);
|
||||
return c.json({success: addingReader.success, message: addingReader.message}, 200);
|
||||
} catch (error) {
|
||||
return c.json({success: false, message: `${body.name} encountered an error while trying to be added`}, 400);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export default app;
|
||||
Reference in New Issue
Block a user