first commit

This commit is contained in:
Alex Moreno 2023-01-24 10:11:58 +01:00
commit a7a39efe49
18 changed files with 5097 additions and 0 deletions

32
.eslintrc.yml Normal file
View File

@ -0,0 +1,32 @@
extends: [eslint:recommended, google]
parserOptions:
ecmaVersion: 2021
sourceType: "module"
rules:
require-jsdoc: 0
no-undef: 0
max-len: 0
eqeqeq: 0
operator-linebreak: 0
radix: 0
guard-for-in: 0
camelcase: 0
default-case: 0
no-eq-null: 0
no-console: 0
no-warning-comments: 0
no-empty: [error, allowEmptyCatch: true]
complexity: 0
max-depth: 0
comma-dangle: 0
bracketSpacing: 0
space-infix-ops: 1
no-invalid-this: 0
space-before-function-paren: [error, never]
prefer-const: 0
curly: [error, multi-or-nest]
indent: [error, 4]
arrow-parens: [error, as-needed]
no-multiple-empty-lines: ["error", { "max": 1, "maxEOF": 1 }]
space-in-parens: ["error", "never"]
arrow-spacing: ["error", { "before": true, "after": true }]

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
config.local.yml

17
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,17 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "attach",
"name": "Attach",
"restart": true,
"timeout": 50000
}, {
"type": "node",
"request": "attach",
"name": "Attach by process ID",
"processId": "${command:PickProcess}"
}
]
}

8
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,8 @@
// Coloque su configuración en este archivo para sobrescribir la configuración predeterminada y de usuario.
{
// Carácter predeterminado de final de línea.
"files.eol": "\n",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}

8
Dockerfile Normal file
View File

@ -0,0 +1,8 @@
FROM node
WORKDIR /app
COPY package.json ./
RUN npm install
COPY db db
COPY src src
COPY server.js ./
CMD ["node", "server.js"]

65
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,65 @@
#!/usr/bin/env groovy
pipeline {
agent any
options {
disableConcurrentBuilds()
}
environment {
PROJECT_NAME = 'vn-rfid'
STACK_NAME = "${env.PROJECT_NAME}-${env.BRANCH_NAME}"
}
stages {
stage('Checkout') {
steps {
script {
switch (env.BRANCH_NAME) {
case 'master':
env.NODE_ENV = 'production'
break
}
}
setEnv()
}
}
stage('Build') {
when { anyOf {
branch 'master'
}}
environment {
CREDENTIALS = credentials('docker-registry')
}
steps {
dockerBuild()
}
}
stage('Deploy') {
when { anyOf {
branch 'master'
}}
environment {
DOCKER_HOST = "${env.SWARM_HOST}"
}
steps {
sh "docker stack deploy --with-registry-auth --compose-file docker-compose.yml ${env.STACK_NAME}"
}
}
}
post {
always {
script {
if (!env.COMMITTER_EMAIL || currentBuild.currentResult == 'SUCCESS') return;
try {
mail(
to: env.COMMITTER_EMAIL,
subject: "Pipeline: ${env.JOB_NAME} (${env.BUILD_NUMBER}): ${currentBuild.currentResult}",
body: "Check status at ${env.BUILD_URL}"
)
} catch (e) {
echo e.toString()
}
}
}
}
}

18
README.md Normal file
View File

@ -0,0 +1,18 @@
## Getting Started // Installing
Pull from repository.
Run this commands on project root directory to install Node dependencies.
```
$ npm install
```
Launch application in developer environment.
```
$ npm run start
```
For test.
```
DELETE expedition in vn.expeditionScan
```

99
backup/OLDinsertRFIDs.js Normal file
View File

@ -0,0 +1,99 @@
const config = require('../config');
const express = require('express');
const router = express.Router(); // eslint-disable-line
const got = require('got');
const con = require('../db/connect');
// Obtenemos los parametros
router.get('/:truckFk', async(req, res) => {
const ip = config.ip;
const truckFk = req.params.truckFk;
let bufferTime = [];
let bufferEpcHex = [];
let interval;
let jsonMessage;
console.log('--START BACKEND--');
const stream = await got.stream(`http://${ip}/api/v1/data/stream`);
stream
.on('data', value => {
// value = '{"timestamp":"2022-07-27T11:57:39.226680176Z","tagInventoryEvent":{"epc":"qrsAAAAAAAAFdgQg","epcHex":"AABB00000000000005760420","pc":"MAA=","antennaPort":4,"antennaName":"4","peakRssiCdbm":-7600,"lastSeenTime":"2022-07-27T11:57:39.041444Z","phaseAngle":46.05}}'
let buffer = value.toString();
buffer = buffer.split('\n');
for (let result of buffer) {
if (result && /{.*:{.*:.*}}/.test(result)) {
const jsonResult = JSON.parse(result);
let epcHex = jsonResult?.tagInventoryEvent?.epcHex;
if (!epcHex) return;
if (epcHex.search('AABB') == -1) return;
// console.log(epcHex)
epcHex = epcHex.replace('AABB', '');
const existEpcHex = element => element == epcHex;
const bufferIndex = bufferEpcHex.findIndex(existEpcHex);
if (bufferIndex >= 0)
return bufferTime[bufferIndex].count = bufferTime[bufferIndex].count + 1;
const newObject = {
code: epcHex,
created: jsonResult.timestamp,
peakRssi: jsonResult.tagInventoryEvent.peakRssiCdbm,
count: 1
};
bufferEpcHex.push(epcHex);
bufferTime.push(newObject);
if (interval) {
clearInterval(interval);
interval = null;
}
interval = setInterval(insertDB, 5000, truckFk);
}
}
})
.on('close', () => {
console.log('CLOSE_STREAM');
});
async function insertDB(truckFk) {
clearInterval(interval);
stream.destroy();
interval = null;
console.log('--INSERT IN DB--');
console.log(bufferEpcHex, bufferTime, truckFk);
const rfids = [];
let response;
for (let code of bufferEpcHex) {
while (code.substring(0, 1) == 0)
code = code.substring(1);
rfids.push(code);
}
console.log('rfids', rfids.join(','));
if (rfids.length)
[response] = await con.query(`CALL vn.palletBuilding(?,?);`, [rfids.join(','), truckFk]);
console.log(response);
console.log(response[0]);
console.log(response[0][0]);
console.log(response[0][0]?.palletFk);
bufferTime = [];
bufferEpcHex = [];
const pallet = response[0][0]?.palletFk;
if (pallet) {
const print = await con.query(`CALL vn.expeditionPallet_printLabel(?);`, [pallet]);
console.log('print', print);
jsonMessage = {pallet: pallet, print: print};
stream.destroy();
return res.json(jsonMessage);
}
return res.json({error: 'ERROR_CREATING_PALLET'});
}
});
module.exports = router;

124
backup/insertRFIDs2.js Normal file
View File

@ -0,0 +1,124 @@
const config = require('../config');
const got = require('got');
const con = require('../db/connect');
module.exports = async() => {
const ip = config.ip;
let bufferTime = [];
let bufferEpcHex = [];
let interval;
let jsonMessage;
console.log('--START BACKEND--');
const stream = await got.stream(`http://${ip}/api/v1/data/stream`);
stream
.on('data', value => {
// value = '{"timestamp":"2022-07-27T11:57:39.226680176Z","tagInventoryEvent":{"epc":"qrsAAAAAAAAFdgQg","epcHex":"AABB00000000000005760420","pc":"MAA=","antennaPort":4,"antennaName":"4","peakRssiCdbm":-7600,"lastSeenTime":"2022-07-27T11:57:39.041444Z","phaseAngle":46.05}}'
let buffer = value.toString();
buffer = buffer.split('\n');
for (let result of buffer) {
if (result && /{.*:{.*:.*}}/.test(result)) {
const jsonResult = JSON.parse(result);
let epcHex = jsonResult?.tagInventoryEvent?.epcHex;
if (!epcHex) return;
if (epcHex.search('AABB') == -1) return;
// console.log(epcHex)
epcHex = epcHex.replace('AABB', '');
const existEpcHex = element => element == epcHex;
const bufferIndex = bufferEpcHex.findIndex(existEpcHex);
if (bufferIndex >= 0)
return bufferTime[bufferIndex].count = bufferTime[bufferIndex].count + 1;
const newObject = {
code: epcHex,
created: jsonResult.timestamp,
peakRssi: jsonResult.tagInventoryEvent.peakRssiCdbm,
count: 1
};
bufferEpcHex.push(epcHex);
bufferTime.push(newObject);
insertLog(bufferTime);
if (interval) {
clearInterval(interval);
interval = null;
}
interval = setInterval(insertDB, 10000);
}
}
});
/* .on("close", () => {
console.log('CLOSE_STREAM')
})*/
async function insertDB() {
clearInterval(interval);
interval = null;
// console.log('--INSERT IN DB--');
// console.log(bufferEpcHex, bufferTime);
let rfids = [];
let response;
for (let code of bufferEpcHex) {
while (code.substring(0, 1) == 0)
code = code.substring(1);
rfids.push(parseInt(code));
}
// console.log('rfids', rfids)
rfids = await cleanDev(rfids);
if (!rfids.length) return console.log({error: 'NOT_PARSED_RFIDS', rfids});
// response = await con.query(`CALL vn.pallet_build(JSON_ARRAY(?),?,@pallet);SELECT @pallet;`, params);
response = await con.query(`CALL vn.pallet_build(JSON_ARRAY(?), ?, @pallet);SELECT @pallet;`, [rfids, 19294]);
console.log(response);
console.log(response[0][1][0]['@pallet']);
// console.log(response)
// console.log(response[1]);
bufferTime = [];
bufferEpcHex = [];
const pallet = response[0][1][0]['@pallet'];
if (pallet) {
console.log('CALL TO PRINT');
const print = await con.query(`CALL vn.expeditionPallet_printLabel(?);`, [pallet]);
// console.log('print', print)
jsonMessage = {pallet: pallet, print: print};
// stream.destroy();
console.log(jsonMessage);
} else
console.log({error: 'ERROR_CREATING_PALLET', expeditions: rfids});
}
async function insertLog() {
const sql = `INSERT INTO lastRFID (code, antennaFk, isConsulted, isChoosed, antennaPort, peakRssi, seenCount)
VALUES(?, 5, 1, 0, 1, ?, ?);`;
for (let rfid of bufferTime) {
const response = await con.query(sql, [rfid.code, rfid.peakRssi, rfid.count]);
// console.log('insertLog', response, [rfid.code, rfid.peakRssi, rfid.count])
}
}
async function cleanDev(ids) {
if (config.env != 'dev') return ids;
const sql = `SELECT id FROM vn.expedition WHERE id = ?`;
const idsCleaned = [];
for (let id of ids) {
const [response] = await con.query(sql, [id]);
console.log('cleanDev', response);
if (response.length > 0)
idsCleaned.push(id);
}
return idsCleaned;
}
};

13
config.yml Normal file
View File

@ -0,0 +1,13 @@
port: 1234
ip: 1.2.3.4
env: dev
interval: 1000
reconnectInterval: 5000
db:
host: host
port: 3307
database: srt
user: user
password: password
multipleStatements: true
insecureAuth: true

13
db/connect.js Normal file
View File

@ -0,0 +1,13 @@
import mysql from 'mysql2/promise';
import yml from 'require-yml';
import path from 'path';
import fs from 'fs-extra';
const {pathname: root} = new URL('../', import.meta.url);
let conf = yml(path.join(root, 'config.yml'));
const localConfFile = path.join(root, 'config.local.yml');
if (fs.existsSync(localConfFile))
conf = Object.assign({}, conf, yml(localConfFile));
export default mysql.createPool(conf.db);

20
docker-compose.yml Normal file
View File

@ -0,0 +1,20 @@
version: '3.7'
services:
main:
image: registry.verdnatura.es/vn-rfid:${BRANCH_NAME:?}
build:
context: .
dockerfile: Dockerfile
ports:
- 8888
configs:
- source: config
target: /app/config.local.yml
deploy:
placement:
constraints:
- node.role == worker
configs:
config:
external: true
name: vn-rfid_config

4517
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

25
package.json Normal file
View File

@ -0,0 +1,25 @@
{
"name": "vn-rfid",
"version": "1.0.0",
"author": "Verdnatura Levante SL",
"description": "rfid backend",
"main": "index.js",
"type": "module",
"scripts": {
"start": "nodemon ./server.js"
},
"keywords": [],
"license": "GPL-3.0",
"dependencies": {
"eslint": "^7.22.0",
"eslint-config-google": "^0.14.0",
"express": "^4.17.1",
"fs-extra": "^11.1.0",
"got": "^11.8.2",
"ip": "^1.1.5",
"mysql2": "^2.3.3",
"mysql2-promise": "^0.1.4",
"nodemon": "^2.0.20",
"require-yml": "^2.0.0"
}
}

22
server.js Normal file
View File

@ -0,0 +1,22 @@
import stream from './src/stream.js';
import yml from 'require-yml';
import path from 'path';
import fs from 'fs-extra';
function main() {
const {pathname: root} = new URL('./', import.meta.url);
let conf = yml(path.join(root, 'config.yml'));
const localConfFile = path.join(root, 'config.local.yml');
if (fs.existsSync(localConfFile))
conf = Object.assign({}, conf, yml(localConfFile));
try {
stream(conf);
} catch (e) {
// Not working
setTimeout(main(), conf.reconnectInterval);
console.log('MAIN_ERROR', e);
}
}
main();

22
src/newPallet.js Normal file
View File

@ -0,0 +1,22 @@
import con from '../db/connect.js';
export default async rfids => {
let response;
if (!rfids.length) return console.log({error: 'NOT_PARSED_RFIDS', rfids});
const codes = new Set();
for (let rfid of rfids)
codes.add(parseInt(rfid.code));
console.log('CALL PALLET_BUILD', codes, ' TOTAL: ', codes.size);
response = await con.query(`CALL vn.expeditionPallet_build(JSON_ARRAY(?), ?, @pallet);SELECT @pallet;`, [Array.from(codes), 19294]);
const pallet = response[0][1][0]['@pallet'];
if (pallet) {
console.log('PRINTING', pallet);
await con.query(`CALL vn.expeditionPallet_printLabel(?);`, [pallet]);
} else
console.log({error: 'ERROR_CREATING_PALLET', expeditions: rfids});
};

29
src/rfidParser.js Normal file
View File

@ -0,0 +1,29 @@
export default async data => {
data = data.toString();
const crudeRfids = data.split('\n');
const rfidsParsed = [];
for (let crudeRfid of crudeRfids) {
if (crudeRfid && /{.*:{.*:.*}}/.test(crudeRfid)) {
const jsonResult = JSON.parse(crudeRfid);
let epcHex = jsonResult?.tagInventoryEvent?.epcHex;
if (!epcHex) return;
if (epcHex.search('AABB') == -1) continue;
epcHex = epcHex.replace('AABB', '');
epcHex = epcHex.substring(0, 1) == 0 ? epcHex.substring(1) : epcHex;
const rfidParsed = {
code: parseInt(epcHex),
created: jsonResult.timestamp,
peakRssi: jsonResult.tagInventoryEvent.peakRssiCdbm,
count: 1,
antenna: jsonResult.tagInventoryEvent.antennaPort
};
rfidsParsed.push(rfidParsed);
}
}
return rfidsParsed;
};

63
src/stream.js Normal file
View File

@ -0,0 +1,63 @@
import got from 'got';
import rfidParser from './rfidParser.js';
import newPallet from './newPallet.js';
let interval;
export default async conf => {
let rfidbuffer = [];
let rfidbufferSet = [new Set(), new Set(), new Set(), new Set()];
const stream = got.stream(`http://${conf.ip}/api/v1/data/stream`);
stream
.on('data', async value => {
const parsed = await rfidParser(value);
if (parsed)
rfidbuffer = rfidbuffer.concat(parsed);
debug();
if (rfidbuffer && rfidbuffer.length && parsed && parsed.length) {
clearInterval(interval);
interval = null;
interval = setInterval(createPallet, conf.interval);
}
})
.on('error', e => {
throw new Error('ERROR_STREAM', e);
});
function createPallet() {
clearInterval(interval); // try remove
if (!rfidbuffer.length) return;
newPallet(rfidbuffer);
rfidbuffer = [];
rfidbufferSet = [new Set(), new Set(), new Set(), new Set()];
}
function debug() {
if (conf.env != 'dev') return;
let totalBuffer = rfidbuffer.map(rfid => rfid.code);
let totalBufferSet = new Set(totalBuffer);
console.log('TOTAL BUFFER: ', totalBufferSet.size);
const totalRead = [0, 0, 0, 0];
for (let buffer of rfidbuffer)
totalRead[buffer.antenna - 1]++;
console.log('TOTAL READ ANTENNA:', totalRead);
for (let buffer of parsed)
rfidbufferSet[buffer.antenna - 1].add(buffer.code);
console.log('UNIQUE READ ANTENNA:', rfidbufferSet[0].size, rfidbufferSet[1].size, rfidbufferSet[2].size, rfidbufferSet[3].size);
for (const [index, set] of rfidbufferSet.entries()) {
if (((set.size * 100) / totalBufferSet.size) < 25)
console.log('[WARNING_ANTENNA]: ', index, ' ONLY ', set.size);
}
console.log('----------------------------------------------------------------');
}
};
50;