Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

node-red-contrib-hikvision-ultimate

Package Overview
Dependencies
Maintainers
1
Versions
121
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-red-contrib-hikvision-ultimate - npm Package Compare versions

Comparing version 0.0.16 to 0.0.17

6

CHANGELOG.md

@@ -5,2 +5,8 @@ # node-red-contrib-hikvision-ultimate

<p>
<b>Version 0.0.17 BETA</b> December 2020<br/>
- BUGFIX: fixed a vaccata in handling boundary of stream pipeline.<br/>
- BUGFIX: fixed a minchiata in ANPR node, where if the alarmed zone was 0, the node outputs "unknown zone".<br/>
- Fixed Radar alarm zone. Zone number in ISAPI is base 0, while in the UI is base 1.<br/>
</p>
<p>
<b>Version 0.0.16 BETA</b> December 2020<br/>

@@ -7,0 +13,0 @@ - NEW: added Radar Node for trapping radar zone's alarms.<br/>

118

nodes/ANPR-config.js

@@ -21,3 +21,3 @@

function nextStatus(oClient) {
oClient.setNodeStatus({ fill: fill, shape: shape, text: text })
oClient.setNodeStatus({ fill: fill, shape: shape, text: text });
}

@@ -27,2 +27,19 @@ node.nodeClients.map(nextStatus);

// Sort the plates, in any case, even if the anpr camera returns a sorted list. It's not always true!
function sortPlates(a, b) {
try {
if (a.Plate.picName < b.Plate.picName) {
return -1;
}
if (a.Plate.picName > b.Plate.picName) {
return 1;
}
return 0;
} catch (error) {
return 0;
}
}
// Function to get the plate list from the camera

@@ -52,54 +69,64 @@ async function getPlates(_lastPicName) {

if (response.status >= 200 && response.status <= 300) {
node.setAllClientsStatus({ fill: "green", shape: "ring", text: "Connected." });
//node.setAllClientsStatus({ fill: "green", shape: "ring", text: "Connected." });
} else {
node.setAllClientsStatus({ fill: "red", shape: "ring", text: response.statusText });
// console.log("BANANA Error response " + response.statusText);
console.log("BANANA Error response " + response.statusText);
throw ("Error response: " + response.statusText);
}
//#region "BODY"
const body = await response.text();
var sRet = "";
sRet = body.toString();
//// console.log("BANANA " + sRet);
var oPlates = null;
try {
var i = sRet.indexOf("<"); // Get only the XML, starting with "<"
if (i > -1) {
sRet = sRet.substring(i);
// By xml2js
xml2js(sRet, function (err, result) {
oPlates = result;
});
} else {
i = sRet.indexOf("{") // It's a Json
if (response.ok) {
var body = "";
body = await response.text();
var sRet = body.toString();
console.log("BANANA ANPR: " + sRet);
var oPlates = null;
try {
var i = sRet.indexOf("<"); // Get only the XML, starting with "<"
if (i > -1) {
sRet = sRet.substring(i);
oPlates = JSON.parse(result);
// By xml2js
xml2js(sRet, function (err, result) {
oPlates = result;
});
} else {
// Invalid body
RED.log.info("ANPR-config: DecodingBody: Invalid Json " + sRet);
// console.log("BANANA ANPR-config: DecodingBody: Invalid Json " + sRet);
throw ("Error Invalid Json: " + sRet);
i = sRet.indexOf("{") // It's a Json
if (i > -1) {
sRet = sRet.substring(i);
oPlates = JSON.parse(result);
} else {
// Invalid body
RED.log.info("ANPR-config: DecodingBody: Invalid Json " + sRet);
// console.log("BANANA ANPR-config: DecodingBody: Invalid Json " + sRet);
throw ("Error Invalid Json: " + sRet);
}
}
}
// console.log("BANANA GIASONE " + JSON.stringify(oPlates));
// Working the plates. Must be sure, that no error occurs, before acknolwedging the plate last picName
if (oPlates.Plates !== null) {
node.setAllClientsStatus({ fill: "green", shape: "ring", text: "Waiting for vehicle..." });
if (!node.isConnected) {
node.nodeClients.forEach(oClient => {
oClient.sendPayload({ topic: oClient.topic || "", payload: null, connected: true });
})
// console.log("BANANA GIASONE " + JSON.stringify(oPlates));
// Working the plates. Must be sure, that no error occurs, before acknolwedging the plate last picName
if (oPlates.Plates !== null && oPlates.Plates !== undefined) {
if (!node.isConnected) {
node.nodeClients.forEach(oClient => {
oClient.sendPayload({ topic: oClient.topic || "", payload: null, connected: true });
})
}
node.isConnected = true;
//console.log("BANANA JSON PLATES: " + JSON.stringify(oPlates));
if (oPlates.Plates.hasOwnProperty("Plate")) {
// Returns a sorted list, always.
oPlates.Plates.Plate = oPlates.Plates.Plate.sort(sortPlates);
console.log("BANANA PLATES ORDINATE:" + JSON.stringify(oPlates));
return oPlates;
} else {
// Returns the object, empty.
return oPlates;
}
} else {
// Error in parsing XML
throw ("Error: oPlates.Plates is null");
}
node.isConnected = true;
return oPlates;
} else {
// Error in parsing XML
throw ("Error: oPlates.Plates is null");
} catch (error) {
RED.log.error("ANPR-config: ERRORE CATCHATO initPlateReader:" + error);
// console.log("BANANA ANPR-config: ERRORE CATCHATO initPlateReader: " + error);
throw ("Error initPlateReader: " + error);
}
} catch (error) {
RED.log.error("ANPR-config: ERRORE CATCHATO initPlateReader:" + error);
// console.log("BANANA ANPR-config: ERRORE CATCHATO initPlateReader: " + error);
throw ("Error initPlateReader: " + error);
}

@@ -130,5 +157,6 @@ //#endregion

node.initPlateReader = () => {
// console.log("BANANA INITPLATEREADER");
node.setAllClientsStatus({ fill: "grey", shape: "ring", text: "Getting prev list to be ignored..." });
(async () => {
//node.setAllClientsStatus({ fill: "grey", shape: "ring", text: "Getting prev list to be ignored..." });
(async () => {
var oPlates = await getPlates("202001010101010000");

@@ -142,2 +170,3 @@ if (oPlates === null) {

node.lastPicName = oPlates.Plates.Plate[oPlates.Plates.Plate.length - 1].picName;
console.log("BANANA PLATES IGNORATE: " + oPlates.Plates.Plate.length + " ignored plates. Last was " + node.lastPicName);
node.setAllClientsStatus({ fill: "grey", shape: "ring", text: "Found " + oPlates.Plates.Plate.length + " ignored plates. Last was " + node.lastPicName });

@@ -154,2 +183,3 @@ } catch (error) {

}
setTimeout(() => node.setAllClientsStatus({ fill: "green", shape: "ring", text: "Waiting for vehicle..." }),2000);
setTimeout(node.queryForPlates, 2000); // Start main polling thread

@@ -156,0 +186,0 @@ }

@@ -44,3 +44,3 @@

setTimeout(startAlarmStream, 5000); // Reconnect
}, 25000);
}, 40000);
}

@@ -73,3 +73,6 @@

//#region "HANDLE STREAM MESSAGE"
// Async get the body, called by streamPipeline(response.body, readStream);
// Handle the complete stream message, enclosed into the --boundary stream string
// ###################################

@@ -79,43 +82,50 @@ const streamPipeline = util.promisify(require('stream').pipeline);

try {
let result = ""; // The complete message, as soon as --boudary is received.
for await (const chunk of stream) {
var sRet = "";
sRet = chunk.toString();
// // console.log("BANANA " + sRet);
try {
sRet = sRet.replace(/--boundary/g, '');
var i = sRet.indexOf("<"); // Get only the XML, starting with "<"
if (i > -1) {
sRet = sRet.substring(i);
// // // console.log("BANANA SBANANATO " + sRet);
// By xml2js
xml2js(sRet, function (err, result) {
node.nodeClients.forEach(oClient => {
if (result !== undefined) oClient.sendPayload({ topic: oClient.topic || "", payload: result.EventNotificationAlert, connected: true });
})
});
} else {
i = sRet.indexOf("{") // It's a Json
result += chunk.toString();
// console.log("BANANA CHUNK " + chunk.toString());
// Gotta --boundary, process the message
if (result.toString().indexOf("--boundary") > -1) {
// console.log("BANANA FOUND BOUNDARY");
var sRet = result.toString();
result = ""; // Reset the result
// console.log("BANANA PROCESSING" + sRet);
try {
sRet = sRet.replace(/--boundary/g, '');
var i = sRet.indexOf("<"); // Get only the XML, starting with "<"
if (i > -1) {
sRet = sRet.substring(i);
//sRet = sRet.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": '); // Fix numbers and chars invalid in JSON
// // console.log("BANANA JSONATO: " + sRet);
node.nodeClients.forEach(oClient => {
oClient.sendPayload({ topic: oClient.topic || "", payload: JSON.parse(sRet), connected: true });
})
// // // // console.log("BANANA SBANANATO " + sRet);
// By xml2js
xml2js(sRet, function (err, result) {
node.nodeClients.forEach(oClient => {
if (result !== undefined) oClient.sendPayload({ topic: oClient.topic || "", payload: result.EventNotificationAlert, connected: true });
})
});
} else {
// Invalid body
RED.log.info("Hikvision-config: DecodingBody: Invalid Json " + sRet);
i = sRet.indexOf("{") // It's a Json
if (i > -1) {
sRet = sRet.substring(i);
//sRet = sRet.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": '); // Fix numbers and chars invalid in JSON
// // // console.log("BANANA JSONATO: " + sRet);
node.nodeClients.forEach(oClient => {
oClient.sendPayload({ topic: oClient.topic || "", payload: JSON.parse(sRet), connected: true });
})
} else {
// Invalid body
RED.log.info("Hikvision-config: DecodingBody: Invalid Json " + sRet);
}
}
// All is fine. Reset and restart the hearbeat timer
// Hikvision sends an heartbeat alarm (videoloss), depending on firmware, every 300ms or more.
// If this HeartBeat isn't received, abort the stream request and restart.
node.resetHeartBeatTimer();
} catch (error) {
// console.log("BANANA startAlarmStream decodifica body: " + error);
RED.log.error("Hikvision-config: DecodingBody error: " + error);
}
// All is fine. Reset and restart the hearbeat timer
// Hikvision sends an heartbeat alarm (videoloss), depending on firmware, every 300ms or more.
// If this HeartBeat isn't received, abort the stream request and restart.
node.resetHeartBeatTimer();
} catch (error) {
// // console.log("BANANA startAlarmStream decodifica body: " + error);
RED.log.info("Hikvision-config: DecodingBody error: " + error);
}
}
} catch (error) {
// // console.log("BANANA NEL BODY errore " + error);
// console.log("BANANA NEL BODY errore " + error);
return;

@@ -125,16 +135,20 @@ }

// ###################################
//#endregion
const response = await client.fetch("http://" + node.host + "/ISAPI/Event/notification/alertStream", options);
if (response.status >= 200 && response.status <= 300) {
node.setAllClientsStatus({ fill: "green", shape: "ring", text: "Connected. Waiting for Alarm." });
node.setAllClientsStatus({ fill: "green", shape: "ring", text: "Waiting for Alarm." });
} else {
node.setAllClientsStatus({ fill: "red", shape: "ring", text: response.statusText });
// // console.log("BANANA Error response " + response.statusText);
// // // console.log("BANANA Error response " + response.statusText);
throw ("Error response: " + response.statusText);
}
node.isConnected = true;
streamPipeline(response.body, readStream);
if (response.ok) {
node.isConnected = true;
streamPipeline(response.body, readStream);
}
} catch (err) {
// Main Error
// // console.log("BANANA MAIN ERROR: " + err);
// // // console.log("BANANA MAIN ERROR: " + err);
// Abort request

@@ -141,0 +155,0 @@ try {

@@ -10,3 +10,3 @@

node.currentPlate = ""; // Stores the current plate (for the avoidsameplatetime function)
node.timerAvoidSamePlate; // Timer for avoiding repeating plate
node.timerAvoidSamePlate = null; // Timer for avoiding repeating plate
node.bAvoidSamePlate = false;

@@ -32,3 +32,3 @@

// ##########################
try { clearTimeout(node.timerAvoidSamePlate); } catch (error) { };
if (node.timerAvoidSamePlate !== null) clearTimeout(node.timerAvoidSamePlate);
node.bAvoidSamePlate = true;

@@ -35,0 +35,0 @@ node.timerAvoidSamePlate = setTimeout(() => {

@@ -54,3 +54,3 @@

oRetMsg.alarm = _msg.payload; // Put the full alarm description here.
oRetMsg.zone = _msg.payload.CIDEvent.zone || "unknown";
oRetMsg.zone = _msg.payload.CIDEvent.zone + 1; // The zone on device's ISAPI is base 0, while the zone on UI is base 1.
if (Number(node.filterzone) === 0 || Number(node.filterzone) === Number(oRetMsg.zone)) { // Filter only selcted zones

@@ -57,0 +57,0 @@ // Get the Hikvision alarm codes, that differs from standard SIA codes.

{
"name": "node-red-contrib-hikvision-ultimate",
"version": "0.0.16",
"version": "0.0.17",
"description": "A native set of node for Hikvision Cameras, Alarms, Radars etc.",

@@ -5,0 +5,0 @@ "author": "Supergiovane (https://github.com/Supergiovane)",

@@ -21,2 +21,3 @@ # node-red-contrib-hikvision-ultimate

There are currently **only two nodes**, one that traps the alarms, in RAW mode, and outputs a JSON and the other that outputs the ANPR License Plate numbers.<br/>
The node uses pipelines to handle streams, so you need at least **Node V.10.0.0**, or newer, installed. To check Node version, type **node -v** in a command prompt.<br/>

@@ -35,3 +36,3 @@ ***THIS NODE IS IN BETA***<br/>

<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/RawAlarm.png' width="50%">
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/RawAlarm.png' width="80%">

@@ -42,2 +43,3 @@ **Output message**

This below, is only an example (in this case, a movement detected from a radar)</br>
**Caution**: the node actively checks if the device is connected to the network. In case of disconnection/reconnection, the nodes will output a message with **msg.connected = false** with a ***null*** payload if disconnected, and **msg.connected = true** if connected.<br/>

@@ -85,8 +87,8 @@ ```javascript

<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/ANPR.png' width="50%">
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/ANPR.png' width="80%">
**Output message**
The node outputs this msg.</br>
The payload contains the license plate number and the property "plate" contains other useful informations.</br>
**Caution**: the node actively checks if the ANPR camera is connected to the network. In case of disconnection/reconnection, the nodes will output a message with **msg.connected = false** with a ***null*** payload if disconnected, and **msg.connected = true** if connected.<br/>

@@ -115,3 +117,3 @@ ```javascript

<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/Radar.png' width="50%">
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/Radar.png' width="80%">

@@ -124,2 +126,3 @@ **Output message**

In an **unknown CID event** arrives from the Radar, the node will output a message containing the CID code, the full alarm and a null payload.</br>
**Caution**: the node actively checks if the radar is connected to the network. In case of disconnection/reconnection, the nodes will output a message with **msg.connected = false** with a ***null*** payload if disconnected, and **msg.connected = true** if connected.<br/>

@@ -126,0 +129,0 @@ ```javascript

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc