node-red-contrib-hikvision-ultimate
Advanced tools
Comparing version 0.0.13 to 0.0.15
@@ -5,2 +5,12 @@ # node-red-contrib-hikvision-ultimate | ||
<p> | ||
<b>Version 0.0.15 BETA</b> December 2020<br/> | ||
- Moved RAW node code into async functions.<br/> | ||
- Fixed BUG in ANPR module, where the last plate was sent every second..<br/> | ||
- Added icons.<br/> | ||
</p> | ||
<p> | ||
<b>Version 0.0.14 BETA</b> December 2020<br/> | ||
- Moved ANPR code into async functions, do help very slow PC's to correctly handle the data.<br/> | ||
</p> | ||
<p> | ||
<b>Version 0.0.13 BETA</b> December 2020<br/> | ||
@@ -7,0 +17,0 @@ - Moved ANPR code into async functions, do help very slow PC's to correctly handle the data.<br/> |
@@ -182,2 +182,4 @@ | ||
}) | ||
// Set the last plate found, to avoid repeating. | ||
node.lastPicName = oPlates.Plates.Plate[oPlates.Plates.Plate.length - 1].picName; | ||
} else { | ||
@@ -184,0 +186,0 @@ // No new plates found |
@@ -8,2 +8,3 @@ | ||
const xml2js = require('xml2js').Parser({ explicitArray: false }).parseString; | ||
const util = require('util'); | ||
@@ -28,3 +29,3 @@ function Hikvisionconfig(config) { | ||
// This function starts the heartbeat timer, to detect the disconnection from the server | ||
node.startHeartBeatTimer = () => { | ||
node.resetHeartBeatTimer = () => { | ||
// Reset node.timerCheckHeartBeat | ||
@@ -44,9 +45,14 @@ if (node.timerCheckHeartBeat !== null) clearTimeout(node.timerCheckHeartBeat); | ||
node.isConnected = false; | ||
setTimeout(node.startAlarmStream, 5000); // Reconnect | ||
setTimeout(startAlarmStream, 5000); // Reconnect | ||
}, 25000); | ||
} | ||
node.startAlarmStream = () => { | ||
async function startAlarmStream() { | ||
node.resetHeartBeatTimer(); // First thing, start the heartbeat timer. | ||
node.setAllClientsStatus({ fill: "grey", shape: "ring", text: "Connecting..." }); | ||
const client = new DigestFetch(node.credentials.user, node.credentials.password); // Instantiate the fetch client. | ||
controller = new AbortController(); // For aborting the stream request | ||
var client = new DigestFetch(node.credentials.user, node.credentials.password); // Instantiate the fetch client. | ||
var options = { | ||
@@ -63,81 +69,91 @@ // These properties are part of the Fetch Standard | ||
timeout: 0, // req/res timeout in ms, it resets on redirect. 0 to disable (OS limit applies). Signal is recommended instead. | ||
compress: true, // support gzip/deflate content encoding. false to disable | ||
compress: false, // support gzip/deflate content encoding. false to disable | ||
size: 0, // maximum response body size in bytes. 0 to disable | ||
agent: null // http(s).Agent instance or function that returns an instance (see below) | ||
} | ||
node.startHeartBeatTimer(); // First thing, start the heartbeat timer. | ||
node.setAllClientsStatus({ fill: "grey", shape: "ring", text: "Connecting..." }); | ||
}; | ||
try { | ||
client.fetch("http://" + node.host + "/ISAPI/Event/notification/alertStream", options) | ||
.then(response => { | ||
//console.log(response.status + " " + response.statusText); | ||
if (response.statusText === "Unauthorized") { | ||
node.setAllClientsStatus({ fill: "red", shape: "ring", text: response.statusText }); | ||
} | ||
if (response.statusText === "Ok") { | ||
node.setAllClientsStatus({ fill: "green", shape: "ring", text: "Connected. Waiting for Alarm." }); | ||
} | ||
return response.body; | ||
}) | ||
.then(body => { | ||
body.on('readable', () => { | ||
node.isConnected = true; | ||
try { | ||
let chunk; | ||
var sRet = "" | ||
while (null !== (chunk = body.read())) { | ||
sRet = chunk.toString(); | ||
} | ||
//console.log("BANANA " + sRet) | ||
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 | ||
// Async get the body, called by streamPipeline(response.body, readStream); | ||
// ################################### | ||
const streamPipeline = util.promisify(require('stream').pipeline); | ||
async function readStream(stream) { | ||
try { | ||
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); | ||
//sRet = sRet.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": '); // Fix numbers and chars invalid in JSON | ||
//console.log("BANANA : " + 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.info("Hikvision-config: DecodingBody error: " + error); | ||
} | ||
} | ||
} catch (error) { | ||
// // console.log("BANANA NEL BODY errore " + error); | ||
return; | ||
} | ||
} | ||
// ################################### | ||
} catch (error) { RED.log.error("Hikvision-config: ERRORE CATCHATO " + 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.startHeartBeatTimer(); | ||
}); | ||
}) | ||
.catch(err => { | ||
node.setAllClientsStatus({ fill: "grey", shape: "ring", text: "Server unreachable: " + err + " Retry..." }); | ||
if (node.isConnected) { | ||
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." }); | ||
} else { | ||
node.setAllClientsStatus({ fill: "red", shape: "ring", text: response.statusText }); | ||
// // console.log("BANANA Error response " + response.statusText); | ||
throw ("Error response: " + response.statusText); | ||
} | ||
node.isConnected = true; | ||
streamPipeline(response.body, readStream); | ||
} catch (err) { | ||
// Main Error | ||
// // console.log("BANANA MAIN ERROR: " + err); | ||
// Abort request | ||
try { | ||
if (controller !== null) controller.abort(); | ||
} catch (error) { } | ||
node.setAllClientsStatus({ fill: "grey", shape: "ring", text: "Server unreachable: " + err + " Retry..." }); | ||
if (node.isConnected) { | ||
try { | ||
node.nodeClients.forEach(oClient => { | ||
oClient.sendPayload({ topic: oClient.topic || "", payload: null, connected: false }); | ||
}) | ||
} | ||
node.isConnected = false; | ||
return; | ||
}); | ||
} catch (error) { } | ||
} | ||
node.isConnected = false; | ||
}; | ||
}; | ||
setTimeout(node.startAlarmStream, 5000); // First connection. | ||
setTimeout(startAlarmStream, 5000); // First connection. | ||
@@ -151,3 +167,2 @@ | ||
if (node.timerCheckHeartBeat !== null) clearTimeout(node.timerCheckHeartBeat); | ||
if (node.startAlarmStream !== null) clearTimeout(node.startAlarmStream) | ||
done(); | ||
@@ -154,0 +169,0 @@ }); |
{ | ||
"name": "node-red-contrib-hikvision-ultimate", | ||
"version": "0.0.13", | ||
"version": "0.0.15", | ||
"description": "A native set of node for Hikvision Cameras, Alarms, Radars etc.", | ||
@@ -10,3 +10,4 @@ "author": "Supergiovane (https://github.com/Supergiovane)", | ||
"digest-fetch": "1.1.5", | ||
"abort-controller": ">=3.0.0" | ||
"abort-controller": ">=3.0.0", | ||
"util": ">=0.12.3" | ||
}, | ||
@@ -35,2 +36,2 @@ "keywords": [ | ||
} | ||
} | ||
} |
@@ -21,3 +21,3 @@ # node-red-contrib-hikvision-ultimate | ||
***THIS NODESET IS IN BETA. E' ancora brutto, ma funziona.***<br/> | ||
***THIS NODE IS IN BETA***<br/> | ||
I'll add helps, docs and samples in this README page. Please have some patience...<br/> | ||
@@ -30,3 +30,2 @@ | ||
<br/> | ||
<br/> | ||
@@ -33,0 +32,0 @@ ## - RAW Alarm Node |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
303184
20
479
5
70
+ Addedutil@>=0.12.3
+ Addedavailable-typed-arrays@1.0.7(transitive)
+ Addedcall-bind@1.0.8(transitive)
+ Addedcall-bind-apply-helpers@1.0.1(transitive)
+ Addedcall-bound@1.0.3(transitive)
+ Addeddefine-data-property@1.1.4(transitive)
+ Addeddunder-proto@1.0.1(transitive)
+ Addedes-define-property@1.0.1(transitive)
+ Addedes-errors@1.3.0(transitive)
+ Addedes-object-atoms@1.0.0(transitive)
+ Addedfor-each@0.3.3(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedget-intrinsic@1.2.7(transitive)
+ Addedget-proto@1.0.1(transitive)
+ Addedgopd@1.2.0(transitive)
+ Addedhas-property-descriptors@1.0.2(transitive)
+ Addedhas-symbols@1.1.0(transitive)
+ Addedhas-tostringtag@1.0.2(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedis-arguments@1.2.0(transitive)
+ Addedis-callable@1.2.7(transitive)
+ Addedis-generator-function@1.1.0(transitive)
+ Addedis-regex@1.2.1(transitive)
+ Addedis-typed-array@1.1.15(transitive)
+ Addedmath-intrinsics@1.1.0(transitive)
+ Addedpossible-typed-array-names@1.0.0(transitive)
+ Addedsafe-regex-test@1.1.0(transitive)
+ Addedset-function-length@1.2.2(transitive)
+ Addedutil@0.12.5(transitive)
+ Addedwhich-typed-array@1.1.18(transitive)