├── .gitattributes ├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── img ├── ANPR.png ├── CIDEvents │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ └── 5.png ├── Doorbell.png ├── GenericAlarm.png ├── NotifyCenter.png ├── PTZ.png ├── Radar.png ├── RawAlarm.png ├── Text.png ├── XML.png ├── accesscontrol.png ├── accesscontrolterminal.jpg ├── axpro.png ├── axproPicture.jpg ├── hikanprcamera.jpg ├── hikcamera.jpg ├── hikcamerasettings.png ├── hikptzcamera.png ├── info.png ├── loading.gif ├── logo.png ├── madeinitaly.png ├── picture.png ├── pictureproperties.png └── speaker.jpg ├── nodes ├── ANPR-config.html ├── ANPR-config.js ├── AXPro-config.html ├── AXPro-config.js ├── AccessControl-config.html ├── AccessControl-config.js ├── Doorbell-config.html ├── Doorbell-config.js ├── Hikvision-config copy.js ├── Hikvision-config.html ├── Hikvision-config.js ├── Speaker-config.html ├── Speaker-config.js ├── hikvisionUltimateANPR.html ├── hikvisionUltimateANPR.js ├── hikvisionUltimateAccessControlTerminal.html ├── hikvisionUltimateAccessControlTerminal.js ├── hikvisionUltimateAlarm.html ├── hikvisionUltimateAlarm.js ├── hikvisionUltimateAlarmRaw.html ├── hikvisionUltimateAlarmRaw.js ├── hikvisionUltimateAxPro.html ├── hikvisionUltimateAxPro.js ├── hikvisionUltimateDoorbell.html ├── hikvisionUltimateDoorbell.js ├── hikvisionUltimatePTZ.html ├── hikvisionUltimatePTZ.js ├── hikvisionUltimatePicture.html ├── hikvisionUltimatePicture.js ├── hikvisionUltimateSpeaker.html ├── hikvisionUltimateSpeaker.js ├── hikvisionUltimateText.html ├── hikvisionUltimateText.js ├── hikvisionUltimateXML.html ├── hikvisionUltimateXML.js ├── icons │ ├── camera-icon.png │ ├── camera-icon.svg │ ├── node-alarm.png │ ├── node-alarm.svg │ ├── node-anpr-icon.png │ ├── node-anpr-icon.svg │ ├── node-radar-icon.png │ ├── node-radar-icon.svg │ ├── node-raw-icon.png │ ├── node-raw-icon.svg │ ├── ptz-icon.png │ └── ptz-icon.svg └── utils │ ├── AccessControlEvents │ ├── MAJOR_ALARM-0x1.json │ ├── MAJOR_EVENT-0x5.json │ ├── MAJOR_EXCEPTION-0x2.json │ └── MAJOR_OPERATION-0x3.json │ ├── Sha256.js │ ├── classDoorbellCapabilities.js │ ├── dateManagement.js │ ├── escape-json.js │ ├── hikDiscovery.js │ └── ipAddressHelper.js ├── package-lock.json └── package.json /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: Supergiovane 7 | 8 | --- 9 | 10 | **Salutation (i'll not respond to users that doesn’t wrote at least "Hello")** 11 | 12 | **Describe the bug** 13 | A clear and concise description of what the bug is. 14 | 15 | **To Reproduce** 16 | Steps to reproduce the behavior: 17 | 1. Go to '...' 18 | 2. Click on '....' 19 | 3. Scroll down to '....' 20 | 4. See error 21 | 22 | **Expected behavior** 23 | A clear and concise description of what you expected to happen. 24 | 25 | **Screenshots** 26 | If applicable, add screenshots to help explain your problem. 27 | 28 | **Hikvision-Ultimate Version** 29 | - Eg. 1.1.95 30 | 31 | **Are you running node-red behind homematic, docker or anything similar?** 32 | - Eg. Node-Red running alone in RaspberryPi 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Massimo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /img/ANPR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/ANPR.png -------------------------------------------------------------------------------- /img/CIDEvents/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/CIDEvents/1.png -------------------------------------------------------------------------------- /img/CIDEvents/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/CIDEvents/2.png -------------------------------------------------------------------------------- /img/CIDEvents/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/CIDEvents/3.png -------------------------------------------------------------------------------- /img/CIDEvents/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/CIDEvents/4.png -------------------------------------------------------------------------------- /img/CIDEvents/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/CIDEvents/5.png -------------------------------------------------------------------------------- /img/Doorbell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/Doorbell.png -------------------------------------------------------------------------------- /img/GenericAlarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/GenericAlarm.png -------------------------------------------------------------------------------- /img/NotifyCenter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/NotifyCenter.png -------------------------------------------------------------------------------- /img/PTZ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/PTZ.png -------------------------------------------------------------------------------- /img/Radar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/Radar.png -------------------------------------------------------------------------------- /img/RawAlarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/RawAlarm.png -------------------------------------------------------------------------------- /img/Text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/Text.png -------------------------------------------------------------------------------- /img/XML.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/XML.png -------------------------------------------------------------------------------- /img/accesscontrol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/accesscontrol.png -------------------------------------------------------------------------------- /img/accesscontrolterminal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/accesscontrolterminal.jpg -------------------------------------------------------------------------------- /img/axpro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/axpro.png -------------------------------------------------------------------------------- /img/axproPicture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/axproPicture.jpg -------------------------------------------------------------------------------- /img/hikanprcamera.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/hikanprcamera.jpg -------------------------------------------------------------------------------- /img/hikcamera.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/hikcamera.jpg -------------------------------------------------------------------------------- /img/hikcamerasettings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/hikcamerasettings.png -------------------------------------------------------------------------------- /img/hikptzcamera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/hikptzcamera.png -------------------------------------------------------------------------------- /img/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/info.png -------------------------------------------------------------------------------- /img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/loading.gif -------------------------------------------------------------------------------- /img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/logo.png -------------------------------------------------------------------------------- /img/madeinitaly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/madeinitaly.png -------------------------------------------------------------------------------- /img/picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/picture.png -------------------------------------------------------------------------------- /img/pictureproperties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/pictureproperties.png -------------------------------------------------------------------------------- /img/speaker.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/img/speaker.jpg -------------------------------------------------------------------------------- /nodes/ANPR-config.html: -------------------------------------------------------------------------------- 1 | 97 | 98 | -------------------------------------------------------------------------------- /nodes/AXPro-config.html: -------------------------------------------------------------------------------- 1 | 31 | 32 | -------------------------------------------------------------------------------- /nodes/AccessControl-config.html: -------------------------------------------------------------------------------- 1 | 97 | 98 | -------------------------------------------------------------------------------- /nodes/Doorbell-config.html: -------------------------------------------------------------------------------- 1 | 102 | 103 | -------------------------------------------------------------------------------- /nodes/Hikvision-config.html: -------------------------------------------------------------------------------- 1 | 103 | 104 | 185 | 186 | -------------------------------------------------------------------------------- /nodes/Speaker-config.html: -------------------------------------------------------------------------------- 1 | 102 | 103 | 159 | 160 | -------------------------------------------------------------------------------- /nodes/hikvisionUltimateANPR.html: -------------------------------------------------------------------------------- 1 | 53 | 54 | 82 | 83 | -------------------------------------------------------------------------------- /nodes/hikvisionUltimateANPR.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports = function (RED) { 4 | function hikvisionUltimateANPR(config) { 5 | RED.nodes.createNode(this, config); 6 | var node = this; 7 | node.topic = config.topic || config.name; 8 | node.server = RED.nodes.getNode(config.server) 9 | node.avoidsameplatetime = config.avoidsameplatetime || 20; // Doesn't send the same plate in this timeframe, in seconds. 10 | node.currentPlate = ""; // Stores the current plate (for the avoidsameplatetime function) 11 | node.timerAvoidSamePlate = null; // Timer for avoiding repeating plate 12 | node.bAvoidSamePlate = false; 13 | 14 | node.setNodeStatus = ({ fill, shape, text }) => { 15 | var dDate = new Date(); 16 | node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" }) 17 | } 18 | 19 | // Called from config node, to send output to the flow 20 | node.sendPayload = (_msg) => { 21 | if (_msg === null || _msg === undefined) return; 22 | _msg.topic = node.topic; 23 | if (_msg.hasOwnProperty("errorDescription")) { node.send([null, _msg]); return; }; // It's a connection error/restore comunication. 24 | if (!_msg.hasOwnProperty("payload") || (_msg.hasOwnProperty("payload") && (_msg.payload === undefined || _msg.payload === null))) return; 25 | 26 | if (node.currentPlate === _msg.payload) { 27 | if (node.bAvoidSamePlate) { 28 | try { node.setNodeStatus({ fill: "grey", shape: "ring", text: "Temporary block same plate " + _msg.payload }); } catch (error) { }; 29 | return; 30 | } 31 | } 32 | 33 | // Timer for avoiding same plate 34 | // ########################## 35 | if (node.timerAvoidSamePlate !== null) clearTimeout(node.timerAvoidSamePlate); 36 | node.bAvoidSamePlate = true; 37 | node.timerAvoidSamePlate = setTimeout(() => { 38 | node.bAvoidSamePlate = false; 39 | }, node.avoidsameplatetime * 1000); 40 | // ########################## 41 | 42 | node.currentPlate = _msg.payload; 43 | node.send([_msg, null]); 44 | try { 45 | node.setNodeStatus({ fill: "green", shape: "dot", text: "Plate " + _msg.payload }); 46 | } catch (error) { } 47 | } 48 | 49 | // On each deploy, unsubscribe+resubscribe 50 | if (node.server) { 51 | node.server.removeClient(node); 52 | node.server.addClient(node); 53 | } 54 | 55 | this.on('input', function (msg) { 56 | 57 | }); 58 | 59 | node.on("close", function (done) { 60 | if (node.server) { 61 | node.server.removeClient(node); 62 | } 63 | done(); 64 | }); 65 | 66 | } 67 | 68 | RED.nodes.registerType("hikvisionUltimateANPR", hikvisionUltimateANPR); 69 | } -------------------------------------------------------------------------------- /nodes/hikvisionUltimateAccessControlTerminal.html: -------------------------------------------------------------------------------- 1 | 104 | 105 | 142 | 143 | -------------------------------------------------------------------------------- /nodes/hikvisionUltimateAccessControlTerminal.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports = function (RED) { 4 | function hikvisionUltimateAccessControlTerminal(config) { 5 | RED.nodes.createNode(this, config); 6 | var node = this; 7 | node.topic = config.topic || config.name; 8 | node.server = RED.nodes.getNode(config.server) 9 | node.filtermajorevent = Number(config.filtermajorevent) || 0; 10 | node.filterminorevent = parseInt(config.filterminorevent || 0, 16); // Hex to decimal 11 | 12 | 13 | node.setNodeStatus = ({ fill, shape, text }) => { 14 | var dDate = new Date(); 15 | node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" }) 16 | } 17 | 18 | // Called from config node, to send output to the flow 19 | node.sendPayload = (_msg) => { 20 | if (_msg === null || _msg === undefined) return; 21 | _msg.topic = node.topic; 22 | if (_msg.hasOwnProperty("errorDescription")) { node.send([null, _msg]); return; }; // It's a connection error/restore comunication. 23 | if (!_msg.hasOwnProperty("payload") || (_msg.hasOwnProperty("payload") && (_msg.payload === undefined || _msg.payload === null))) return; 24 | 25 | // Apply filter 26 | if (node.filtermajorevent > 0) { 27 | if (Number(_msg.payload.major) === node.filtermajorevent) { 28 | if (node.filterminorevent > 0) { 29 | if (Number(_msg.payload.minor) === node.filterminorevent) { 30 | node.send([_msg, null]); 31 | setTimeout(() => { 32 | node.setNodeStatus({ fill: "green", shape: "dot", text: "Event " + _msg.payload.eventDescription }); 33 | }, 1000); 34 | } else { 35 | try { 36 | setTimeout(() => { 37 | node.setNodeStatus({ fill: "grey", shape: "dot", text: "Filtered " + _msg.payload.eventDescription }); 38 | }, 500); 39 | } catch (error) { } 40 | return; 41 | } 42 | } else { 43 | node.send([_msg, null]); 44 | setTimeout(() => { 45 | node.setNodeStatus({ fill: "green", shape: "dot", text: "Event " + _msg.payload.eventDescription }); 46 | }, 1000); 47 | } 48 | } 49 | } else { 50 | node.send([_msg, null]); 51 | try { 52 | setTimeout(() => { 53 | node.setNodeStatus({ fill: "green", shape: "dot", text: "Event " + _msg.payload.eventDescription }); 54 | }, 1000); 55 | } catch (error) { } 56 | } 57 | 58 | 59 | } 60 | 61 | // On each deploy, unsubscribe+resubscribe 62 | if (node.server) { 63 | node.server.removeClient(node); 64 | node.server.addClient(node); 65 | } 66 | 67 | this.on('input', function (msg) { 68 | 69 | }); 70 | 71 | node.on("close", function (done) { 72 | if (node.server) { 73 | node.server.removeClient(node); 74 | } 75 | done(); 76 | }); 77 | 78 | } 79 | 80 | RED.nodes.registerType("hikvisionUltimateAccessControlTerminal", hikvisionUltimateAccessControlTerminal); 81 | } -------------------------------------------------------------------------------- /nodes/hikvisionUltimateAlarmRaw.html: -------------------------------------------------------------------------------- 1 | 51 | 52 | 74 | 75 | -------------------------------------------------------------------------------- /nodes/hikvisionUltimateAlarmRaw.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports = function (RED) { 4 | function hikvisionUltimateAlarmRaw(config) { 5 | RED.nodes.createNode(this, config); 6 | var node = this; 7 | node.topic = config.topic || config.name; 8 | node.server = RED.nodes.getNode(config.server) 9 | 10 | node.setNodeStatus = ({ fill, shape, text }) => { 11 | var dDate = new Date(); 12 | node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" }) 13 | } 14 | 15 | // Called from config node, to send output to the flow 16 | node.sendPayload = (_msg, extension = '') => { 17 | if (_msg === null || _msg === undefined) return; 18 | _msg.topic = node.topic; 19 | if (_msg.hasOwnProperty("errorDescription")) { node.send([null, _msg, null]); return; }; // It's a connection error/restore comunication. 20 | if (!_msg.hasOwnProperty("payload") || (_msg.hasOwnProperty("payload") && _msg.payload === undefined)) return; 21 | 22 | if (_msg.type !== undefined && _msg.type === 'img') { 23 | _msg.extension = extension; 24 | node.send([null, null, _msg]); 25 | return; 26 | } 27 | 28 | 29 | // Heartbeat discard 30 | // 0 31 | // videoloss 32 | // inactive 33 | if (_msg.hasOwnProperty("payload") 34 | && _msg.payload.hasOwnProperty("eventType") 35 | && _msg.payload.eventType.toString().toLowerCase() === "videoloss" 36 | && _msg.payload.eventState.toString().toLowerCase() === "inactive" 37 | && _msg.payload.hasOwnProperty("activePostCount") && (Number(_msg.payload.activePostCount) === 0 || Number(_msg.payload.activePostCount) === 1)) { 38 | // It's a HertBeat, exit. 39 | node.setNodeStatus({ fill: "green", shape: "ring", text: "Waiting for alert..." }); 40 | return; 41 | }; 42 | 43 | node.setNodeStatus({ fill: "green", shape: "dot", text: "Alert received" }); 44 | node.send([_msg, null, null]); 45 | } 46 | 47 | // On each deploy, unsubscribe+resubscribe 48 | if (node.server) { 49 | node.server.removeClient(node); 50 | node.server.addClient(node); 51 | } 52 | 53 | this.on('input', function (msg) { 54 | 55 | }); 56 | 57 | node.on("close", function (done) { 58 | if (node.server) { 59 | node.server.removeClient(node); 60 | } 61 | done(); 62 | }); 63 | 64 | } 65 | 66 | RED.nodes.registerType("hikvisionUltimateAlarmRaw", hikvisionUltimateAlarmRaw); 67 | } -------------------------------------------------------------------------------- /nodes/hikvisionUltimateAxPro.html: -------------------------------------------------------------------------------- 1 | 53 | 54 | 77 | 78 | -------------------------------------------------------------------------------- /nodes/hikvisionUltimateAxPro.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash') 2 | 3 | module.exports = function (RED) { 4 | function hikvisionUltimateAxPro(config) { 5 | RED.nodes.createNode(this, config); 6 | var node = this; 7 | node.topic = config.topic || config.name; 8 | node.server = RED.nodes.getNode(config.server) 9 | node.zonesStatus = [] // Contains the status of all zones 10 | node.outputtype = Number(config.outputtype || 0) 11 | 12 | node.setNodeStatus = ({ fill, shape, text }) => { 13 | var dDate = new Date(); 14 | node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" }) 15 | } 16 | 17 | // Called from config node, to send output to the flow 18 | node.sendPayload = (_msg) => { 19 | if (_msg === null || _msg === undefined) return; 20 | _msg.topic = node.topic; 21 | if (_msg.hasOwnProperty("errorDescription")) { node.send([null, _msg]); return; }; // It's a connection error/restore comunication. 22 | // If heartbeat, return 23 | if (_msg.payload.hasOwnProperty("eventType") && _msg.payload.hasOwnProperty("eventState") && _msg.payload.eventType === "cidEvent" && _msg.payload.eventState === "inactive") return 24 | if ((node.outputtype === 0 || node.outputtype === 1) && _msg.payload.hasOwnProperty('CIDEvent')) { 25 | // ALARM EVENT 26 | node.send([{ payload: { CIDEvent: RED.util.cloneMessage(_msg.payload.CIDEvent) } }, null]); // Clone message to avoid adding _msgid 27 | } 28 | if ((node.outputtype === 0 || node.outputtype === 2) && _msg.payload.hasOwnProperty('ZoneList')) { 29 | // CHECK ONLY THE CHANGED ZONE STATUS 30 | for (let index = 0; index < _msg.payload.ZoneList.length; index++) { 31 | try { 32 | const receivedZone = _msg.payload.ZoneList[index].Zone; 33 | let foundInZoneStatus = node.zonesStatus.find((element) => element.id === receivedZone.id) 34 | if (!_.isEqual(foundInZoneStatus, receivedZone)) { 35 | if (foundInZoneStatus === undefined) { 36 | node.zonesStatus.push(receivedZone) // Add updated 37 | } else { 38 | node.zonesStatus[node.zonesStatus.findIndex((element) => element.id === receivedZone.id)] = receivedZone 39 | //node.zonesStatus.splice(foundInZoneStatus) 40 | //node.zonesStatus.push(receivedZone) // Add updated 41 | } 42 | node.setNodeStatus({ fill: "green", shape: "dot", text: "Zone changed " + receivedZone.name }); 43 | node.send([{ payload: { zoneUpdate: RED.util.cloneMessage(receivedZone) } }, null]); // Clone message to avoid adding _msgid 44 | } 45 | } catch (error) { } 46 | } 47 | } else { 48 | //node.send([_msg, null]) 49 | node.setNodeStatus({ fill: "green", shape: "ring", text: "Waiting for zone change" }); 50 | } 51 | 52 | } 53 | 54 | // On each deploy, unsubscribe+resubscribe 55 | if (node.server) { 56 | node.server.removeClient(node); 57 | node.server.addClient(node); 58 | } 59 | 60 | this.on('input', function (msg) { 61 | try { 62 | // Disarm Area 63 | if (msg.hasOwnProperty("disarmArea")) { 64 | node.server.disarmArea(msg.disarmArea) 65 | } 66 | // Arm Away Area 67 | if (msg.hasOwnProperty("armAwayArea")) { 68 | node.server.armAwayArea(msg.armAwayArea) 69 | } 70 | // Arm Stay Area 71 | if (msg.hasOwnProperty("armStayArea")) { 72 | node.server.armStayArea(msg.armStayArea) 73 | } 74 | // Clear Alarm Area 75 | if (msg.hasOwnProperty("clearAlarmArea")) { 76 | node.server.clearAlarmArea(msg.clearAlarmArea) 77 | } 78 | 79 | // Disarm All Area in a batch 80 | if (msg.hasOwnProperty("disarmAllAreas")) { 81 | node.server.disarmAllAreas() 82 | } 83 | // Clear All Alarm Areas 84 | if (msg.hasOwnProperty("clearAllAlarmAreas")) { 85 | node.server.clearAllAlarmAreas() 86 | } 87 | 88 | } catch (error) { } 89 | 90 | 91 | }); 92 | 93 | node.on("close", function (done) { 94 | if (node.server) { 95 | node.server.removeClient(node); 96 | } 97 | done(); 98 | }); 99 | 100 | } 101 | 102 | RED.nodes.registerType("hikvisionUltimateAxPro", hikvisionUltimateAxPro); 103 | } -------------------------------------------------------------------------------- /nodes/hikvisionUltimateDoorbell.html: -------------------------------------------------------------------------------- 1 | 55 | 56 | 151 | 152 | -------------------------------------------------------------------------------- /nodes/hikvisionUltimateDoorbell.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports = function (RED) { 4 | function hikvisionUltimateDoorbell(config) { 5 | RED.nodes.createNode(this, config); 6 | var node = this; 7 | node.topic = config.topic || config.name; 8 | node.server = RED.nodes.getNode(config.server) 9 | node.ringStatus = (config.ringStatus === null || config.ringStatus === undefined) ? "all" : config.ringStatus.toLowerCase(); 10 | node.floorNo = (config.floorNo === null || config.floorNo === undefined) ? "all" : config.floorNo; 11 | node.unitNo = (config.unitNo === null || config.unitNo === undefined) ? "all" : config.unitNo; 12 | node.zoneNo = (config.zoneNo === null || config.zoneNo === undefined) ? "all" : config.zoneNo; 13 | node.buildingNo = (config.buildingNo === null || config.buildingNo === undefined) ? "all" : config.buildingNo; 14 | node.currentEmittedMSG = {}; // To keep the current status and avoid emitting msg if already emitted. 15 | 16 | node.setNodeStatus = ({ fill, shape, text }) => { 17 | var dDate = new Date(); 18 | node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" }) 19 | } 20 | 21 | 22 | // Called from config node, to send output to the flow 23 | // Expected return JSON from ISAPI/VideoIntercom/callerInfo 24 | // { 25 | // "CallerInfo": { 26 | // "buildingNo": 1, 27 | // "floorNo": 1, 28 | // "zoneNo": 1, 29 | // "unitNo": 1, 30 | // "devNo": 88, 31 | // "devType": 1, 32 | // "lockNum": 1, 33 | // "status": "idle" ("idle,ring,onCall") 34 | // } 35 | // } 36 | // "devType":{ 1-door station, 2-master station, 37 | // 3-indoor station, 4-outer door station, 5-villa door station, 6-doorphone, 38 | // 7-Infosight Client Software, 8-iVMS-4200 Client Software, 9-APP, 39 | // 10-doorbell, 11-VOIP Client Software, 12-network camera, 13-access control device*/ 40 | node.sendPayload = (_msg) => { 41 | if (_msg === null || _msg === undefined) return; 42 | 43 | if (_msg.type !== undefined && _msg.type === 'img') { 44 | _msg.extension = extension; 45 | node.send([null, null, _msg]); 46 | return; 47 | } 48 | 49 | 50 | _msg.topic = node.topic; 51 | _msg.payload = true; 52 | if (_msg.hasOwnProperty("errorDescription")) { node.send([null, _msg]); return; }; // It's a connection error/restore comunication. 53 | //node.send([_msg, null]); 54 | if (_msg.hasOwnProperty("CallerInfo") && _msg.CallerInfo.hasOwnProperty("status")) { 55 | 56 | if ( 57 | ((node.ringStatus === "all" || node.ringStatus === _msg.CallerInfo.status.toString())) 58 | && (node.floorNo === "all" || node.floorNo === _msg.CallerInfo.floorNo.toString()) 59 | && (node.unitNo === "all" || node.unitNo === _msg.CallerInfo.unitNo.toString()) 60 | && (node.zoneNo === "all" || node.zoneNo === _msg.CallerInfo.zoneNo.toString()) 61 | && (node.buildingNo === "all" || node.buildingNo === _msg.CallerInfo.buildingNo.toString()) 62 | ) { 63 | delete _msg._msgid; // To allow objects compare 64 | delete node.currentEmittedMSG._msgid; // To allow objects compare 65 | 66 | if (RED.util.compareObjects(node.currentEmittedMSG, _msg)) return; // Omit sending the same notification more than once 67 | node.currentEmittedMSG = _msg; 68 | // Oputputs only msg that are no "idle" 69 | if (_msg.CallerInfo.status.toString() !== "idle") node.send([_msg, null]); 70 | } 71 | 72 | } 73 | } 74 | 75 | // On each deploy, unsubscribe+resubscribe 76 | if (node.server) { 77 | node.server.removeClient(node); 78 | node.server.addClient(node); 79 | } 80 | 81 | 82 | this.on('input', function (msg) { 83 | // node.request = async function (_callerNode, _method, _URL, _body) { 84 | 85 | if (msg.hasOwnProperty("openDoor")) { 86 | // Open the door latch 87 | let iDoor = msg.openDoor || 1; 88 | // 89 | // 90 | // 91 | // 92 | // 93 | // 94 | // 95 | // 96 | // 97 | // 98 | // 99 | let sBody = ` 100 | `+ iDoor + ` 101 | unlock 102 | HikvisionUltimate 103 | 104 | `; 105 | 106 | // Try with API 2.0 107 | node.server.request(node, "PUT", "/ISAPI/VideoIntercom/remoteOpenDoor", sBody).then(success => { 108 | node.setNodeStatus({ fill: "green", shape: "ring", text: "Door unlocked" }); 109 | msg.payload = true; 110 | node.send([msg, null]); 111 | }).catch(error => { 112 | // Try with API 1.0 113 | node.server.request(node, "PUT", "/ISAPI/AccessControl/RemoteControl/door/" + iDoor, "open").then(success => { 114 | node.setNodeStatus({ fill: "green", shape: "ring", text: "Door unlocked" }); 115 | msg.payload = true; 116 | node.send([msg, null]); 117 | }).catch(error => { 118 | node.setNodeStatus({ fill: "red", shape: "ring", text: "Error unlocking door " + error.message }); 119 | msg.payload = false; 120 | node.send([msg, null]); 121 | }); 122 | 123 | }); 124 | 125 | } 126 | 127 | if (msg.hasOwnProperty("hangUp")) { 128 | try { 129 | // Both calls are needed to stop current ring and call 130 | 131 | // Stop ringing. This stops the APP ringing. 132 | // Try with API 2.0, but with some firmware it doesn't work 133 | node.server.request(node, "DELETE", "/ISAPI/VideoIntercom/ring", "").then(success => { 134 | node.setNodeStatus({ fill: "green", shape: "ring", text: "Stop ringing" }); 135 | }).catch(error => { 136 | node.setNodeStatus({ fill: "red", shape: "ring", text: "Error stop ringing " + error.message }); 137 | RED.log.error("hikvisionUltimateDoorbell: Error stopping ring " + error.message); 138 | }); 139 | 140 | // Stop current call initiated by the intercom. This stops the intercom call. 141 | // Try with API 2.0 142 | setTimeout(() => { 143 | //const jHangUp = JSON.stringify(JSON.parse(`{"CallSignal": { "cmdType": "hangUp" } }`)); 144 | try { 145 | const jHangUp = JSON.parse(JSON.stringify(JSON.parse(`{"CallSignal": {"cmdType": "hangUp"}}`))) 146 | node.server.request(node, "PUT", "/ISAPI/VideoIntercom/callSignal?format=json", jHangUp).then(success => { 147 | node.setNodeStatus({ fill: "green", shape: "ring", text: "Hang Up" }); 148 | }).catch(error => { 149 | RED.log.error("hikvisionUltimateDoorbell: Error hangUp " + error.message); 150 | }); 151 | } catch (error) { 152 | } 153 | 154 | setTimeout(() => { 155 | try { 156 | const jReject = JSON.parse(JSON.stringify(JSON.parse(`{"CallSignal": {"cmdType": "reject"}}`))) 157 | node.server.request(node, "PUT", "/ISAPI/VideoIntercom/callSignal?format=json", jReject).then(success => { 158 | node.setNodeStatus({ fill: "green", shape: "ring", text: "reject" }); 159 | }).catch(error => { 160 | RED.log.error("hikvisionUltimateDoorbell: Error reject " + error.message); 161 | }); 162 | } catch (error) { 163 | } 164 | 165 | }, 1000); 166 | }, 1000); 167 | } catch (error) { 168 | 169 | } 170 | 171 | } 172 | 173 | 174 | 175 | }); 176 | 177 | node.on("close", function (done) { 178 | if (node.server) { 179 | node.server.removeClient(node); 180 | } 181 | if (node.server) { 182 | node.server.removeClient(node); 183 | } 184 | done(); 185 | }); 186 | 187 | } 188 | 189 | RED.nodes.registerType("hikvisionUltimateDoorbell", hikvisionUltimateDoorbell); 190 | } -------------------------------------------------------------------------------- /nodes/hikvisionUltimatePTZ.html: -------------------------------------------------------------------------------- 1 | 53 | 54 | 132 | 133 | -------------------------------------------------------------------------------- /nodes/hikvisionUltimatePTZ.js: -------------------------------------------------------------------------------- 1 | module.exports = function (RED) { 2 | function hikvisionUltimatePTZ(config) { 3 | RED.nodes.createNode(this, config); 4 | var node = this; 5 | node.topic = config.topic || node.name; 6 | node.server = RED.nodes.getNode(config.server) 7 | node.PTZPreset = (config.PTZPreset === null || config.PTZPreset === undefined) ? "1" : config.PTZPreset; 8 | node.channelID = (config.channelID === null || config.channelID === undefined) ? "1" : config.channelID; 9 | 10 | node.setNodeStatus = ({ fill, shape, text }) => { 11 | var dDate = new Date(); 12 | node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" }) 13 | } 14 | 15 | // Called from config node, to send output to the flow 16 | node.sendPayload = (_msg) => { 17 | if (_msg === null || _msg === undefined) return; 18 | 19 | if (_msg.type !== undefined && _msg.type === 'img') { 20 | // The payload is an image, exit. 21 | return; 22 | } 23 | 24 | _msg.topic = node.topic; 25 | if (_msg.hasOwnProperty("errorDescription")) { node.send([null, _msg]); return; }; // It's a connection error/restore comunication. 26 | if (!_msg.hasOwnProperty("payload") || (_msg.hasOwnProperty("payload") && _msg.payload === undefined)) return; 27 | 28 | if (_msg.hasOwnProperty("payload")) { 29 | if (_msg.payload.hasOwnProperty("eventType")) { 30 | // Chech if it's only a hearbeat alarm 31 | try { 32 | var sAlarmType = _msg.payload.eventType.toString().toLowerCase(); 33 | if (sAlarmType === "videoloss" && _msg.payload.hasOwnProperty("activePostCount") && _msg.payload.activePostCount == "0") { 34 | node.setNodeStatus({ fill: "green", shape: "ring", text: "Received HeartBeat (the device is online)" }); 35 | return; // It's a Heartbeat 36 | } 37 | } catch (error) { } 38 | } 39 | } 40 | node.send([_msg, null]); 41 | node.setNodeStatus({ fill: "green", shape: "dot", text: "PTZ Pteset recalled." }); 42 | } 43 | 44 | // On each deploy, unsubscribe+resubscribe 45 | if (node.server) { 46 | node.server.removeClient(node); 47 | node.server.addClient(node); 48 | } 49 | 50 | this.on('input', function (msg) { 51 | if (msg === null || msg === undefined) return; 52 | if (msg.hasOwnProperty("payload") && msg.hasOwnProperty("payload") !== null && msg.hasOwnProperty("payload") !== undefined) { 53 | if (typeof msg.payload === "boolean" && msg.payload === true) { 54 | recallPTZ(); 55 | } else if (typeof msg.payload === "object") { 56 | // Set the preset via input msg 57 | if (msg.payload.hasOwnProperty("channelID")) node.channelID = msg.payload.channelID; 58 | if (msg.payload.hasOwnProperty("PTZPreset")) node.PTZPreset = msg.payload.PTZPreset; 59 | node.setNodeStatus({ fill: "green", shape: "dot", text: "Preset passed by msg input." }); 60 | recallPTZ(); 61 | } 62 | } 63 | 64 | }); 65 | 66 | // Recalls the PTZ 67 | function recallPTZ() { 68 | // Recall PTZ Preset 69 | // Params: _callerNode, _method, _URL, _body 70 | try { 71 | node.server.request(node, "PUT", "/ISAPI/PTZCtrl/channels/" + node.channelID + "/presets/" + node.PTZPreset + "/goto", ""); 72 | } catch (error) { 73 | 74 | } 75 | } 76 | 77 | node.on("close", function (done) { 78 | if (node.server) { 79 | node.server.removeClient(node); 80 | } 81 | done(); 82 | }); 83 | 84 | } 85 | 86 | RED.nodes.registerType("hikvisionUltimatePTZ", hikvisionUltimatePTZ); 87 | } -------------------------------------------------------------------------------- /nodes/hikvisionUltimatePicture.html: -------------------------------------------------------------------------------- 1 | 174 | 175 | 322 | 323 | -------------------------------------------------------------------------------- /nodes/hikvisionUltimatePicture.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = function (RED) { 3 | 4 | const jimp = require("jimp"); // Resize 5 | 6 | 7 | function hikvisionUltimatePicture(config) { 8 | RED.nodes.createNode(this, config); 9 | var node = this; 10 | node.topic = config.topic || config.name; 11 | node.server = RED.nodes.getNode(config.server) 12 | node.picture; // Stores the cam image 13 | node.pictureLarghezza = 0; 14 | node.pictureAltezza = 0; 15 | node.urlImageCurrentIndex = config.urlImageCurrentIndex === undefined ? 0 : config.urlImageCurrentIndex; // Stores the valid URL 16 | node.previousInputMessage = {}; // 01/09/2022 previous msg input to be passet to the output 17 | 18 | node.setNodeStatus = ({ fill, shape, text }) => { 19 | var dDate = new Date(); 20 | node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" }) 21 | } 22 | 23 | // 15/12/2020 apply the manipulation to the node's variable 24 | node.variabilizeManipulation = (_config) => { 25 | node.channelID = (_config.channelID === null || _config.channelID === undefined) ? "1" : _config.channelID; 26 | node.qualityimage = (_config.qualityimage === null || _config.qualityimage === undefined || _config.qualityimage.trim() === "") ? "80" : _config.qualityimage; 27 | node.rotateimage = (_config.rotateimage === null || _config.rotateimage === undefined) ? "0" : _config.rotateimage; 28 | node.widthimage = (_config.widthimage === null || _config.widthimage === undefined || _config.widthimage.trim() === "") ? "0" : _config.widthimage; 29 | node.heightimage = (_config.heightimage === null || _config.heightimage === undefined || _config.heightimage.trim() === "") ? "0" : _config.heightimage; 30 | node.cropimage = (_config.cropimage === null || _config.cropimage === undefined || _config.cropimage.trim() === "") ? "" : _config.cropimage; 31 | // 27/01/2021 Fonts 32 | node.textoverlay = (_config.textoverlay === null || _config.textoverlay === undefined || _config.textoverlay.trim() === "") ? "" : _config.textoverlay; 33 | node.textoverlayXY = (_config.textoverlayXY === null || _config.textoverlayXY === undefined || _config.textoverlayXY.trim() === "") ? "0,0" : _config.textoverlayXY; 34 | node.textoverlayWH = (_config.textoverlayWH === null || _config.textoverlayWH === undefined || _config.textoverlayWH.trim() === "") ? "" : _config.textoverlayWH; 35 | node.textoverlayFont = (_config.textoverlayFont === null || _config.textoverlayFont === undefined || _config.textoverlayFont.trim() === "") ? "FONT_SANS_32_WHITE" : _config.textoverlayFont; 36 | 37 | node.urlImage = ["/ISAPI/Streaming/channels/" + node.channelID + "01/picture", "/ISAPI/ContentMgmt/StreamingProxy/channels/" + node.channelID + "01/picture"]; // Stores all URLS the node will try to get images from 38 | //node.urlImage = ["/ISAPI/ContentMgmt/StreamingProxy/channels/" + node.channelID + "01/picture", "/ISAPI/Streaming/channels/" + node.channelID + "01/picture"]; // Stores all URLS the node will try to get images from 39 | if (node.urlImageCurrentIndex > node.urlImage.length - 1) node.urlImageCurrentIndex = 0; 40 | 41 | if (node.cropimage !== "" && node.cropimage.split(",").length === 4) { 42 | node.cropimage = { 43 | x: Number(node.cropimage.split(",")[0].trim()), 44 | y: Number(node.cropimage.split(",")[1].trim()), 45 | w: Number(node.cropimage.split(",")[2].trim()), 46 | h: Number(node.cropimage.split(",")[3].trim()) 47 | } 48 | } else { 49 | node.cropimage = ""; 50 | } 51 | 52 | if (node.textoverlayXY !== "" && node.textoverlayXY.split(",").length === 2) { 53 | node.textoverlayXY = { 54 | x: Number(node.textoverlayXY.split(",")[0].trim()), 55 | y: Number(node.textoverlayXY.split(",")[1].trim()) 56 | } 57 | } else { 58 | node.textoverlayXY = ""; 59 | } 60 | 61 | if (node.textoverlayWH !== "" && node.textoverlayWH.split(",").length === 2) { 62 | node.textoverlayWH = { 63 | w: Number(node.textoverlayWH.split(",")[0].trim()), 64 | h: Number(node.textoverlayWH.split(",")[1].trim()) 65 | } 66 | } else { 67 | node.textoverlayWH = ""; 68 | } 69 | } 70 | node.variabilizeManipulation(config); 71 | 72 | 73 | 74 | // 14/12/2020 Get the picture image from camera 75 | RED.httpAdmin.get("/hikvisionUltimateGetPicture", RED.auth.needsPermission('hikvisionUltimatePicture.read'), function (req, res) { 76 | if (typeof req.query.serverID !== "undefined" && req.query.serverID !== null && req.query.serverID !== "") { 77 | var _nodeServer = RED.nodes.getNode(req.query.serverID);// Retrieve node.id of the config node. 78 | // Create the config object 79 | //#region CREATING CONFIG 80 | var sManipulate = req.query.manipulate; 81 | var oConfig = { channelID: sManipulate.split("-SEP-")[0].toString().trim() }; 82 | oConfig.qualityimage = sManipulate.split("-SEP-")[1].toString().trim(); 83 | oConfig.rotateimage = sManipulate.split("-SEP-")[2].toString().trim(); 84 | oConfig.widthimage = sManipulate.split("-SEP-")[3].toString().trim(); 85 | oConfig.heightimage = sManipulate.split("-SEP-")[4].toString().trim(); 86 | oConfig.cropimage = sManipulate.split("-SEP-")[5].toString().trim().replace(/-/g, ","); 87 | oConfig.textoverlay = sManipulate.split("-SEP-")[6].toString().trim(); 88 | oConfig.textoverlayXY = sManipulate.split("-SEP-")[7].toString().trim().replace(/-/g, ","); 89 | oConfig.textoverlayWH = sManipulate.split("-SEP-")[8].toString().trim().replace(/-/g, ","); 90 | oConfig.textoverlayFont = sManipulate.split("-SEP-")[9].toString().trim(); 91 | node.urlImageCurrentIndex = (sManipulate.split("-SEP-")[10].toString().trim() === "YES" ? 0 : node.urlImageCurrentIndex); // Retry from beginning, to find the right image url 92 | 93 | node.variabilizeManipulation(oConfig); 94 | //#endregion 95 | 96 | //console.log("MAN " + JSON.stringify(oConfig)) 97 | if (_nodeServer === null) { 98 | res.json({ picture: "", width: 0, height: 0 }); 99 | } else { 100 | node.picture = null; 101 | node.server = _nodeServer; 102 | // Call the request, that then sends the result via node.sendPayload function 103 | node.server.request(node, "GET", node.urlImage[node.urlImageCurrentIndex], null).then(success => { 104 | // Wait until the server has called node.sendPayload and node.sendPayload has populated the node.picture variable 105 | var iTimeout = 0; 106 | var CB = () => { 107 | iTimeout += 1; 108 | if (iTimeout >= 15) { 109 | // Set the URL to the next in the list, so it can retry with that url in SendPayload 110 | node.urlImageCurrentIndex += 1; 111 | if (node.urlImageCurrentIndex > node.urlImage.length - 1) { 112 | // No more URLs to try 113 | node.urlImageCurrentIndex = 0; 114 | res.json({ picture: "", width: " !Error getting picture Timeout! ", height: 0 }); 115 | } else { 116 | // Cycled through all URLS 117 | res.json({ picture: "", width: " !Retry new URL... ", height: 0 }); 118 | } 119 | return; 120 | } else { 121 | if (node.picture !== null) { 122 | res.json({ picture: node.picture, width: node.pictureLarghezza, height: node.pictureAltezza, urlImageCurrentIndex: node.urlImageCurrentIndex }); 123 | return; 124 | } 125 | setTimeout(CB, 500); 126 | } 127 | } 128 | setTimeout(CB, 500); 129 | 130 | }).catch(error => { 131 | // No more URLs to try 132 | node.urlImageCurrentIndex = 0; 133 | res.json({ picture: "", width: " !Error getting picture! ", height: " !" + error.message + "! " }); 134 | }); 135 | } 136 | } else { res.json({ picture: "", width: 0, height: 0 }); } 137 | }); 138 | 139 | // Get picture 140 | // node.getPicture = (_picBase64) => new Promise(function (resolve, reject) { 141 | // try { 142 | // jimp.read(_picBase64) 143 | // .then(image => { 144 | // if (node.rotateimage !== 0) image = image.rotate(Number(node.rotateimage)); 145 | // if (node.cropimage !== "") image = image.crop(node.cropimage.x, node.cropimage.y, node.cropimage.w, node.cropimage.h); 146 | // if (node.heightimage !== "0" && node.widthimage !== "0") image = image.resize(Number(node.widthimage), Number(node.heightimage)); 147 | // if (node.qualityimage !== 100) image = image.quality(Number(node.qualityimage)); 148 | // node.pictureLarghezza = image.bitmap.width; 149 | // node.pictureAltezza = image.bitmap.height; 150 | 151 | // jimp.loadFont(jimp.FONT_SANS_32_WHITE).then(font => { 152 | // image = image.print(font, 10, 10, 'Hello World!'); 153 | // }).catch(err => { }); 154 | 155 | // image.getBufferAsync(jimp.MIME_JPEG).then(picture => { 156 | // node.picture = "data:image/jpg;base64," + picture.toString("base64"); 157 | // resolve(node.picture); 158 | // }).catch(error => { 159 | // reject(error); 160 | // }); 161 | // }); 162 | // } catch (error) { 163 | // reject(error); 164 | // } 165 | // }); 166 | 167 | // Get picture 168 | async function getPicture(_picBase64) { 169 | try { 170 | image = await jimp.read(_picBase64); 171 | if (node.rotateimage !== 0) image = await image.rotate(Number(node.rotateimage)); 172 | if (node.cropimage !== "") image = await image.crop(node.cropimage.x, node.cropimage.y, node.cropimage.w, node.cropimage.h); 173 | if (node.heightimage !== "0" && node.widthimage !== "0") image = await image.resize(Number(node.widthimage), Number(node.heightimage)); 174 | if (node.qualityimage !== 100) image = await image.quality(Number(node.qualityimage)); 175 | node.pictureLarghezza = image.bitmap.width; 176 | node.pictureAltezza = image.bitmap.height; 177 | 178 | // 27/01/2021 FONTS 179 | if (node.textoverlay !== "") { 180 | const oFont = jimp[node.textoverlayFont]; 181 | try { 182 | const font = await jimp.loadFont(oFont); 183 | if (node.textoverlayWH === "") { 184 | image = await image.print(font, node.textoverlayXY.x, node.textoverlayXY.y, { 185 | text: node.textoverlay, 186 | alignmentX: jimp.HORIZONTAL_ALIGN_LEFT, 187 | alignmentY: jimp.VERTICAL_ALIGN_TOP 188 | }); 189 | } else { 190 | image = await image.print(font, node.textoverlayXY.x, node.textoverlayXY.y, { 191 | text: node.textoverlay, 192 | alignmentX: jimp.HORIZONTAL_ALIGN_LEFT, 193 | alignmentY: jimp.VERTICAL_ALIGN_TOP 194 | }, node.textoverlayWH.w, node.textoverlayWH.h); 195 | } 196 | } catch (error) { 197 | 198 | } 199 | 200 | } 201 | 202 | let picture = await image.getBufferAsync(jimp.MIME_JPEG); 203 | let b64 = picture.toString("base64"); 204 | node.picture = "data:image/jpg;base64," + b64; 205 | // Return various type of picture formats 206 | return ({ 207 | forUI: node.picture, forEmail: picture, base64: b64 208 | }); 209 | 210 | } catch (error) { 211 | return (error); 212 | } 213 | }; 214 | 215 | 216 | // Called from config node, to send output to the flow 217 | node.sendPayload = (_msg) => { 218 | if (_msg === null || _msg === undefined) return; 219 | 220 | if (_msg.type !== undefined && _msg.type === 'img') { 221 | // Coming from an event containing an image 222 | return; 223 | } 224 | // 01/09/2022 Add the previous input message 225 | _msg.previousInputMessage = node.previousInputMessage; 226 | _msg.topic = node.topic; 227 | if (_msg.hasOwnProperty("errorDescription")) { node.send([null, _msg]); return; }; // It's a connection error/restore comunication. 228 | if (!_msg.hasOwnProperty("payload") || (_msg.hasOwnProperty("payload") && _msg.payload === undefined)) return; 229 | 230 | // 07/04/2021 The server has got a wrong response from camera/NVR 231 | if (_msg.hasOwnProperty("wrongResponse")) { 232 | // Maybe the URL was not working because the NVR is old or requires another URL 233 | // Try with another URL 234 | node.setNodeStatus({ fill: "yellow", shape: "ring", text: "Got wrong response. Trying wit another URL." }); 235 | // Call the request, that then sends the result via node.sendPayload function 236 | //console.log("BANANA FIGA NON VA CON", node.urlImage[node.urlImageCurrentIndex]); 237 | if (node.server.debug) RED.log.info("BANANA TRYING GETTING IMAGE WITH", node.urlImage[node.urlImageCurrentIndex]); 238 | //console.log("BANANA PROVA CON", node.urlImage[node.urlImageCurrentIndex]); 239 | node.server.request(node, "GET", node.urlImage[node.urlImageCurrentIndex], null); // Hybrid NVR get image from an IP camera 240 | 241 | return; 242 | } 243 | 244 | if (_msg.payload.hasOwnProperty("eventType")) { 245 | // Chech if it's only a hearbeat alarm 246 | try { 247 | var sAlarmType = _msg.payload.eventType.toString().toLowerCase(); 248 | if (sAlarmType === "videoloss" && _msg.payload.hasOwnProperty("activePostCount") && _msg.payload.activePostCount == "0") { 249 | node.setNodeStatus({ fill: "green", shape: "ring", text: "Received HeartBeat (the device is online)" }); 250 | return; // It's a Heartbeat 251 | } 252 | } catch (error) { } 253 | return; 254 | } 255 | 256 | 257 | getPicture(_msg.payload).then(data => { 258 | _msg.payload = data.forUI; 259 | _msg.forEmail = data.forEmail; 260 | _msg.base64 = data.base64; 261 | node.send(_msg, null); 262 | node.setNodeStatus({ fill: "green", shape: "dot", text: "Picture received" }); 263 | }).catch(error => { 264 | node.setNodeStatus({ fill: "red", shape: "dot", text: "GetBuffer error: " + error.message }); 265 | }) 266 | 267 | 268 | } 269 | 270 | // On each deploy, unsubscribe+resubscribe 271 | if (node.server) { 272 | node.server.removeClient(node); 273 | node.server.addClient(node); 274 | } 275 | 276 | this.on('input', function (msg) { 277 | if (msg === null || msg === undefined) return; 278 | // 01/09/2022 Save the original message to be passed through and sent out 279 | node.previousInputMessage = msg; 280 | if (msg.hasOwnProperty("textoverlay")) node.textoverlay = msg.textoverlay; 281 | 282 | if (msg.hasOwnProperty("payload") && msg.payload !== null && msg.payload !== undefined) { 283 | if (msg.payload === true) { 284 | try { 285 | // Call the request, that then sends the result via node.sendPayload function 286 | node.server.request(node, "GET", node.urlImage[node.urlImageCurrentIndex], null); 287 | } catch (error) { 288 | 289 | } 290 | } 291 | } 292 | 293 | }); 294 | 295 | node.on("close", function (done) { 296 | if (node.server) { 297 | node.server.removeClient(node); 298 | } 299 | done(); 300 | }); 301 | 302 | } 303 | 304 | RED.nodes.registerType("hikvisionUltimatePicture", hikvisionUltimatePicture); 305 | } -------------------------------------------------------------------------------- /nodes/hikvisionUltimateSpeaker.html: -------------------------------------------------------------------------------- 1 | 109 | 110 | 138 | 139 | -------------------------------------------------------------------------------- /nodes/hikvisionUltimateSpeaker.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports = function (RED) { 4 | function hikvisionUltimateSpeaker(config) { 5 | RED.nodes.createNode(this, config); 6 | var node = this; 7 | node.topic = config.topic || config.name; 8 | node.server = RED.nodes.getNode(config.server) 9 | 10 | 11 | node.setNodeStatus = ({ fill, shape, text }) => { 12 | var dDate = new Date(); 13 | node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" }) 14 | } 15 | 16 | // Called from config node, to send output to the flow 17 | node.sendPayload = (_msg) => { 18 | if (_msg === null || _msg === undefined) return; 19 | _msg.topic = node.topic; 20 | if (_msg.hasOwnProperty("errorDescription")) { node.send([null, _msg]); return; }; // It's a connection error/restore comunication. 21 | if (!_msg.hasOwnProperty("payload") || (_msg.hasOwnProperty("payload") && (_msg.payload === undefined || _msg.payload === null))) return; 22 | 23 | 24 | node.send([_msg, null]); 25 | try { 26 | //node.setNodeStatus({ fill: "green", shape: "dot", text: "Plate " + _msg.payload }); 27 | } catch (error) { } 28 | } 29 | 30 | // On each deploy, unsubscribe+resubscribe 31 | if (node.server) { 32 | node.server.removeClient(node); 33 | node.server.addClient(node); 34 | } 35 | 36 | this.on('input', function (msg) { 37 | if (msg.payload === true) { 38 | (async () => { 39 | msg.payload = await node.server.playAloud(config.customAudioID, config.volume); 40 | node.send([msg, null]); 41 | node.setNodeStatus({ fill: "green", shape: "dot", text: "Play" }); 42 | })(); 43 | } 44 | if (msg.payload === false) { 45 | (async () => { 46 | msg.payload = await node.server.stopFile(config.customAudioID); 47 | node.send([msg, null]); 48 | node.setNodeStatus({ fill: "grey", shape: "dot", text: "Stop" }); 49 | })(); 50 | } 51 | }); 52 | 53 | node.on("close", function (done) { 54 | if (node.server) { 55 | node.server.removeClient(node); 56 | } 57 | done(); 58 | }); 59 | 60 | } 61 | 62 | RED.nodes.registerType("hikvisionUltimateSpeaker", hikvisionUltimateSpeaker); 63 | } -------------------------------------------------------------------------------- /nodes/hikvisionUltimateText.html: -------------------------------------------------------------------------------- 1 | 57 | 58 | 134 | 135 | -------------------------------------------------------------------------------- /nodes/hikvisionUltimateText.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports = function (RED) { 4 | function hikvisionUltimateText(config) { 5 | RED.nodes.createNode(this, config); 6 | var node = this; 7 | node.server = RED.nodes.getNode(config.server) 8 | node.row1 = config.row1 === undefined ? "" : config.row1; 9 | node.row1XY = config.row1XY === undefined ? "" : config.row1XY; 10 | node.row2 = config.row2 === undefined ? "" : config.row2; 11 | node.row2XY = config.row2XY === undefined ? "" : config.row2XY; 12 | node.row3 = config.row3 === undefined ? "" : config.row3; 13 | node.row3XY = config.row3XY === undefined ? "" : config.row3XY; 14 | node.row4 = config.row4 === undefined ? "" : config.row4; 15 | node.row4XY = config.row4XY === undefined ? "" : config.row4XY; 16 | node.channelID = config.channelID === undefined ? "1" : config.channelID; 17 | 18 | 19 | node.setNodeStatus = ({ fill, shape, text }) => { 20 | var dDate = new Date(); 21 | node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" }) 22 | } 23 | 24 | 25 | 26 | this.on('input', function (msg) { 27 | 28 | // Overrides 29 | if (msg.hasOwnProperty("row1")) node.row1 = msg.row1; 30 | if (msg.hasOwnProperty("row1XY")) node.row1XY = msg.row1XY; 31 | if (msg.hasOwnProperty("row2")) node.row2 = msg.row2; 32 | if (msg.hasOwnProperty("row2XY")) node.row2XY = msg.row2XY; 33 | if (msg.hasOwnProperty("row3")) node.row3 = msg.row3; 34 | if (msg.hasOwnProperty("row3XY")) node.row3XY = msg.row3XY; 35 | if (msg.hasOwnProperty("row4")) node.row4 = msg.row4; 36 | if (msg.hasOwnProperty("row4XY")) node.row4XY = msg.row4XY; 37 | if (msg.hasOwnProperty("channelid")) node.channelID = msg.channelid; 38 | 39 | let sRows = ` 40 | 41 | 42 | 43 | 1 44 | ` + (node.row1.trim() === "" ? "false" : "true") + ` 45 | ` + (node.row1XY.trim() === "" ? "" : node.row1XY.split(",")[0]) + ` 46 | ` + (node.row1XY.trim() === "" ? "" : node.row1XY.split(",")[1]) + ` 47 | ` + node.row1 + ` 48 | 49 | 50 | 51 | 2 52 | ` + (node.row2.trim() === "" ? "false" : "true") + ` 53 | ` + (node.row2XY.trim() === "" ? "" : node.row2XY.split(",")[0]) + ` 54 | ` + (node.row2XY.trim() === "" ? "" : node.row2XY.split(",")[1]) + ` 55 | ` + node.row2 + ` 56 | 57 | 58 | 59 | 3 60 | ` + (node.row3.trim() === "" ? "false" : "true") + ` 61 | ` + (node.row3XY.trim() === "" ? "" : node.row3XY.split(",")[0]) + ` 62 | ` + (node.row3XY.trim() === "" ? "" : node.row3XY.split(",")[1]) + ` 63 | ` + node.row3 + ` 64 | 65 | 66 | 67 | 4 68 | ` + (node.row4.trim() === "" ? "false" : "true") + ` 69 | ` + (node.row4XY.trim() === "" ? "" : node.row4XY.split(",")[0]) + ` 70 | ` + (node.row4XY.trim() === "" ? "" : node.row4XY.split(",")[1]) + ` 71 | ` + node.row4 + ` 72 | 73 | 74 | `; 75 | 76 | 77 | node.setNodeStatus({ fill: "green", shape: "ring", text: "OK" }); 78 | try { 79 | // Params: _callerNode, _method, _URL, _body 80 | node.server.request(node, "PUT", "/ISAPI/System/Video/inputs/channels/" + node.channelID + "/overlays/text", sRows); 81 | } catch (error) { 82 | // Try this, maybe the device is an old Turbo DVR 83 | try { 84 | node.server.request(node, "PUT", "/ISAPI/System/Video/inputs/channels/" + node.channelID + "/overlays", sRows); 85 | } catch (error) { } 86 | } 87 | 88 | }); 89 | 90 | // Called from config node, to send output to the flow 91 | node.sendPayload = (_msg) => { 92 | 93 | }; 94 | 95 | 96 | node.on("close", function (done) { 97 | done(); 98 | }); 99 | 100 | } 101 | 102 | RED.nodes.registerType("hikvisionUltimateText", hikvisionUltimateText); 103 | } -------------------------------------------------------------------------------- /nodes/hikvisionUltimateXML.html: -------------------------------------------------------------------------------- 1 | 62 | 63 | 98 | 99 | -------------------------------------------------------------------------------- /nodes/hikvisionUltimateXML.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports = function (RED) { 4 | function hikvisionUltimateXML(config) { 5 | RED.nodes.createNode(this, config); 6 | var node = this; 7 | node.server = RED.nodes.getNode(config.server) 8 | node.xmlText = config.xmlText === undefined ? "" : config.xmlText; 9 | node.path = config.path === undefined ? "" : config.path; 10 | node.method = config.method === undefined ? "PUT" : config.method; 11 | 12 | 13 | node.setNodeStatus = ({ fill, shape, text }) => { 14 | var dDate = new Date(); 15 | node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" }) 16 | } 17 | 18 | // Called from config node, to send output to the flow 19 | node.sendPayload = (_msg) => { 20 | if (_msg.type !== undefined && _msg.type === 'img') { 21 | // The payload is an image, exit. 22 | return; 23 | } 24 | node.setNodeStatus({ fill: "green", shape: "ring", text: "Received response" }); 25 | if (_msg === null || _msg === undefined) return; 26 | node.send(_msg); 27 | 28 | } 29 | 30 | this.on('input', function (msg) { 31 | 32 | // Overrides 33 | if (msg.hasOwnProperty("XML")) node.xmlText = msg.XML; 34 | if (msg.hasOwnProperty("path")) node.path = msg.path; 35 | if (msg.hasOwnProperty("method")) node.method = msg.method; 36 | 37 | node.setNodeStatus({ fill: "green", shape: "ring", text: "Send request..." }); 38 | try { 39 | // Params: _callerNode, _method, _URL, _body, _fromXMLNode 40 | node.server.request(node, node.method, node.path, node.xmlText, true); 41 | } catch (error) { 42 | 43 | } 44 | 45 | }); 46 | 47 | 48 | node.on("close", function (done) { 49 | done(); 50 | }); 51 | 52 | } 53 | 54 | RED.nodes.registerType("hikvisionUltimateXML", hikvisionUltimateXML); 55 | } -------------------------------------------------------------------------------- /nodes/icons/camera-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/nodes/icons/camera-icon.png -------------------------------------------------------------------------------- /nodes/icons/camera-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /nodes/icons/node-alarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/nodes/icons/node-alarm.png -------------------------------------------------------------------------------- /nodes/icons/node-alarm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /nodes/icons/node-anpr-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/nodes/icons/node-anpr-icon.png -------------------------------------------------------------------------------- /nodes/icons/node-anpr-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /nodes/icons/node-radar-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/nodes/icons/node-radar-icon.png -------------------------------------------------------------------------------- /nodes/icons/node-radar-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /nodes/icons/node-raw-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/nodes/icons/node-raw-icon.png -------------------------------------------------------------------------------- /nodes/icons/node-raw-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /nodes/icons/ptz-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Supergiovane/node-red-contrib-hikvision-ultimate/26609177ef5ea918e3ae839151351174121f3098/nodes/icons/ptz-icon.png -------------------------------------------------------------------------------- /nodes/icons/ptz-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /nodes/utils/AccessControlEvents/MAJOR_ALARM-0x1.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ShortDescription": "MINOR_ALARMIN_SHORT_CIRCUIT", 4 | "Value": "0x400", 5 | "Description": "Zone Short Circuit Attempts Alarm" 6 | }, 7 | { 8 | "ShortDescription": "MINOR_ALARMIN_BROKEN_CIRCUIT", 9 | "Value": "0x401", 10 | "Description": "Zone Disconnected Alarm" 11 | }, 12 | { 13 | "ShortDescription": "MINOR_ALARMIN_EXCEPTION", 14 | "Value": "0x402", 15 | "Description": "Zone Exception Alarm" 16 | }, 17 | { 18 | "ShortDescription": "MINOR_ALARMIN_RESUME", 19 | "Value": "0x403", 20 | "Description": "Zone Restored" 21 | }, 22 | { 23 | "ShortDescription": "MINOR_HOST_DESMANTLE_ALARM", 24 | "Value": "0x404", 25 | "Description": "Zone Tampering Alarm" 26 | }, 27 | { 28 | "ShortDescription": "MINOR_HOST_DESMANTLE_RESUME", 29 | "Value": "0x405", 30 | "Description": "Zone Tampering Restored" 31 | }, 32 | { 33 | "ShortDescription": "MINOR_CARD_READER_DESMANTLE_ALARM", 34 | "Value": "0x406", 35 | "Description": "Card Reader Tampering Alarm" 36 | }, 37 | { 38 | "ShortDescription": "MINOR_CARD_READER_DESMANTLE_RESUME", 39 | "Value": "0x407", 40 | "Description": "Card Reader Tampering Restored" 41 | }, 42 | { 43 | "ShortDescription": "MINOR_CASE_SENSOR_ALARM", 44 | "Value": "0x408", 45 | "Description": "Alarm Input Alarm Triggered" 46 | }, 47 | { 48 | "ShortDescription": "MINOR_CASE_SENSOR_RESUME", 49 | "Value": "0x409", 50 | "Description": "Alarm Input Restored" 51 | }, 52 | { 53 | "ShortDescription": "MINOR_STRESS_ALARM", 54 | "Value": "0x40a", 55 | "Description": "Duress Alarm" 56 | }, 57 | { 58 | "ShortDescription": "MINOR_OFFLINE_ECENT_NEARLY_FULL", 59 | "Value": "0x40b", 60 | "Description": "No Memory for Offline Event Storage Alarm" 61 | }, 62 | { 63 | "ShortDescription": "MINOR_CARD_MAX_AUTHENTICATE_FAIL", 64 | "Value": "0x40c", 65 | "Description": "Maximum Failed Card Authentications Alarm" 66 | }, 67 | { 68 | "ShortDescription": "MINOR_SD_CARD_FULL", 69 | "Value": "0x40d", 70 | "Description": "SD Card Full Alarm" 71 | }, 72 | { 73 | "ShortDescription": "MINOR_LINKAGE_CAPTURE_PIC", 74 | "Value": "0x40e", 75 | "Description": "Capture Linkage Alarm" 76 | }, 77 | { 78 | "ShortDescription": "MINOR_SECURITY_MODULE_DESMANTLE_ALARM", 79 | "Value": "0x40f", 80 | "Description": "Secure Door Control Unit Tampering Alarm" 81 | }, 82 | { 83 | "ShortDescription": "MINOR_SECURITY_MODULE_DESMANTLE_RESUME", 84 | "Value": "0x410", 85 | "Description": "Secure Door Control Unit Tampering Restored" 86 | }, 87 | { 88 | "ShortDescription": "MINOR_FIRE_IMPORT_SHORT_CIRCUIT", 89 | "Value": "0x415", 90 | "Description": "Fire Input Short Circuit Attempts Alarm" 91 | }, 92 | { 93 | "ShortDescription": "MINOR_FIRE_IMPORT_BROKEN_CIRCUIT", 94 | "Value": "0x416", 95 | "Description": "Fire Input Open Circuit Attempts Alarm" 96 | }, 97 | { 98 | "ShortDescription": "MINOR_FIRE_IMPORT_RESUME", 99 | "Value": "0x417", 100 | "Description": "Fire Input Restored" 101 | }, 102 | { 103 | "ShortDescription": "MINOR_FIRE_BUTTON_TRIGGER", 104 | "Value": "0x418", 105 | "Description": "Fire Button Triggered" 106 | }, 107 | { 108 | "ShortDescription": "MINOR_FIRE_BUTTON_RESUME", 109 | "Value": "0x419", 110 | "Description": "Fire Button Resumed" 111 | }, 112 | { 113 | "ShortDescription": "MINOR_MAINTENANCE_BUTTON_TRIGGER", 114 | "Value": "0x41a", 115 | "Description": "Maintenance Button Triggered" 116 | }, 117 | { 118 | "ShortDescription": "MINOR_MAINTENANCE_BUTTON_RESUME", 119 | "Value": "0x41b", 120 | "Description": "Maintenance Button Resumed" 121 | }, 122 | { 123 | "ShortDescription": "MINOR_EMERGENCY_BUTTON_TRIGGER", 124 | "Value": "0x41c", 125 | "Description": "Panic Button Triggered" 126 | }, 127 | { 128 | "ShortDescription": "MINOR_EMERGENCY_BUTTON_RESUME", 129 | "Value": "0x41d", 130 | "Description": "Panic Button Resumed" 131 | }, 132 | { 133 | "ShortDescription": "MINOR_DISTRACT_CONTROLLER_ALARM", 134 | "Value": "0x41e", 135 | "Description": "Distributed Elevator Controller Tampering Alarm" 136 | }, 137 | { 138 | "ShortDescription": "MINOR_DISTRACT_CONTROLLER_RESUME", 139 | "Value": "0x41f", 140 | "Description": "Distributed Elevator Controller Tampering Restored" 141 | }, 142 | { 143 | "ShortDescription": "MINOR_CHANNEL_CONTROLLER_DESMANTLE_ALARM", 144 | "Value": "0x422", 145 | "Description": "Lane Controller Tampering Alarm" 146 | }, 147 | { 148 | "ShortDescription": "MINOR_CHANNEL_CONTROLLER_DESMANTLE_RESUME", 149 | "Value": "0x423", 150 | "Description": "Lane Controller Tampering Alarm Restored" 151 | }, 152 | { 153 | "ShortDescription": "MINOR_CHANNEL_CONTROLLER_FIRE_IMPORT_ALARM", 154 | "Value": "0x424", 155 | "Description": "Lane Controller Fire Input Alarm" 156 | }, 157 | { 158 | "ShortDescription": "MINOR_CHANNEL_CONTROLLER_FIRE_IMPORT_RESUME", 159 | "Value": "0x425", 160 | "Description": "Lane Controller Fire Input Alarm Restored" 161 | }, 162 | { 163 | "ShortDescription": "MINOR_PRINTER_OUT_OF_PAPER", 164 | "Value": "0x440", 165 | "Description": "No Paper in Printer Alarm" 166 | }, 167 | { 168 | "ShortDescription": "MINOR_LEGAL_EVENT_NEARLY_FULL", 169 | "Value": "0x442", 170 | "Description": "No Memory Alarm for Valid Offline Event Storage" 171 | }, 172 | { 173 | "ShortDescription": "MINOR_ALARM_CUSTOM1 to MINOR_ALARM_CUSTOM64", 174 | "Value": "0x900 to 0x93f", 175 | "Description": "Access Control: Custom Alarm Event 1 to Custom Alarm Event 64" 176 | } 177 | ] -------------------------------------------------------------------------------- /nodes/utils/AccessControlEvents/MAJOR_EXCEPTION-0x2.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ShortDescription": "MINOR_NET_BROKEN", 4 | "Value": "0x27", 5 | "Description": "Network Disconnected" 6 | }, 7 | { 8 | "ShortDescription": "MINOR_RS485_DEVICE_ABNORMAL", 9 | "Value": "0x3a", 10 | "Description": "RS485 Connection Exception" 11 | }, 12 | { 13 | "ShortDescription": "MINOR_RS485_DEVICE_REVERT", 14 | "Value": "0x3b", 15 | "Description": "RS485 Connection Restored" 16 | }, 17 | { 18 | "ShortDescription": "MINOR_DEV_POWER_ON", 19 | "Value": "0x400", 20 | "Description": "Power on" 21 | }, 22 | { 23 | "ShortDescription": "MINOR_DEV_POWER_OFF", 24 | "Value": "0x401", 25 | "Description": "Power off" 26 | }, 27 | { 28 | "ShortDescription": "MINOR_WATCH_DOG_RESET", 29 | "Value": "0x402", 30 | "Description": "Watchdog Reset" 31 | }, 32 | { 33 | "ShortDescription": "MINOR_LOW_BATTERY", 34 | "Value": "0x403", 35 | "Description": "Low Battery Voltage" 36 | }, 37 | { 38 | "ShortDescription": "MINOR_BATTERY_RESUME", 39 | "Value": "0x404", 40 | "Description": "Battery Voltage Restored" 41 | }, 42 | { 43 | "ShortDescription": "MINOR_AC_OFF", 44 | "Value": "0x405", 45 | "Description": "AC Power Disconnected" 46 | }, 47 | { 48 | "ShortDescription": "MINOR_AC_RESUME", 49 | "Value": "0x406", 50 | "Description": "AC Power Restored" 51 | }, 52 | { 53 | "ShortDescription": "MINOR_NET_RESUME", 54 | "Value": "0x407", 55 | "Description": "Network Restored" 56 | }, 57 | { 58 | "ShortDescription": "MINOR_FLASH_ABNORMAL", 59 | "Value": "0x408", 60 | "Description": "Flash Reading and Writing Exception" 61 | }, 62 | { 63 | "ShortDescription": "MINOR_CARD_READER_OFFLINE", 64 | "Value": "0x409", 65 | "Description": "Card Reader Offline" 66 | }, 67 | { 68 | "ShortDescription": "MINOR_CAED_READER_RESUME", 69 | "Value": "0x40a", 70 | "Description": "Card Reader Online" 71 | }, 72 | { 73 | "ShortDescription": "MINOR_INDICATOR_LIGHT_OFF", 74 | "Value": "0x40b", 75 | "Description": "Indicator Turns off" 76 | }, 77 | { 78 | "ShortDescription": "MINOR_INDICATOR_LIGHT_RESUME", 79 | "Value": "0x40c", 80 | "Description": "Indicator Resumed" 81 | }, 82 | { 83 | "ShortDescription": "MINOR_CHANNEL_CONTROLLER_OFF", 84 | "Value": "0x40d", 85 | "Description": "Lane Controller Offline" 86 | }, 87 | { 88 | "ShortDescription": "MINOR_CHANNEL_CONTROLLER_RESUME", 89 | "Value": "0x40e", 90 | "Description": "Lane Controller Online" 91 | }, 92 | { 93 | "ShortDescription": "MINOR_SECURITY_MODULE_OFF", 94 | "Value": "0x40f", 95 | "Description": "Secure Door Control Unit Offline" 96 | }, 97 | { 98 | "ShortDescription": "MINOR_SECURITY_MODULE_RESUME", 99 | "Value": "0x410", 100 | "Description": "Secure Door Control Unit Online" 101 | }, 102 | { 103 | "ShortDescription": "MINOR_BATTERY_ELECTRIC_LOW", 104 | "Value": "0x411", 105 | "Description": "Low Battery Voltage (Only for Face Recognition Terminal)" 106 | }, 107 | { 108 | "ShortDescription": "MINOR_BATTERY_ELECTRIC_RESUME", 109 | "Value": "0x412", 110 | "Description": "Battery Voltage Recovered (Only for Face Recognition Terminal)" 111 | }, 112 | { 113 | "ShortDescription": "MINOR_LOCAL_CONTROL_NET_BROKEN", 114 | "Value": "0x413", 115 | "Description": "Network of Distributed Access Controller Disconnected" 116 | }, 117 | { 118 | "ShortDescription": "MINOR_LOCAL_CONTROL_NET_RSUME", 119 | "Value": "0x414", 120 | "Description": "Network of Distributed Access Controller Restored" 121 | }, 122 | { 123 | "ShortDescription": "MINOR_MASTER_RS485_LOOPNODE_BROKEN", 124 | "Value": "0x415", 125 | "Description": "RS485 Loop of Master Access Controller Disconnected" 126 | }, 127 | { 128 | "ShortDescription": "MINOR_MASTER_RS485_LOOPNODE_RESUME", 129 | "Value": "0x416", 130 | "Description": "RS485 Loop of Master Access Controller Connected" 131 | }, 132 | { 133 | "ShortDescription": "MINOR_LOCAL_CONTROL_OFFLINE", 134 | "Value": "0x417", 135 | "Description": "Distributed Access Controller Offline" 136 | }, 137 | { 138 | "ShortDescription": "MINOR_LOCAL_CONTROL_RESUME", 139 | "Value": "0x418", 140 | "Description": "Distributed Access Controller Online" 141 | }, 142 | { 143 | "ShortDescription": "MINOR_LOCAL_DOWNSIDE_RS485_LOOPNODE_BROKEN", 144 | "Value": "0x419", 145 | "Description": "Downstream RS485 Loop of Distributed Access Control Disconnected" 146 | }, 147 | { 148 | "ShortDescription": "MINOR_LOCAL_DOWNSIDE_RS485_LOOPNODE_RESUME", 149 | "Value": "0x41a", 150 | "Description": "Downstream RS485 Loop of Distributed Access Control Connected" 151 | }, 152 | { 153 | "ShortDescription": "MINOR_DISTRACT_CONTROLLER_ONLINE", 154 | "Value": "0x41b", 155 | "Description": "Distributed Elevator Controller Online" 156 | }, 157 | { 158 | "ShortDescription": "MINOR_DISTRACT_CONTROLLER_OFFLINE", 159 | "Value": "0x41c", 160 | "Description": "Distributed Elevator Controller Offline" 161 | }, 162 | { 163 | "ShortDescription": "MINOR_ID_CARD_READER_NOT_CONNECT", 164 | "Value": "0x41d", 165 | "Description": "ID Card Reader Disconnected" 166 | }, 167 | { 168 | "ShortDescription": "MINOR_ID_CARD_READER_RESUME", 169 | "Value": "0x41e", 170 | "Description": "ID Card Reader Connected" 171 | }, 172 | { 173 | "ShortDescription": "MINOR_FINGER_PRINT_MODULE_NOT_CONNECT", 174 | "Value": "0x41f", 175 | "Description": "Fingerprint Module Disconnected" 176 | }, 177 | { 178 | "ShortDescription": "MINOR_FINGER_PRINT_MODULE_RESUME", 179 | "Value": "0x420", 180 | "Description": "Fingerprint Module Connected" 181 | }, 182 | { 183 | "ShortDescription": "MINOR_CAMERA_NOT_CONNECT", 184 | "Value": "0x421", 185 | "Description": "Camera Disconnected" 186 | }, 187 | { 188 | "ShortDescription": "MINOR_CAMERA_RESUME", 189 | "Value": "0x422", 190 | "Description": "Camera Connected" 191 | }, 192 | { 193 | "ShortDescription": "MINOR_COM_NOT_CONNECT", 194 | "Value": "0x423", 195 | "Description": "COM Port Disconnected" 196 | }, 197 | { 198 | "ShortDescription": "MINOR_COM_RESUME", 199 | "Value": "0x424", 200 | "Description": "COM Port Connected" 201 | }, 202 | { 203 | "ShortDescription": "MINOR_DEVICE_NOT_AUTHORIZE", 204 | "Value": "0x425", 205 | "Description": "Device Unauthorized" 206 | }, 207 | { 208 | "ShortDescription": "MINOR_PEOPLE_AND_ID_CARD_DEVICE_ONLINE", 209 | "Value": "0x426", 210 | "Description": "Face Recognition Terminal Online" 211 | }, 212 | { 213 | "ShortDescription": "MINOR_PEOPLE_AND_ID_CARD_DEVICE_OFFLINE", 214 | "Value": "0x427", 215 | "Description": "Face Recognition Terminal Offline" 216 | }, 217 | { 218 | "ShortDescription": "MINOR_LOCAL_LOGIN_LOCK", 219 | "Value": "0x428", 220 | "Description": "Local Login Lock" 221 | }, 222 | { 223 | "ShortDescription": "MINOR_LOCAL_LOGIN_UNLOCK", 224 | "Value": "0x429", 225 | "Description": "Local Login Unlock" 226 | }, 227 | { 228 | "ShortDescription": "MINOR_SUBMARINEBACK_COMM_BREAK", 229 | "Value": "0x42a", 230 | "Description": "Communication with Anti-passing Back Server Failed" 231 | }, 232 | { 233 | "ShortDescription": "MINOR_SUBMARINEBACK_COMM_RESUME", 234 | "Value": "0x42b", 235 | "Description": "Communication with Anti-passing Back Server Restored" 236 | }, 237 | { 238 | "ShortDescription": "MINOR_MOTOR_SENSOR_EXCEPTION", 239 | "Value": "0x42c", 240 | "Description": "Motor or Sensor Exception" 241 | }, 242 | { 243 | "ShortDescription": "MINOR_CAN_BUS_EXCEPTION", 244 | "Value": "0x42d", 245 | "Description": "CAN Bus Exception" 246 | }, 247 | { 248 | "ShortDescription": "MINOR_CAN_BUS_RESUME", 249 | "Value": "0x42e", 250 | "Description": "CAN Bus Exception Restored" 251 | }, 252 | { 253 | "ShortDescription": "MINOR_GATE_TEMPERATURE_OVERRUN", 254 | "Value": "0x42f", 255 | "Description": "Too High Pedestal Temperature" 256 | }, 257 | { 258 | "ShortDescription": "MINOR_IR_EMITTER_EXCEPTION", 259 | "Value": "0x430", 260 | "Description": "Active Infrared Intrusion Detector Exception" 261 | }, 262 | { 263 | "ShortDescription": "MINOR_IR_EMITTER_RESUME", 264 | "Value": "0x431", 265 | "Description": "Active Infrared Intrusion Detector Restored" 266 | }, 267 | { 268 | "ShortDescription": "MINOR_LAMP_BOARD_COMM_EXCEPTION", 269 | "Value": "0x432", 270 | "Description": "Communication with Light Board Failed" 271 | }, 272 | { 273 | "ShortDescription": "MINOR_LAMP_BOARD_COMM_RESUME", 274 | "Value": "0x433", 275 | "Description": "Communication with Light Board Restored" 276 | }, 277 | { 278 | "ShortDescription": "MINOR_IR_ADAPTOR_COMM_EXCEPTION", 279 | "Value": "0x434", 280 | "Description": "Communication with IR Adaptor Failed" 281 | }, 282 | { 283 | "ShortDescription": "MINOR_IR_ADAPTOR_COMM_RESUME", 284 | "Value": "0x435", 285 | "Description": "Communication with IR Adaptor Restored" 286 | }, 287 | { 288 | "ShortDescription": "MINOR_PRINTER_ONLINE", 289 | "Value": "0x436", 290 | "Description": "Printer Online" 291 | }, 292 | { 293 | "ShortDescription": "MINOR_PRINTER_OFFLINE", 294 | "Value": "0x437", 295 | "Description": "Printer Offline" 296 | }, 297 | { 298 | "ShortDescription": "MINOR_4G_MOUDLE_ONLINE", 299 | "Value": "0x438", 300 | "Description": "4G Module Online" 301 | }, 302 | { 303 | "ShortDescription": "MINOR_4G_MOUDLE_OFFLINE", 304 | "Value": "0x439", 305 | "Description": "4G Module Offline" 306 | }, 307 | { 308 | "ShortDescription": "MINOR_AUXILIARY_BOARD_OFFLINE", 309 | "Value": "0x43c", 310 | "Description": "Auxiliary Board Disconnected" 311 | }, 312 | { 313 | "ShortDescription": "MINOR_AUXILIARY_BOARD_RESUME", 314 | "Value": "0x43d", 315 | "Description": "Auxiliary Board Connected" 316 | }, 317 | { 318 | "ShortDescription": "MINOR_IDCARD_SECURITY_MOUDLE_EXCEPTION", 319 | "Value": "0x43e", 320 | "Description": "Secure ID Card Unit Exception" 321 | }, 322 | { 323 | "ShortDescription": "MINOR_IDCARD_SECURITY_MOUDLE_RESUME", 324 | "Value": "0x43f", 325 | "Description": "Secure ID Card Unit Restored" 326 | }, 327 | { 328 | "ShortDescription": "MINOR_FP_PERIPHERAL_EXCEPTION", 329 | "Value": "0x440", 330 | "Description": "Fingerprint Collection Peripheral Exception" 331 | }, 332 | { 333 | "ShortDescription": "MINOR_FP_PERIPHERAL_RESUME", 334 | "Value": "0x441", 335 | "Description": "Fingerprint Collection Peripheral Restored" 336 | }, 337 | { 338 | "ShortDescription": "MINOR_EXCEPTION_CUSTOM1 to MINOR_EXCEPTION_CUSTOM64", 339 | "Value": "0x900 to 0x93f", 340 | "Description": "Access Control: Custom Exception Event 1 to Custom Exception Event 64" 341 | } 342 | ] -------------------------------------------------------------------------------- /nodes/utils/AccessControlEvents/MAJOR_OPERATION-0x3.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ShortDescription": "MINOR_LOCAL_LOGIN", 4 | "Value": "0x50", 5 | "Description": "Local Login" 6 | }, 7 | { 8 | "ShortDescription": "MINOR_LOCAL_LOGOUT", 9 | "Value": "0x51", 10 | "Description": "Local Logout" 11 | }, 12 | { 13 | "ShortDescription": "MINOR_LOCAL_UPGRADE", 14 | "Value": "0x5a", 15 | "Description": "Local Upgrade" 16 | }, 17 | { 18 | "ShortDescription": "MINOR_REMOTE_LOGIN", 19 | "Value": "0x70", 20 | "Description": "Remote Login" 21 | }, 22 | { 23 | "ShortDescription": "MINOR_REMOTE_LOGOUT", 24 | "Value": "0x71", 25 | "Description": "Remote Logout" 26 | }, 27 | { 28 | "ShortDescription": "MINOR_REMOTE_ARM", 29 | "Value": "0x79", 30 | "Description": "Remote Arming" 31 | }, 32 | { 33 | "ShortDescription": "MINOR_REMOTE_DISARM", 34 | "Value": "0x7a", 35 | "Description": "Remote Disarming" 36 | }, 37 | { 38 | "ShortDescription": "MINOR_REMOTE_REBOOT", 39 | "Value": "0x7b", 40 | "Description": "Remote Reboot" 41 | }, 42 | { 43 | "ShortDescription": "MINOR_REMOTE_UPGRADE", 44 | "Value": "0x7e", 45 | "Description": "Remote Upgrade" 46 | }, 47 | { 48 | "ShortDescription": "MINOR_REMOTE_CFGFILE_OUTPUT", 49 | "Value": "0x86", 50 | "Description": "Remote Operation: Export Configuration File" 51 | }, 52 | { 53 | "ShortDescription": "MINOR_REMOTE_CFGFILE_INTPUT", 54 | "Value": "0x87", 55 | "Description": "Remote Operation: Import Configuration File" 56 | }, 57 | { 58 | "ShortDescription": "MINOR_REMOTE_ALARMOUT_OPEN_MAN", 59 | "Value": "0xd6", 60 | "Description": "Remote Operation: Enable Alarm Output Manually" 61 | }, 62 | { 63 | "ShortDescription": "MINOR_REMOTE_ALARMOUT_CLOSE_MAN", 64 | "Value": "0xd7", 65 | "Description": "Remote Operation: Disable Alarm Output Manually" 66 | }, 67 | { 68 | "ShortDescription": "MINOR_REMOTE_OPEN_DOOR", 69 | "Value": "0x400", 70 | "Description": "Door Remotely Open" 71 | }, 72 | { 73 | "ShortDescription": "MINOR_REMOTE_CLOSE_DOOR", 74 | "Value": "0x401", 75 | "Description": "Door Remotely Closed" 76 | }, 77 | { 78 | "ShortDescription": "MINOR_REMOTE_ALWAYS_OPEN", 79 | "Value": "0x402", 80 | "Description": "Remain Open Remotely" 81 | }, 82 | { 83 | "ShortDescription": "MINOR_REMOTE_ALWAYS_CLOSE", 84 | "Value": "0x403", 85 | "Description": "Remain Closed Remotely" 86 | }, 87 | { 88 | "ShortDescription": "MINOR_REMOTE_CHECK_TIME", 89 | "Value": "0x404", 90 | "Description": "Remote: Manual Time Sync" 91 | }, 92 | { 93 | "ShortDescription": "MINOR_NTP_CHECK_TIME", 94 | "Value": "0x405", 95 | "Description": "Network Time Protocol Synchronization" 96 | }, 97 | { 98 | "ShortDescription": "MINOR_REMOTE_CLEAR_CARD", 99 | "Value": "0x406", 100 | "Description": "Remote Operation: Clear All Card No." 101 | }, 102 | { 103 | "ShortDescription": "MINOR_REMOTE_RESTORE_CFG", 104 | "Value": "0x407", 105 | "Description": "Remote Operation: Restore Defaults" 106 | }, 107 | { 108 | "ShortDescription": "MINOR_ALARMIN_ARM", 109 | "Value": "0x408", 110 | "Description": "Zone Arming" 111 | }, 112 | { 113 | "ShortDescription": "MINOR_ALARMIN_DISARM", 114 | "Value": "0x409", 115 | "Description": "Zone Disarming" 116 | }, 117 | { 118 | "ShortDescription": "MINOR_LOCAL_RESTORE_CFG", 119 | "Value": "0x40a", 120 | "Description": "Local Operation: Restore Defaults" 121 | }, 122 | { 123 | "ShortDescription": "MINOR_REMOTE_CAPTURE_PIC", 124 | "Value": "0x40b", 125 | "Description": "Remote Operation: Capture" 126 | }, 127 | { 128 | "ShortDescription": "MINOR_MOD_NET_REPORT_CFG", 129 | "Value": "0x40c", 130 | "Description": "Edit Network Parameters" 131 | }, 132 | { 133 | "ShortDescription": "MINOR_MOD_GPRS_REPORT_PARAM", 134 | "Value": "0x40d", 135 | "Description": "Edit GPRS Parameters" 136 | }, 137 | { 138 | "ShortDescription": "MINOR_MOD_REPORT_GROUP_PARAM", 139 | "Value": "0x40e", 140 | "Description": "Edit Control Center Parameters" 141 | }, 142 | { 143 | "ShortDescription": "MINOR_UNLOCK_PASSWORD_OPEN_DOOR", 144 | "Value": "0x40f", 145 | "Description": "Enter Dismiss Code" 146 | }, 147 | { 148 | "ShortDescription": "MINOR_AUTO_RENUMBER", 149 | "Value": "0x410", 150 | "Description": "Auto Renumber" 151 | }, 152 | { 153 | "ShortDescription": "MINOR_AUTO_COMPLEMENT_NUMBER", 154 | "Value": "0x411", 155 | "Description": "Auto Supplement Number" 156 | }, 157 | { 158 | "ShortDescription": "MINOR_NORMAL_CFGFILE_INPUT", 159 | "Value": "0x412", 160 | "Description": "Import Configuration File" 161 | }, 162 | { 163 | "ShortDescription": "MINOR_NORMAL_CFGFILE_OUTTPUT", 164 | "Value": "0x413", 165 | "Description": "Export Configuration File" 166 | }, 167 | { 168 | "ShortDescription": "MINOR_CARD_RIGHT_INPUT", 169 | "Value": "0x414", 170 | "Description": "Import Card Permission Parameters" 171 | }, 172 | { 173 | "ShortDescription": "MINOR_CARD_RIGHT_OUTTPUT", 174 | "Value": "0x415", 175 | "Description": "Export Card Permission Parameters" 176 | }, 177 | { 178 | "ShortDescription": "MINOR_LOCAL_USB_UPGRADE", 179 | "Value": "0x416", 180 | "Description": "Upgrade Device via USB flash Drive" 181 | }, 182 | { 183 | "ShortDescription": "MINOR_REMOTE_VISITOR_CALL_LADDER", 184 | "Value": "0x417", 185 | "Description": "Visitor Calling Elevator" 186 | }, 187 | { 188 | "ShortDescription": "MINOR_REMOTE_HOUSEHOLD_CALL_LADDER", 189 | "Value": "0x418", 190 | "Description": "Resident Calling Elevator" 191 | }, 192 | { 193 | "ShortDescription": "MINOR_REMOTE_ACTUAL_GUARD", 194 | "Value": "0x419", 195 | "Description": "Remotely Arming" 196 | }, 197 | { 198 | "ShortDescription": "MINOR_REMOTE_ACTUAL_UNGUARD", 199 | "Value": "0x41a", 200 | "Description": "Remotely Disarming" 201 | }, 202 | { 203 | "ShortDescription": "MINOR_REMOTE_CONTROL_NOT_CODE_OPER_FAILED", 204 | "Value": "0x41b", 205 | "Description": "Operation Failed: Keyfob Not Pairing" 206 | }, 207 | { 208 | "ShortDescription": "MINOR_REMOTE_CONTROL_CLOSE_DOOR", 209 | "Value": "0x41c", 210 | "Description": "Keyfob Operation: Close Door" 211 | }, 212 | { 213 | "ShortDescription": "MINOR_REMOTE_CONTROL_OPEN_DOOR", 214 | "Value": "0x41d", 215 | "Description": "Keyfob Operation: Open Door" 216 | }, 217 | { 218 | "ShortDescription": "MINOR_REMOTE_CONTROL_ALWAYS_OPEN_DOOR", 219 | "Value": "0x41e", 220 | "Description": "Keyfob Operation: Remain Door Open" 221 | }, 222 | { 223 | "ShortDescription": "MINOR_M1_CARD_ENCRYPT_VERIFY_OPEN", 224 | "Value": "0x41f", 225 | "Description": "M1 Card Encryption Verification Enabled" 226 | }, 227 | { 228 | "ShortDescription": "MINOR_M1_CARD_ENCRYPT_VERIFY_CLOSE", 229 | "Value": "0x420", 230 | "Description": "M1 Card Encryption Verification Disabled" 231 | }, 232 | { 233 | "ShortDescription": "MINOR_NFC_FUNCTION_OPEN", 234 | "Value": "0X421", 235 | "Description": "Opening Door with NFC Card Enabled" 236 | }, 237 | { 238 | "ShortDescription": "MINOR_NFC_FUNCTION_CLOSE", 239 | "Value": "0X422", 240 | "Description": "Opening Door with NFC Card Disabled" 241 | }, 242 | { 243 | "ShortDescription": "MINOR_OFFLINE_DATA_OUTPUT", 244 | "Value": "0x423", 245 | "Description": "Export Offline Collected Data" 246 | }, 247 | { 248 | "ShortDescription": "MINOR_CREATE_SSH_LINK", 249 | "Value": "0x42d", 250 | "Description": "Establish SSH Connection" 251 | }, 252 | { 253 | "ShortDescription": "MINOR_CLOSE_SSH_LINK", 254 | "Value": "0x42e", 255 | "Description": "Disconnect SSH Connection" 256 | }, 257 | { 258 | "ShortDescription": "MINOR_OPERATION_CUSTOM1 to MINOR_OPERATION_CUSTOM64", 259 | "Value": "0x900-0x93f", 260 | "Description": "Access Control: Custom Operation Event 1 to Custom Operation Event 64" 261 | } 262 | ] -------------------------------------------------------------------------------- /nodes/utils/Sha256.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | exports.__esModule = true; 3 | exports.sha256 = void 0; 4 | function m(e, t) { 5 | var n = (65535 & e) + (65535 & t); 6 | return (e >> 16) + (t >> 16) + (n >> 16) << 16 | 65535 & n; 7 | } 8 | function C(e, t) { 9 | return e >>> t | e << 32 - t; 10 | } 11 | function fun0(e) { 12 | var t = ''; 13 | for (var n = 0; n < 4 * e.length; n++) { 14 | t += '0123456789abcdef'.charAt(e[n >> 2] >> 8 * (3 - n % 4) + 4 & 15) + 15 | '0123456789abcdef'.charAt(e[n >> 2] >> 8 * (3 - n % 4) & 15); 16 | } 17 | return t; 18 | } 19 | function fun1(e, t) { 20 | var n; 21 | var r; 22 | var s; 23 | var o; 24 | var i; 25 | var a; 26 | var u; 27 | var c; 28 | var l; 29 | var d; 30 | var p; 31 | var P; 32 | var h = [1116352408, 1899447441, 3049323471, 3921009573, 961987163, 1508970993, 2453635748, 2870763221, 3624381080, 33 | 310598401, 607225278, 1426881987, 1925078388, 2162078206, 2614888103, 3248222580, 3835390401, 4022224774, 34 | 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, 2554220882, 2821834349, 2952996808, 35 | 3210313671, 3336571891, 3584528711, 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, 36 | 1695183700, 1986661051, 2177026350, 2456956037, 2730485921, 2820302411, 3259730800, 3345764771, 3516065817, 37 | 3600352804, 4094571909, 275423344, 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, 1537002063, 38 | 1747873779, 1955562222, 2024104815, 2227730452, 2361852424, 2428436474, 2756734187, 3204031479, 3329325298]; 39 | var f = [1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225]; 40 | var I = Array(64); 41 | for (e[t >> 5] |= 128 << 24 - t % 32, e[15 + (t + 64 >> 9 << 4)] = t, l = 0; l < e.length; l += 16) { 42 | for (n = f[0], r = f[1], s = f[2], o = f[3], i = f[4], a = f[5], u = f[6], c = f[7], d = 0; d < 64; d++) { 43 | I[d] = d < 16 ? e[d + l] : m(m(m(C(I[d - 2], 17) ^ C(I[d - 2], 19) ^ I[d - 2] >>> 10, I[d - 7]), C(I[d - 15], 7) ^ C(I[d - 15], 18) ^ I[d - 15] >>> 3), I[d - 16]); 44 | p = m(m(m(m(c, C(i, 6) ^ C(i, 11) ^ C(i, 25)), i & a ^ ~i & u), h[d]), I[d]); 45 | P = m(C(n, 2) ^ C(n, 13) ^ C(n, 22), n & r ^ n & s ^ r & s); 46 | c = u; 47 | u = a; 48 | a = i; 49 | i = m(o, p); 50 | o = s; 51 | s = r; 52 | r = n; 53 | n = m(p, P); 54 | } 55 | f[0] = m(n, f[0]); 56 | f[1] = m(r, f[1]); 57 | f[2] = m(s, f[2]); 58 | f[3] = m(o, f[3]); 59 | f[4] = m(i, f[4]); 60 | f[5] = m(a, f[5]); 61 | f[6] = m(u, f[6]); 62 | f[7] = m(c, f[7]); 63 | } 64 | return f; 65 | } 66 | function fun2(e) { 67 | var t = []; 68 | for (var n = 0; n < 8 * e.length; n += 8) { 69 | t[n >> 5] |= (255 & e.charCodeAt(n / 8)) << 24 - n % 32; 70 | } 71 | return t; 72 | } 73 | function fun3(e) { 74 | e = e.replace(/\r\n/g, '\n'); 75 | var t = ''; 76 | for (var n = 0; n < e.length; n++) { 77 | var r = e.charCodeAt(n); 78 | if (r < 128) { 79 | t += String.fromCharCode(r); 80 | } 81 | else { 82 | if (r > 127 && r < 2048) { 83 | t += String.fromCharCode(r >> 6 | 192); 84 | } 85 | else { 86 | t += String.fromCharCode(r >> 12 | 224); 87 | t += String.fromCharCode(r >> 6 & 63 | 128); 88 | } 89 | t += String.fromCharCode(63 & r | 128); 90 | } 91 | } 92 | return t; 93 | } 94 | function sha256(e) { 95 | var a0 = fun1(fun2(e = (fun3(e))), 8 * e.length); 96 | return fun0(a0); 97 | } 98 | exports.sha256 = sha256; 99 | -------------------------------------------------------------------------------- /nodes/utils/classDoorbellCapabilities.js: -------------------------------------------------------------------------------- 1 | // Declaration 2 | module.exports = class classDoorbellCapabilities { 3 | /** 4 | * @param {string} [_model] 5 | * @param {string} [_firmwareVersion] 6 | * @param {number} [_port] 7 | */ 8 | constructor(_model, _firmwareVersion, _port) { 9 | this.model = _model; 10 | this.firmwareVersion = _firmwareVersion; 11 | this.port = _port; 12 | } 13 | } 14 | // 13/01/2023 Gather infos 15 | RED.httpAdmin.get("/hikvisionUltimateGetInfoDoorBell", RED.auth.needsPermission('Doorbellconfig.read'), async function (req, res) { 16 | let _nodeServer = RED.nodes.getNode(req.query.nodeID);// Retrieve node.id of the config node. 17 | if (_nodeServer === null) _nodeServer = { server: RED.nodes.getNode(node.id) }; 18 | // Setting default params 19 | let jParams = { 20 | protocol: _nodeServer.server.protocol, 21 | host: _nodeServer.server.host.includes(":") ? _nodeServer.server.host.split(":")[0] : _nodeServer.server.host, 22 | port: _nodeServer.server.port, 23 | user: _nodeServer.server.credentials.user, 24 | password: _nodeServer.server.credentials.password, 25 | authentication: _nodeServer.server.authentication 26 | }; 27 | var clientInfo; 28 | if (req.query.hasOwnProperty("params")) { 29 | jParams = JSON.parse(decodeURIComponent(req.query.params));// Retrieve node.id of the config node. 30 | if (jParams.password === "__PWRD__") { 31 | jParams.password = _nodeServer.server.credentials.password; 32 | } 33 | } 34 | 35 | if (jParams.authentication === "digest") clientInfo = new DigestFetch(jParams.user, jParams.password); // Instantiate the fetch client. 36 | if (jParams.authentication === "basic") clientInfo = new DigestFetch(jParams.user, jParams.password, { basic: true }); // Instantiate the fetch client. 37 | var opt = { 38 | // These properties are part of the Fetch Standard 39 | method: "GET", 40 | headers: {}, // request headers. format is the identical to that accepted by the Headers constructor (see below) 41 | body: null, // request body. can be null, a string, a Buffer, a Blob, or a Node.js Readable stream 42 | redirect: 'follow', // set to `manual` to extract redirect headers, `error` to reject redirect 43 | signal: null, // pass an instance of AbortSignal to optionally abort requests 44 | 45 | // The following properties are node-fetch extensions 46 | follow: 20, // maximum redirect count. 0 to not follow redirect 47 | timeout: 5000, // req/res timeout in ms, it resets on redirect. 0 to disable (OS limit applies). Signal is recommended instead. 48 | compress: false, // support gzip/deflate content encoding. false to disable 49 | size: 0, // maximum response body size in bytes. 0 to disable 50 | agent: jParams.protocol === "https" ? customHttpsAgent : null // http(s).Agent instance or function that returns an instance (see below) 51 | }; 52 | try { 53 | let result = {}; // Result to be returned 54 | async function deviceInfo() { 55 | try { 56 | const resInfo = await clientInfo.fetch(jParams.protocol + "://" + jParams.host + ":" + jParams.port + "/ISAPI/System/deviceInfo", opt); 57 | const body = await resInfo.text(); 58 | const parser = new XMLParser(); 59 | return parser.parse(body).DeviceInfo; 60 | 61 | } catch (error) { 62 | throw error; 63 | } 64 | } 65 | async function callSignal() { 66 | try { 67 | const resInfo = await clientInfo.fetch(jParams.protocol + "://" + jParams.host + ":" + jParams.port + "/ISAPI/VideoIntercom/callSignal/capabilities?format=json", opt); 68 | const body = await resInfo.text(); 69 | return JSON.parse(body).CallSignal.cmdType["@opt"]; 70 | 71 | } catch (error) { 72 | throw error; 73 | } 74 | } 75 | result.deviceInfo = await deviceInfo(); 76 | result.callSignal = await callSignal(); 77 | 78 | res.json(result); 79 | 80 | 81 | } catch (err) { 82 | res.json({ error: err.message }); 83 | } 84 | 85 | 86 | 87 | }); -------------------------------------------------------------------------------- /nodes/utils/dateManagement.js: -------------------------------------------------------------------------------- 1 | exports.toHikvisionISODateString = function (date) { 2 | var tzo = -date.getTimezoneOffset(), 3 | dif = tzo >= 0 ? '+' : '-', 4 | pad = function (num) { 5 | return (num < 10 ? '0' : '') + num; 6 | }; 7 | 8 | return date.getFullYear() + 9 | '-' + pad(date.getMonth() + 1) + 10 | '-' + pad(date.getDate()) + 11 | 'T' + pad(date.getHours()) + 12 | ':' + pad(date.getMinutes()) + 13 | ':' + pad(date.getSeconds()) + 14 | dif + pad(Math.floor(Math.abs(tzo) / 60)) + 15 | ':' + pad(Math.abs(tzo) % 60); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /nodes/utils/escape-json.js: -------------------------------------------------------------------------------- 1 | /* 2 | Escape JSON 3 | */ 4 | var escapeJSON = exports.escapeJSON = function(json) { 5 | var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; 6 | var meta = { // table of character substitutions 7 | '\b': '\\b', 8 | '\t': '\\t', 9 | '\n': '\\n', 10 | '\f': '\\f', 11 | '\r': '\\r', 12 | '"' : '\\"', 13 | '\\': '\\\\' 14 | }; 15 | 16 | escapable.lastIndex = 0; 17 | return escapable.test(json) ? '"' + json.replace(escapable, function (a) { 18 | var c = meta[a]; 19 | return (typeof c === 'string') ? c 20 | : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); 21 | }) + '"' : '"' + json + '"'; 22 | 23 | }; -------------------------------------------------------------------------------- /nodes/utils/hikDiscovery.js: -------------------------------------------------------------------------------- 1 | // Search all devicees on the lan 2 | // inquiry 3 | // 239.255.255.250 4 | // Port 37020 5 | // Protocol: UDP 6 | const ipAddress = require('./ipAddressHelper') 7 | const { XMLParser } = require("fast-xml-parser"); 8 | const parser = new XMLParser(); 9 | var aDevices = new Array(); // Devices to return 10 | 11 | 12 | //Multicast Client receiving sent messages 13 | exports.Discover = async function getAllHikvisionDevicesDescriptors() { 14 | return new Promise(function (resolve, reject) { 15 | const MCAST_PORT = 37020; 16 | const MCAST_ADDR = "239.255.255.250"; //same mcast address as Server 17 | let HOST = ''; //this is your own IP 18 | const discoMSG = 'inquiry'; 19 | try { 20 | HOST = ipAddress.getLocalAddress(); 21 | } catch (error) { 22 | 23 | } 24 | try { 25 | const dgram = require('dgram'); 26 | const client = dgram.createSocket({ type: 'udp4', reuseAddr: true }); 27 | 28 | client.on('listening', function () { 29 | let currentAddress = client.address(); 30 | //console.log('UDP Client listening on ' + currentAddress.address + ":" + currentAddress.port); 31 | client.setBroadcast(true) 32 | client.setMulticastTTL(128); 33 | client.addMembership(MCAST_ADDR); 34 | }); 35 | 36 | client.on('message', function (message, remote) { 37 | 38 | try { 39 | 40 | let jObj = parser.parse(message.toString()); 41 | if (jObj.hasOwnProperty("ProbeMatch")) { 42 | if (aDevices.find(a => a.IPv4Address === jObj.ProbeMatch.IPv4Address) === undefined) { 43 | aDevices.push(jObj.ProbeMatch); 44 | } 45 | } 46 | 47 | } catch (error) { 48 | reject([]); 49 | console.log('getAllHikvisionDevicesDescriptors: From: ' + remote.address + ':' + remote.port + ' - ' + error.message); 50 | } 51 | 52 | }); 53 | 54 | client.bind(MCAST_PORT); 55 | 56 | // Send query message 57 | setTimeout(() => { 58 | let b = Buffer.from(discoMSG); 59 | client.send(b, 0, b.length, MCAST_PORT, MCAST_ADDR, function () { 60 | //console.log("Sent " + b); 61 | }); 62 | }, 10); 63 | 64 | // Set timeout timer 65 | setTimeout(() => { 66 | try { 67 | client.dropMembership(MCAST_ADDR); 68 | client.close(); 69 | client.disconnect(); 70 | } catch (error) { 71 | } 72 | resolve(aDevices); 73 | }, 2000); 74 | } catch (error) { 75 | 76 | } 77 | 78 | }) 79 | 80 | } 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /nodes/utils/ipAddressHelper.js: -------------------------------------------------------------------------------- 1 | // Helper for ipaddresses 2 | const os = require('os') 3 | 4 | // #region "GET LOCAL INTERFACE PROPERTIES" 5 | function getIPv4Interfaces () { 6 | // get the local address of the IPv4 interface we're going to use 7 | const candidateInterfaces = {} 8 | const interfaces = os.networkInterfaces() 9 | for (const iface in interfaces) { 10 | for (const key in interfaces[iface]) { 11 | const intf = interfaces[iface][key] 12 | // 11/05/2022 Fixed a breaking change introduced by node 18 (https://nodejs.org/api/os.html#osnetworkinterfaces) 13 | // In Node < 18, intf.family is a string "IPv4" or "IPv6", from node 18, is an integer, for example 4. 14 | try { 15 | //// knxLog.get().debug('ipAddressHelper.js: parsing interface: %s (%j)', iface, intf) 16 | if (intf.family !== undefined && intf.family.toString().includes('4') && !intf.internal) { 17 | //// knxLog.get().trace('ipAddressHelper.js: Found suitable interface: %s (%j)', iface, intf) 18 | candidateInterfaces[iface] = intf 19 | } else { 20 | //// knxLog.get().trace('ipAddressHelper.js: Found NOT suitable interface: %s (%j)', iface, intf) 21 | } 22 | } catch (error) { 23 | //// knxLog.get().error('ipAddressHelper.js: getIPv4Interfaces: error parsing the interface %s (%j)', iface, intf) 24 | } 25 | } 26 | } 27 | 28 | return candidateInterfaces 29 | } 30 | 31 | exports.getLocalAddress = function (_interface = '') { 32 | // knxLog.get().trace('ipAddressHelper.js: getLocalAddress: getting interfaces') 33 | const candidateInterfaces = getIPv4Interfaces() 34 | // if user has declared a desired interface then use it 35 | if (_interface !== '') { 36 | if (!candidateInterfaces.hasOwnProperty(_interface)) { 37 | // knxLog.get().error('ipAddressHelper.js: exports.getLocalAddress: Interface ' + _interface + ' not found or has no useful IPv4 address!') 38 | throw Error('Interface ' + _interface + ' not found or has no useful IPv4 address!') 39 | } else { 40 | return candidateInterfaces[_interface].address 41 | } 42 | } 43 | 44 | // just return the first available IPv4 non-loopback interface 45 | if (Object.keys(candidateInterfaces).length > 0) { 46 | return candidateInterfaces[Object.keys(candidateInterfaces)[0]].address 47 | } 48 | // no local IpV4 interfaces? 49 | throw Error('No valid IPv4 interfaces detected') 50 | } 51 | // #endregion 52 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-red-contrib-hikvision-ultimate", 3 | "version": "1.2.10", 4 | "description": "A native set of nodes for Hikvision (and compatible) Cameras, Alarms, Radars, NVR, Doorbells, etc.", 5 | "author": "Supergiovane (https://github.com/Supergiovane)", 6 | "dependencies": { 7 | "node-fetch": "2.6.7", 8 | "digest-fetch": "2.0.1", 9 | "jimp": "0.22.10", 10 | "lodash": "4.17.21", 11 | "fast-xml-parser": "4.0.13", 12 | "dicer": "0.3.1" 13 | }, 14 | "keywords": [ 15 | "node-red", 16 | "hikvision", 17 | "alarm", 18 | "camera", 19 | "radar", 20 | "ANPR", 21 | "license plate", 22 | "doorbell", 23 | "door intercom", 24 | "access control terminal", 25 | "Ax Pro" 26 | ], 27 | "engines": { 28 | "node": ">=16.0.0" 29 | }, 30 | "license": "MIT", 31 | "repository": { 32 | "type": "git", 33 | "url": "https://github.com/Supergiovane/node-red-contrib-hikvision-ultimate" 34 | }, 35 | "node-red": { 36 | "nodes": { 37 | "Hikvision-config": "nodes/Hikvision-config.js", 38 | "AXPro-config": "nodes/AXPro-config.js", 39 | "Doorbell-config": "nodes/Doorbell-config.js", 40 | "ANPR-config": "nodes/ANPR-config.js", 41 | "Speaker-config": "nodes/Speaker-config.js", 42 | "AccessControl-config": "nodes/AccessControl-config.js", 43 | "hikvisionUltimateText": "nodes/hikvisionUltimateText.js", 44 | "hikvisionUltimateAlarm": "nodes/hikvisionUltimateAlarm.js", 45 | "hikvisionUltimateAlarmRaw": "nodes/hikvisionUltimateAlarmRaw.js", 46 | "hikvisionUltimateANPR": "nodes/hikvisionUltimateANPR.js", 47 | "hikvisionUltimatePTZ": "nodes/hikvisionUltimatePTZ.js", 48 | "hikvisionUltimatePicture": "nodes/hikvisionUltimatePicture.js", 49 | "hikvisionUltimateXML": "nodes/hikvisionUltimateXML.js", 50 | "hikvisionUltimateDoorbell": "nodes/hikvisionUltimateDoorbell.js", 51 | "hikvisionUltimateAxPro": "nodes/hikvisionUltimateAxPro.js", 52 | "hikvisionUltimateAccessControlTerminal": "nodes/hikvisionUltimateAccessControlTerminal.js", 53 | "hikvisionUltimateSpeaker": "nodes/hikvisionUltimateSpeaker.js" 54 | } 55 | } 56 | } --------------------------------------------------------------------------------