Merge branch 'more-onvif-events' into 'dev'

more onvif events e.g. person detection trigger recording

See merge request Shinobi-Systems/Shinobi!496
plugins-allow-selecting-specific-detector
Moe 2024-05-09 21:00:09 +00:00
commit 2578e13f50
3 changed files with 109 additions and 135 deletions

View File

@ -1,116 +1,106 @@
module.exports = function(s,config,lang){ function hasOnvifEventsEnabled(monitorConfig) {
return monitorConfig.details.is_onvif === '1' && monitorConfig.details.onvif_events === '1';
}
module.exports = function (s, config, lang) {
const {Cam} = require("onvif");
const { const {
triggerEvent, triggerEvent,
} = require('./utils.js')(s,config,lang) } = require('./utils.js')(s, config, lang)
const onvifEvents = require("node-onvif-events");
const onvifEventIds = [] function handleEvent(event, monitorConfig, onvifEventLog) {
const onvifEventControllers = {} const eventValue = event.message?.message?.data?.simpleItem?.$?.Value;
const startMotion = async (onvifId,monitorConfig) => { if (eventValue === false) {
const groupKey = monitorConfig.ke onvifEventLog(`ONVIF Event Stopped`, `topic ${event.topic?._}`)
const monitorId = monitorConfig.mid return
const onvifIdKey = `${monitorConfig.mid}${monitorConfig.ke}`
const controlBaseUrl = monitorConfig.details.control_base_url || s.buildMonitorUrl(monitorConfig, true)
const controlURLOptions = s.cameraControlOptionsFromUrl(controlBaseUrl,monitorConfig)
const onvifPort = parseInt(monitorConfig.details.onvif_port) || 8000
let options = {
id: onvifId,
hostname: controlURLOptions.host,
username: controlURLOptions.username,
password: controlURLOptions.password,
port: onvifPort,
};
const detector = onvifEventControllers[onvifIdKey] || await onvifEvents.MotionDetector.create(options.id, options);
function onvifEventLog(type,data){
s.userLog({
ke: groupKey,
mid: monitorId
},{
type: type,
msg: data
})
}
onvifEventLog(`ONVIF Event Detection Listening!`)
try {
detector.listen((motion) => {
if (motion) {
onvifEventLog(`ONVIF Event Detected!`)
triggerEvent({
f: 'trigger',
id: monitorId,
ke: groupKey,
details:{
plug: 'onvifEvent',
name: 'onvifEvent',
reason: 'motion',
confidence: 100,
// reason: 'object',
// matrices: [matrix],
// imgHeight: img.height,
// imgWidth: img.width,
}
})
} else {
onvifEventLog(`ONVIF Event Stopped`)
}
});
} catch(e) {
console.error(e)
onvifEventLog(`ONVIF Event Error`,e)
}
return detector
}
async function initializeOnvifEvents(monitorConfig){
const monitorMode = monitorConfig.mode
const groupKey = monitorConfig.ke
const monitorId = monitorConfig.mid
const hasOnvifEventsEnabled = monitorConfig.details.is_onvif === '1' && monitorConfig.details.onvif_events === '1';
if(hasOnvifEventsEnabled){
const onvifIdKey = `${monitorConfig.mid}${monitorConfig.ke}`
let onvifId = onvifEventIds.indexOf(onvifIdKey)
if(onvifEventIds.indexOf(onvifIdKey) === -1){
onvifId = onvifEventIds.length;
onvifEventIds.push(onvifIdKey);
}
try{
onvifEventControllers[onvifIdKey].close()
s.debugLog('ONVIF Event Module Warning : This could cause a memory leak?')
}catch(err){
s.debugLog('ONVIF Event Module Error', err.stack);
}
try{
delete(onvifEventControllers[onvifIdKey])
s.debugLog('Can ',monitorConfig.name, 'read ONVIF Events?',monitorMode !== 'stop')
if(monitorMode !== 'stop'){
s.debugLog('Starting ONVIF Event Reader on ',monitorConfig.name)
const detector = await startMotion(onvifId,monitorConfig)
onvifEventControllers[onvifIdKey] = detector;
}
}catch(err){
console.error(err)
s.debugLog('ONVIF Event Module Start Error', err.stack);
}
} }
onvifEventLog(`ONVIF Event Detected!`, `topic ${event.topic?._}`)
triggerEvent({
f: 'trigger',
id: monitorConfig.mid,
ke: monitorConfig.ke,
details: {
plug: 'onvifEvent',
name: 'onvifEvent',
reason: event.topic?._,
confidence: 100,
[event.message?.message?.data?.simpleItem?.$?.Name]: eventValue
}
})
} }
function configureOnvif(monitorConfig, onvifEventLog) {
const controlBaseUrl = monitorConfig.details.control_base_url || s.buildMonitorUrl(monitorConfig, true)
const controlURLOptions = s.cameraControlOptionsFromUrl(controlBaseUrl, monitorConfig)
const onvifPort = parseInt(monitorConfig.details.onvif_port) || 8000
const options = {
hostname: controlURLOptions.host,
username: controlURLOptions.username,
password: controlURLOptions.password,
port: onvifPort,
};
return new Cam(options, function (error) {
if (error) {
onvifEventLog(`ONVIF Event Error`,e)
return
}
this.on('event', function (event) {
handleEvent(event, monitorConfig, onvifEventLog);
})
})
}
const cams = {};
function initializeOnvifEvents(monitorConfig) {
monitorConfig.key = `${monitorConfig.mid}${monitorConfig.ke}`
const onvifEventLog = function onvifEventLog(type, data) {
s.userLog({
ke: monitorConfig.key,
mid: monitorConfig.mid
}, {
type: type,
msg: data
})
}
if (!hasOnvifEventsEnabled(monitorConfig)) {
cams[monitorConfig.key]?.removeAllListeners('event')
return
}
if (cams[monitorConfig.key]) {
onvifEventLog("ONVIF already listening to events")
return;
}
cams[monitorConfig.key] = configureOnvif(monitorConfig,onvifEventLog);
}
s.onMonitorStart((monitorConfig) => { s.onMonitorStart((monitorConfig) => {
initializeOnvifEvents(monitorConfig) initializeOnvifEvents(monitorConfig)
}) })
const connectionInfoArray = s.definitions["Monitor Settings"].blocks["Detector"].info const connectionInfoArray = s.definitions["Monitor Settings"].blocks["Detector"].info
connectionInfoArray.splice(2, 0, { connectionInfoArray.splice(2, 0, {
"name": "detail=onvif_events", "name": "detail=onvif_events",
"field": lang['ONVIF Events'], "field": lang['ONVIF Events'],
"default": "0", "default": "0",
"form-group-class": "h_onvif_input h_onvif_1", "form-group-class": "h_onvif_input h_onvif_1",
"form-group-class-pre-layer": "h_det_input h_det_1", "form-group-class-pre-layer": "h_det_input h_det_1",
"fieldType": "select", "fieldType": "select",
"possible": [ "possible": [
{ {
"name": lang.No, "name": lang.No,
"value": "0" "value": "0"
}, },
{ {
"name": lang.Yes, "name": lang.Yes,
"value": "1" "value": "1"
} }
] ]
}); });
} }

42
package-lock.json generated
View File

@ -37,10 +37,10 @@
"mysql2": "^2.1.0", "mysql2": "^2.1.0",
"node-abort-controller": "^3.0.1", "node-abort-controller": "^3.0.1",
"node-fetch": "^2.6.7", "node-fetch": "^2.6.7",
"node-onvif-events": "^2.0.5",
"node-ssh": "^12.0.4", "node-ssh": "^12.0.4",
"node-telegram-bot-api": "^0.61.0", "node-telegram-bot-api": "^0.61.0",
"nodemailer": "^6.7.1", "nodemailer": "^6.7.1",
"onvif": "^0.7.0",
"pam-diff": "^1.1.0", "pam-diff": "^1.1.0",
"path": "^0.12.7", "path": "^0.12.7",
"pipe2pam": "^0.6.2", "pipe2pam": "^0.6.2",
@ -5592,14 +5592,6 @@
"node": ">= 6.13.0" "node": ">= 6.13.0"
} }
}, },
"node_modules/node-onvif-events": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/node-onvif-events/-/node-onvif-events-2.0.5.tgz",
"integrity": "sha512-rZOHirBe/O47qD0zdjUBQn9dPFO9VdCw6ZSQGUN/Grjxh9p+LOZImN3kLuDdfNfczI8gIfg4JUV0LnSUSxzIeA==",
"dependencies": {
"onvif": "git+https://github.com/agsh/onvif.git"
}
},
"node_modules/node-ssh": { "node_modules/node-ssh": {
"version": "12.0.4", "version": "12.0.4",
"resolved": "https://registry.npmjs.org/node-ssh/-/node-ssh-12.0.4.tgz", "resolved": "https://registry.npmjs.org/node-ssh/-/node-ssh-12.0.4.tgz",
@ -5926,12 +5918,12 @@
} }
}, },
"node_modules/onvif": { "node_modules/onvif": {
"version": "0.6.9", "version": "0.7.0",
"resolved": "git+ssh://git@github.com/agsh/onvif.git#6495d3c6a18cc30dda19db3f06217cbf8b5d4160", "resolved": "git+ssh://git@github.com/agsh/onvif.git#8d7aefc8f73c24f5409ae678f18a2f68c6436e84",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"lodash.get": "^4.4.2", "lodash.get": "^4.4.2",
"xml2js": "^0.5.0" "xml2js": "^0.6.2"
}, },
"engines": { "engines": {
"node": ">=6.0" "node": ">=6.0"
@ -8079,9 +8071,9 @@
} }
}, },
"node_modules/xml2js": { "node_modules/xml2js": {
"version": "0.5.0", "version": "0.6.2",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
"integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==",
"dependencies": { "dependencies": {
"sax": ">=0.6.0", "sax": ">=0.6.0",
"xmlbuilder": "~11.0.0" "xmlbuilder": "~11.0.0"
@ -12438,14 +12430,6 @@
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
"integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA=="
}, },
"node-onvif-events": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/node-onvif-events/-/node-onvif-events-2.0.5.tgz",
"integrity": "sha512-rZOHirBe/O47qD0zdjUBQn9dPFO9VdCw6ZSQGUN/Grjxh9p+LOZImN3kLuDdfNfczI8gIfg4JUV0LnSUSxzIeA==",
"requires": {
"onvif": "git+https://github.com/agsh/onvif.git"
}
},
"node-ssh": { "node-ssh": {
"version": "12.0.4", "version": "12.0.4",
"resolved": "https://registry.npmjs.org/node-ssh/-/node-ssh-12.0.4.tgz", "resolved": "https://registry.npmjs.org/node-ssh/-/node-ssh-12.0.4.tgz",
@ -12709,11 +12693,11 @@
} }
}, },
"onvif": { "onvif": {
"version": "git+ssh://git@github.com/agsh/onvif.git#6495d3c6a18cc30dda19db3f06217cbf8b5d4160", "version": "git+ssh://git@github.com/agsh/onvif.git#8d7aefc8f73c24f5409ae678f18a2f68c6436e84",
"from": "onvif@git+https://github.com/agsh/onvif.git", "from": "onvif@^0.7.0",
"requires": { "requires": {
"lodash.get": "^4.4.2", "lodash.get": "^4.4.2",
"xml2js": "^0.5.0" "xml2js": "^0.6.2"
} }
}, },
"p-limit": { "p-limit": {
@ -14417,9 +14401,9 @@
"requires": {} "requires": {}
}, },
"xml2js": { "xml2js": {
"version": "0.5.0", "version": "0.6.2",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
"integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==",
"requires": { "requires": {
"sax": ">=0.6.0", "sax": ">=0.6.0",
"xmlbuilder": "~11.0.0" "xmlbuilder": "~11.0.0"

View File

@ -43,10 +43,10 @@
"mysql2": "^2.1.0", "mysql2": "^2.1.0",
"node-abort-controller": "^3.0.1", "node-abort-controller": "^3.0.1",
"node-fetch": "^2.6.7", "node-fetch": "^2.6.7",
"node-onvif-events": "^2.0.5",
"node-ssh": "^12.0.4", "node-ssh": "^12.0.4",
"node-telegram-bot-api": "^0.61.0", "node-telegram-bot-api": "^0.61.0",
"nodemailer": "^6.7.1", "nodemailer": "^6.7.1",
"onvif": "^0.7.0",
"pam-diff": "^1.1.0", "pam-diff": "^1.1.0",
"path": "^0.12.7", "path": "^0.12.7",
"pipe2pam": "^0.6.2", "pipe2pam": "^0.6.2",