New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.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 1.0.27 to 1.0.28

img/NotifyCenter.png

6

CHANGELOG.md

@@ -7,2 +7,8 @@ <p align="center"><img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/logo.png' width="40%"></p>

<p>
<b>Version 1.0.28</b> January 2021<br/>
- BREAKING CHANGE: the Radar node is now part of the Alarm node. The Radar node has been deleted.<br/>
- NEW: the Alarm node can now filter for channels and zones as well. SOME ADJUSTMENT TO YOUR FLOW MAY BE NEEDED.<br/>
- NEW: Text overlay node: you can set the camera's 4 rows overlay text.<br/>
</p>
<p>
<b>Version 1.0.27</b> January 2021<br/>

@@ -9,0 +15,0 @@ - NEW: Text overlay in the picture node. You can also set the position and font. The text can be set with msg.textoverlay as well.<br/>

244

nodes/hikvisionUltimateAlarm.js

@@ -10,2 +10,12 @@

node.reactto = (config.reactto === null || config.reactto === undefined) ? "vmd" : config.reactto.toLowerCase();// Rect to alarm coming from...
node.filterzone = config.filterzone || "0";// Rect to alarm coming from zone...
node.channelID = config.channelID || "0";// Rect to alarm coming from channelID...
node.currentAlarmMSG = {}; // Stores the current alarm object
node.total_alarmfilterduration = 0; // stores the total time an alarm has been true in the alarmfilterperiod time.
node.isNodeInAlarm = false; // Stores the current state of the filtered alarm.
node.isRunningTimerFilterPeriod = false; // Indicates wether the period timer is running;
node.alarmfilterduration = config.alarmfilterduration !== undefined ? config.alarmfilterduration : 0;
node.alarmfilterperiod = config.alarmfilterperiod !== undefined ? config.alarmfilterperiod : 0;
node.devicetype = config.devicetype !== undefined ? config.devicetype : 0;
if (node.devicetype == 0) node.alarmfilterduration = 0; // Normal events, set it to zero

@@ -17,2 +27,42 @@ node.setNodeStatus = ({ fill, shape, text }) => {

// 29/01/2021 start the timer that counts the time the alarm has been true
// ###################################
startTimerAlarmFilterDuration = () => {
node.timer_alarmfilterduration = setInterval(() => {
if (node.currentAlarmMSG.hasOwnProperty("payload")) {
if (node.currentAlarmMSG.payload === true) {
node.total_alarmfilterduration += 1;
if (node.isRunningTimerFilterPeriod) node.setNodeStatus({ fill: "red", shape: "ring", text: "Zone " + node.currentAlarmMSG.zone + " pre alert count " + node.total_alarmfilterduration });
if (node.total_alarmfilterduration >= node.alarmfilterduration) {
if (!node.isNodeInAlarm) {
// Emit alarm
if (node.timer_alarmfilterperiod !== null) clearTimeout(node.timer_alarmfilterperiod);
//node.setNodeStatus({ fill: "yellow", shape: "ring", text: "STOP TimerFilterPeriod" });
node.isRunningTimerFilterPeriod = false;
node.isNodeInAlarm = true;
node.total_alarmfilterduration = 0;
node.setNodeStatus({ fill: "red", shape: "dot", text: "Zone " + node.currentAlarmMSG.zone + " alarm" });
node.send([node.currentAlarmMSG, null]);
} else { node.total_alarmfilterduration = 0; }
}
}
}
}, 1000);
}
// 29/01/2021 This timer resets the node.total_alarmfilterduration
startTimerAlarmFilterPeriod = () => {
//node.setNodeStatus({ fill: "yellow", shape: "ring", text: "START TimerFilterPeriod" });
node.isRunningTimerFilterPeriod = true;
node.total_alarmfilterduration = 0;
node.timer_alarmfilterperiod = setTimeout(() => {
node.total_alarmfilterduration = 0;
//node.setNodeStatus({ fill: "yellow", shape: "ring", text: "ELAPSED TimerFilterPeriod" });
node.isRunningTimerFilterPeriod = false;
}, node.alarmfilterperiod * 1000);
}
if (node.alarmfilterduration !== 0) startTimerAlarmFilterDuration(); // If filter is enabled, start timer
// ###################################
// Called from config node, to send output to the flow

@@ -23,6 +73,115 @@ node.sendPayload = (_msg) => {

if (_msg.hasOwnProperty("errorDescription")) { node.send([null, _msg]); return; }; // It's a connection error/restore comunication.
if (!_msg.hasOwnProperty("payload")) return;
var sAlarmType = "";
var bAlarmStatus = false;
if (_msg.hasOwnProperty("payload")) {
var oRetMsg = {}; // Return message
// Check what alarm type must i search for.
// Security devices issue a CID alarm
//#region "CID"
// #################################
if ((node.devicetype == 1 || node.devicetype == 2)
&& _msg.payload.hasOwnProperty("CIDEvent")
&& _msg.payload.CIDEvent.type.toString().toLowerCase() === "zonealarm"
&& _msg.payload.CIDEvent.hasOwnProperty("zone")) {
oRetMsg.topic = _msg.topic;
oRetMsg.alarm = _msg.payload; // Put the full alarm description here.
oRetMsg.zone = _msg.payload.CIDEvent.zone + 1; // The zone on device's ISAPI is base 0, while the zone on UI is base 1.
// CID Alarm (node.reactto is CID:startAlarmCode-endAlarmCode)
let sAlarmCodeStart = node.reactto.split(":")[1].split("-")[0];
let sAlarmCodeEnd = node.reactto.split(":")[1].split("-")[1];
if (Number(node.filterzone) === 0 || Number(node.filterzone) === Number(oRetMsg.zone)) { // Filter only selcted zones
// Get the Hikvision alarm codes, that differs from standard SIA codes.
switch (_msg.payload.CIDEvent.code.toString().toLowerCase()) {
// Standard SIA Code is _msg.payload.CIDEvent.standardCIDcode
case sAlarmCodeStart:
// Starts alarm
oRetMsg.payload = true;
node.setNodeStatus({ fill: "red", shape: "ring", text: "Zone " + oRetMsg.zone + " pre alert" });
break;
case sAlarmCodeEnd:
// End alarm.
oRetMsg.payload = false;
node.setNodeStatus({ fill: "green", shape: "dot", text: "Zone " + oRetMsg.zone + " normal" });
break;
default:
// Unknown CID code.
node.setNodeStatus({ fill: "grey", shape: "ring", text: "Zone " + oRetMsg.zone + " unknowk CID code " + _msg.payload.CIDEvent.code });
return; // Unknown state
}
}
}
// #################################
//#endregion
// Camera/NVR, no CID codes, just standard hikvision strings
//#region "STANDARD"
// #################################
// STANDARD MOTION EVENT
// {
// "topic": "",
// "payload": {
// "$": {
// "version": "2.0",
// "xmlns": "http://www.isapi.org/ver20/XMLSchema"
// },
// "ipAddress": "192.168.1.32",
// "portNo": "80",
// "protocolType": "HTTP",
// "macAddress": "58:03:fb:dc:94:d6",
// "dynChannelID": "13",
// "channelID": "13",
// "dateTime": "2021-01-29T09:58:05+01:00",
// "activePostCount": "38",
// "eventType": "VMD",
// "eventState": "active",
// "eventDescription": "Motion alarm",
// "channelName": "Viessmann"
// },
// "_msgid": "913ac479.52e768"
// }
// SMART EVENT
// {
// "topic": "",
// "payload": {
// "$": {
// "version": "2.0",
// "xmlns": "http://www.isapi.org/ver20/XMLSchema"
// },
// "ipAddress": "192.168.1.32",
// "portNo": "80",
// "protocolType": "HTTP",
// "macAddress": "58:03:fb:dc:94:d6",
// "dynChannelID": "13",
// "channelID": "13",
// "dateTime": "2021-01-29T10:26:44+01:00",
// "activePostCount": "1",
// "eventType": "fielddetection",
// "eventState": "active",
// "eventDescription": "fielddetection alarm",
// "channelName": "Viessmann",
// "DetectionRegionList": {
// "DetectionRegionEntry": {
// "regionID": "0",
// "RegionCoordinatesList": "\n",
// "TargetRect": {
// "X": "0.000000",
// "Y": "0.000000",
// "width": "0.000000",
// "height": "0.000000"
// }
// }
// }
// },
// "_msgid": "853ba286.3a708"
// }
if (node.devicetype == 0) {
var sAlarmType = "";
var bAlarmStatus = false;
if (_msg.payload.hasOwnProperty("eventType")) {

@@ -36,27 +195,61 @@ // Check if it's only a hearbeat alarm

}
if (_msg.payload.hasOwnProperty("eventState")) {
bAlarmStatus = (_msg.payload.eventState.toString().toLowerCase() === "active" ? true : false);
// Filter channel
let sChannelID = (_msg.payload.hasOwnProperty("channelID") ? _msg.payload.channelID : "0")
// Filter regionID (Zone)
let iRegionID = 0;
if (_msg.payload.hasOwnProperty("DetectionRegionList") && _msg.payload.DetectionRegionList.hasOwnProperty("DetectionRegionEntry") && _msg.payload.DetectionRegionList.DetectionRegionEntry.hasOwnProperty("regionID")) iRegionID = Number(_msg.payload.DetectionRegionList.DetectionRegionEntry.regionID) + 1;
if (Number(node.channelID) === 0 || Number(node.channelID) === Number(sChannelID)) { // Filter only selcted channel
if (Number(node.filterzone) === 0 || Number(node.filterzone) === iRegionID) { // Filter only selcted regionID (zone)
if (_msg.payload.hasOwnProperty("eventState")) {
bAlarmStatus = (_msg.payload.eventState.toString().toLowerCase() === "active" ? true : false);
} else {
// Mmmm.... no event state?
node.setNodeStatus({ fill: "red", shape: "ring", text: "Received alarm but no state!" });
return;
}
// check alarm filter
var aReactTo = node.reactto.split(","); // node.reactto can contain multiple names for the same event, depending from firmware
for (let index = 0; index < aReactTo.length; index++) {
const element = aReactTo[index];
if (element !== null && element !== undefined && element.trim() !== "" && sAlarmType === element) {
oRetMsg.payload = bAlarmStatus;
oRetMsg.topic = _msg.topic;
oRetMsg.channelid = sChannelID; // Channel ID (in case of NVR)
oRetMsg.zone = iRegionID; // Zone
oRetMsg.description = (_msg.payload.hasOwnProperty("eventDescription") ? _msg.payload.eventDescription : "");
break; // Find first occurrence, exit.
}
}
}
}
}
// #################################
//#endregion
// 29/01/2020 check wether the filter is enabled or not
if (oRetMsg.hasOwnProperty("payload")) {
if (node.alarmfilterduration == 0) {
node.send([oRetMsg, null]);
} else {
// Mmmm.... no event state?
node.setNodeStatus({ fill: "red", shape: "ring", text: "Received alarm but no state!" });
return;
}
//console.log ("BANANA " + _msg.payload.eventState.toString().toLowerCase())
// check alarm filter
var aReactTo = node.reactto.split(","); // node.reactto can contain multiple names for the same event, depending from firmware
for (let index = 0; index < aReactTo.length; index++) {
const element = aReactTo[index];
if (element !== null && element !== undefined && element.trim() !== "" && sAlarmType === element) {
var oRetMsg = {}; // Return message
oRetMsg.payload = bAlarmStatus;
oRetMsg.topic = _msg.topic;
oRetMsg.channelid = (_msg.payload.hasOwnProperty("channelID") ? _msg.payload.channelID : "0");
oRetMsg.description = (_msg.payload.hasOwnProperty("eventDescription") ? _msg.payload.eventDescription : "");
// Sends the false only in case the isNodeInAlarm is true.
node.currentAlarmMSG = oRetMsg;
if (oRetMsg.payload === false && node.isNodeInAlarm) {
node.send([oRetMsg, null]);
node.setNodeStatus({ fill: "green", shape: "dot", text: "Alarm " + (bAlarmStatus === true ? "start" : "end") });
return; // Find first occurrence, exit.
node.currentAlarmMSG = {};
node.isNodeInAlarm = false;
} else if (oRetMsg.payload === true && !node.isNodeInAlarm) {
if (!node.isRunningTimerFilterPeriod) {
startTimerAlarmFilterPeriod();
}
}
}
}
}

@@ -78,2 +271,7 @@

}
if (node.timer_alarmfilterduration !== null) clearInterval(node.timer_alarmfilterduration);
if (node.timer_alarmfilterperiod !== null) clearTimeout(node.timer_alarmfilterperiod);
if (node.server) {
node.server.removeClient(node);
}
done();

@@ -80,0 +278,0 @@ });

4

package.json
{
"name": "node-red-contrib-hikvision-ultimate",
"version": "1.0.27",
"version": "1.0.28",
"description": "A native set of nodes for Hikvision Cameras, Alarms, Radars etc.",

@@ -34,3 +34,3 @@ "author": "Supergiovane (https://github.com/Supergiovane)",

"ANPR-config": "nodes/ANPR-config.js",
"hikvisionUltimateRadar": "nodes/hikvisionUltimateRadar.js",
"hikvisionUltimateText": "nodes/hikvisionUltimateText.js",
"hikvisionUltimateAlarm": "nodes/hikvisionUltimateAlarm.js",

@@ -37,0 +37,0 @@ "hikvisionUltimateAlarmRaw": "nodes/hikvisionUltimateAlarmRaw.js",

@@ -20,4 +20,6 @@

All nodes are capable of auto reconnect if the connection is lost and are able to actively monitor the connection.<br/>
Be sure to have installed **Node.js v12.3.0** or newer (issue a node -v command in a console, to check it out).
Be sure to have installed **Node.js v12.3.0** or newer (issue a node -v command in a console, to check it out).<br/>
**Note:** for NVR/DVR, pleas remember to select "Notify Alarm Center" in the event window, otherwise the NVR won't emit any alarm event.<br/>
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/NotifyCenter.png' width="20%">

@@ -32,15 +34,17 @@ ## CHANGELOG

## ALARM NODE
The alarm node connects to ***NVR, Camera, Alarm system*** and outputs true/false whenever an alarm occurs. <br/>
The alarm node connects to ***NVR, Camera, Alarm system, Radars, etc..*** and outputs true/false whenever an alarm occurs. <br/>
The node can be configured as **Camera/NVR** (with standard and smart events) or as **Security System** and **Radar** (with specific CID events, designed for these type of security devices)<br/>
Some alarm events supports the alarm start and end events, while others, only the alarm start event. CID alarms ALWAYS support start/end events.<br/>
You can filter for CHANNEL, EVENT and ZONE. For NVR, the ***Channel*** represents the CAMERA number, while for Cameras, represents the sensor number (by default 1, if the camera has only one image sensor). The ***zone*** represents the alarm zone for RADARS AND SECURITY SYSTEM, otherwise the region (for example the intrusion alert region number).<br/>
The RADAR and SECURITY SYSTEM device types, can filter improper/false alams.<br/>
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/GenericAlarm.png' width="80%">
You can choose from different alarms, for example: <br/>
You can choose from many different alarms, including: <br/>
- Video Motion Alarm (When motion is detected)
- Local alarm input (it's the device's IO pigtail connector)
- Line crossing (when someone crosses a line)
- Video loss (when the camera loses the video signal)
- Video blind (when you put something in front of the camera to block image)
- CID alarms
- Many more.....
For other advanced alarms, not present in this node, use the ***RAW Alarm*** node instead.

@@ -57,10 +61,53 @@

```javascript
msg = {
"payload":true, // True if alarm starts, false if ends.
"channelid":"1", // If you have many video channels on your camera, this represents the channel number.
"description":"Motion alarm", // Type of alarm
"_msgid":"28f2b9e6.7c74f6"
// Example of an event from NVR/Camera
msg.payload = {
"payload": true,
"topic": "",
"channelid": "13", // This is the camera number for NVR, or the channel ID for cameras
"zone": 0, // Zone or Region, see above, the explained difference
"description": "Motion alarm",
"_msgid": "386a613.89f259e"
}
```
```javascript
// Example of an event from Security System or Radar
msg.payload = {
{
"zone": 1, // This is the zone number that fired the alarm
"payload": true, // true if alarm, otherwise false if alarm ended.
"alarm": {
"ipAddress": "192.168.1.25",
"ipv6Address": "",
"portNo": 80,
"protocol": "HTTP",
"macAddress": "BananaRama",
"channelID": 1,
"dateTime": "2012-01-13T03:58:19+01:00",
"activePostCount": 1,
"eventType": "cidEvent",
"eventState": "active",
"eventDescription": "CID event",
"CIDEvent": {
"code": 3103,
"standardCIDcode": 3130,
"type": "zoneAlarm",
"trigger": "2012-01-13T03:58:19+01:00",
"upload": "2012-01-13T03:58:19+01:00",
"CameraList": [],
"NVRList": [
{
"id": 1,
"ip": "192.168.1.32",
"port": 8000,
"channel": 1
}
],
"zone": 1
}
}
"_msgid": "b07e50f6.86a72"
}
```
**Output PIN 2 (connection error)**

@@ -121,3 +168,2 @@ ```javascript

## PTZ NODE
This node works with Hikvision PTZ cameras.<br/>
Just select the preset in the configuration window and recall it by passing ***true*** as payload.<br/>

@@ -220,64 +266,55 @@

## RADAR ALARM NODE
This node works with Hikvision Radars.<br/>
## TEXT OVERLAY NODE
You can set the camera's text overlay.<br/>
There are 4 rows avaiable, to be set from the configuration window or dinamically via msg input from flow.<br/>
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/Radar.png' width="80%">
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/master/img/Text.png' width="80%">
**Copy this code and paste it into your flow**
<details><summary>View code</summary>
> Adjust the nodes according to your setup
<code>
[{"id":"7e79800b.afb8a8","type":"hikvisionUltimateText","z":"3f22f0c6.ff1328","name":"Overlay Text","server":"ff0cbde2.8c00b8","row1":"UNO","row1XY":"40,100","row2":"DUE","row2XY":"","row3":"TRE","row3XY":"","row4":"QUATTRO","row5XY":"","x":510,"y":120,"wires":[]},{"id":"3aa8a40f.9a0964","type":"inject","z":"3f22f0c6.ff1328","name":"Go","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":170,"y":120,"wires":[["7e79800b.afb8a8"]]},{"id":"2b4d9297.75ee46","type":"comment","z":"3f22f0c6.ff1328","name":"Set the overlay text","info":"","x":190,"y":80,"wires":[]},{"id":"22dc37f9.b3b86","type":"function","z":"3f22f0c6.ff1328","name":"MSG Override","func":"// Override one or more rows\n// You can use from row1 to row4 to set the text\n// and from row1XY to row4XY to set the position in the format x,y (for example: 100,200)\n\n// Row 1\nmsg.row1=\"Temperature: \" + msg.payload;\nmsg.row1XY=\"100,200\";\n\n// Row 2 (here we leave the position previosly set via the camera menu)\nmsg.row2=\"Sun\";\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":320,"y":180,"wires":[["7e79800b.afb8a8"]]},{"id":"a91e43a0.ccbb2","type":"inject","z":"3f22f0c6.ff1328","name":"Go","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"22°c","payloadType":"str","x":170,"y":180,"wires":[["22dc37f9.b3b86"]]},{"id":"ff0cbde2.8c00b8","type":"Hikvision-config","host":"192.168.1.20","port":"80","name":"Viessman","authentication":"digest","protocol":"http","heartbeattimerdisconnectionlimit":"1","deviceinfo":"{\"DeviceInfo\":{\"$\":{\"version\":\"2.0\",\"xmlns\":\"http://www.hikvision.com/ver20/XMLSchema\"},\"deviceName\":\"Viessman\",\"deviceID\":\"b3464000-5074-11b4-82cc-bcbac23d3ac8\",\"deviceDescription\":\"IPCamera\",\"deviceLocation\":\"hangzhou\",\"systemContact\":\"Hikvision.China\",\"model\":\"DS-2CD2085FWD-I\",\"serialNumber\":\"DS-2CD2085FWD-I20190716AAWRD39667116\",\"macAddress\":\"Bananassa\",\"firmwareVersion\":\"V5.6.3\",\"firmwareReleasedDate\":\"build 190923\",\"encoderVersion\":\"V7.3\",\"encoderReleasedDate\":\"build 190910\",\"bootVersion\":\"V1.3.4\",\"bootReleasedDate\":\"100316\",\"hardwareVersion\":\"0x0\",\"deviceType\":\"IPCamera\",\"telecontrolID\":\"88\",\"supportBeep\":\"false\",\"supportVideoLoss\":\"false\",\"firmwareVersionInfo\":\"B-R-G1-0\"}}"}]
</code>
</details>
<br/>
<br/>
**Flow Messages**
The node outputs a message whenever an alarm starts or ends. It uses CID codes to identify the alarm type.</br>
The payload is TRUE whenever alarm occurs, otherwise FALSE whenever alarm ends.</br>
The complete alarm event is stored in the "alarm" property of the payload.</br>
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>
The radar node can filter improper/false alams.</br>
The node accepts only an input. Pass anything you like to set the text overlay.</br>
You can override the texts by passing some msg inputs. See the sample below</br>
**Output PIN 1**
**Input**
```javascript
msg.payload = {
{
"zone": 1, // This is the zone number that fired the alarm
"payload": true, // true if alarm, otherwise false if alarm ended.
"alarm": {
"ipAddress": "192.168.1.25",
"ipv6Address": "",
"portNo": 80,
"protocol": "HTTP",
"macAddress": "9banana",
"channelID": 1,
"dateTime": "2012-01-13T03:58:19+01:00",
"activePostCount": 1,
"eventType": "cidEvent",
"eventState": "active",
"eventDescription": "CID event",
"CIDEvent": {
"code": 3103,
"standardCIDcode": 3130,
"type": "zoneAlarm",
"trigger": "2012-01-13T03:58:19+01:00",
"upload": "2012-01-13T03:58:19+01:00",
"CameraList": [],
"NVRList": [
{
"id": 1,
"ip": "192.168.1.32",
"port": 8000,
"channel": 1
}
],
"zone": 1
}
}
"_msgid": "b07e50f6.86a72"
}
// Simply overlay the text set in the config window
msg.payload = true;
return msg;
```
**Output PIN 2 (connection error)**
```javascript
msg = {
"topic": "",
"errorDescription": "", // This will contain the error rescription, in case of errors.
"payload": false, // Or TRUE if error
"_msgid": "dd5b3622.884a78"
}
// Override one or more rows
// You can use from row1 to row4 to set the text
// and from row1XY to row4XY to set the position in the format x,y (for example: 100,200)
// Row 1
msg.row1 = "Temperature: " + msg.payload;
msg.row1XY = "100,200";
// Row 2 (here we leave the position previosly set via the camera menu)
msg.row2 = "Sun";
return msg;
```
```javascript
// Delete all 4 rows
msg.row1 = "";
msg.row2 = "";
msg.row3 = "";
msg.row4 = "";
return msg;
```
<br/>

@@ -284,0 +321,0 @@ <br/>

Sorry, the diff of this file is not supported yet

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