Merge branch 'ptz-improvements' into 'dev'

Improve Automatic PTZ (Return Home when Object lost) + More

See merge request Shinobi-Systems/Shinobi!237
fix-non-showing-inputs
Moe 2020-09-21 04:27:48 +00:00
commit ecc4b5f42c
10 changed files with 223 additions and 65 deletions

View File

@ -420,6 +420,25 @@ module.exports = function(s,config,lang){
}
]
},
{
"name": "detail=onvif_non_standard",
"field": lang['Non-Standard ONVIF'],
"description": "Is this a Non-Standard ONVIF camera?",
"default": "0",
"example": "",
"form-group-class": "h_onvif_input h_onvif_1",
"fieldType": "select",
"possible": [
{
"name": lang.No,
"value": "0"
},
{
"name": lang.Yes,
"value": "1"
}
]
},
{
hidden: true,
"name": "detail=onvif_port",
@ -3608,6 +3627,24 @@ module.exports = function(s,config,lang){
"form-group-class": "h_control_call_input h_control_call_GET h_control_call_PUT h_control_call_POST",
"possible": ""
},
{
"name": "detail=control_invert_y",
"field": lang["Invert Y-Axis"],
"description": "For When your camera is mounted upside down or uses inverted vertical controls.",
"default": "0",
"example": "",
"fieldType": "select",
"possible": [
{
"name": lang.No,
"value": "0"
},
{
"name": lang.Yes,
"value": "1"
}
]
},
]
},
"Grouping": {

View File

@ -37,6 +37,7 @@
"Token": "Token",
"OAuth Code": "OAuth Code",
"Google Drive": "Google Drive",
"Invert Y-Axis": "Invert Y-Axis",
"Get Code": "Get Code",
"PTZ Tracking": "PTZ Tracking",
"PTZ Tracking Target": "PTZ Tracking Target",
@ -88,6 +89,7 @@
"Never": "Never",
"API": "API",
"ONVIF": "ONVIF",
"Non-Standard ONVIF": "Non-Standard ONVIF",
"FFprobe": "Probe",
"Monitor States": "Monitor States",
"Schedule": "Schedule",

View File

@ -2,5 +2,5 @@ var os = require('os');
var exec = require('child_process').exec;
module.exports = function(s,config,lang,app,io){
require('./control/onvif.js')(s,config,lang,app,io)
const ptz = require('./control/ptz.js')(s,config,lang,app,io)
// const ptz = require('./control/ptz.js')(s,config,lang,app,io)
}

View File

@ -17,13 +17,26 @@ module.exports = function(s,config,lang,app,io){
try{
const info = await device.init()
response.ok = true
response.device = device
}catch(err){
response.msg = 'Device responded with an error'
response.error = error
response.error = err
}
return response
}
const runOnvifMethod = (onvifOptions,callback) => {
const replaceDynamicInOptions = (Camera,options) => {
const newOptions = {}
Object.keys(options).forEach((key) => {
const value = options[key]
if(typeof value === 'string'){
newOptions[key] = value.replace(/__CURRENT_TOKEN/g,Camera.current_profile.token)
}else if(value !== undefined && value !== null){
newOptions[key] = value
}
})
return newOptions
}
const runOnvifMethod = async (onvifOptions,callback) => {
var onvifAuth = onvifOptions.auth
var response = {ok: false}
var errorMessage = function(msg,error){
@ -83,7 +96,8 @@ module.exports = function(s,config,lang,app,io){
var options
var command
if(argNames[0] === 'options' || argNames[0] === 'params'){
options = onvifOptions.options || {}
options = replaceDynamicInOptions(Camera,onvifOptions.options || {})
response.options = options
}
if(onvifAuth.service){
command = Camera.services[onvifAuth.service][onvifAuth.action](options)
@ -94,7 +108,7 @@ module.exports = function(s,config,lang,app,io){
}
}
if(!s.group[onvifAuth.ke].activeMonitors[onvifAuth.id].onvifConnection){
const response = createOnvifDevice(onvifAuth)
const response = await createOnvifDevice(onvifAuth)
if(response.ok){
doAction(response.device)
}else{
@ -112,15 +126,15 @@ module.exports = function(s,config,lang,app,io){
config.webPaths.apiPrefix+':auth/onvif/:ke/:id/:service/:action'
],function (req,res){
s.auth(req.params,function(user){
const options = s.getPostData(req,'options',true) || s.getPostData(req,'params',true)
runOnvifMethod({
auth: {
ke: req.params.ke,
id: req.params.id,
auth: req.params.auth,
action: req.params.action,
service: req.params.service,
},
options: s.getPostData(req,'options',true) || s.getPostData(req,'params',true),
options: options,
},(endData) => {
s.closeJsonResponse(res,endData)
})

View File

@ -1,8 +1,9 @@
var os = require('os');
var exec = require('child_process').exec;
var request = require('request')
module.exports = function(s,config,lang,app,io){
module.exports = function(s,config,lang){
const moveLock = {}
const ptzTimeoutsUntilResetToHome = {}
const startMove = async function(options,callback){
const device = s.group[options.ke].activeMonitors[options.id].onvifConnection
if(!device){
@ -41,6 +42,7 @@ module.exports = function(s,config,lang,app,io){
}
const moveOnvifCamera = function(options,callback){
const monitorConfig = s.group[options.ke].rawMonitorConfigurations[options.id]
const invertedVerticalAxis = monitorConfig.details.control_invert_y === '1'
const controlUrlStopTimeout = parseInt(monitorConfig.details.control_url_stop_timeout) || 1000
switch(options.direction){
case'center':
@ -68,8 +70,8 @@ module.exports = function(s,config,lang,app,io){
var onvifDirections = {
"left": [-1.0,'x'],
"right": [1.0,'x'],
"down": [-1.0,'y'],
"up": [1.0,'y'],
"down": [invertedVerticalAxis ? 1.0 : -1.0,'y'],
"up": [invertedVerticalAxis ? -1.0 : 1.0,'y'],
"zoom_in": [1.0,'z'],
"zoom_out": [-1.0,'z']
}
@ -258,10 +260,123 @@ module.exports = function(s,config,lang,app,io){
}
}
}
s.cameraControl = ptzControl
const getPresetPositions = (options,callback) => {
const profileToken = options.ProfileToken || "__CURRENT_TOKEN"
return s.runOnvifMethod({
auth: {
ke: options.ke,
id: options.id,
service: 'ptz',
action: 'getPresets',
},
options: {
ProfileToken: profileToken
},
},callback)
}
const setPresetForCurrentPosition = (options,callback) => {
const nonStandardOnvif = s.group[options.ke].rawMonitorConfigurations[options.id].details.onvif_non_standard === '1'
const profileToken = options.ProfileToken || "__CURRENT_TOKEN"
s.runOnvifMethod({
auth: {
ke: options.ke,
id: options.id,
service: 'ptz',
action: 'setPreset',
},
options: {
ProfileToken: profileToken,
PresetToken: nonStandardOnvif ? null : options.PresetToken || profileToken,
PresetName: options.PresetName || nonStandardOnvif ? '1' : profileToken
},
},(endData) => {
callback(endData)
})
}
const moveToPresetPosition = (options,callback) => {
const nonStandardOnvif = s.group[options.ke].rawMonitorConfigurations[options.id].details.onvif_non_standard === '1'
const profileToken = options.ProfileToken || "__CURRENT_TOKEN"
return s.runOnvifMethod({
auth: {
ke: options.ke,
id: options.id,
service: 'ptz',
action: 'gotoPreset',
},
options: {
ProfileToken: profileToken,
PresetToken: options.PresetToken || nonStandardOnvif ? '1' : profileToken,
Speed: {
"x": 1,
"y": 1,
"z": 1
},
},
},callback)
}
const getLargestMatrix = (matrices) => {
var largestMatrix = {width: 0, height: 0}
matrices.forEach((matrix) => {
if(matrix.width > largestMatrix.width && matrix.height > largestMatrix.height)largestMatrix = matrix
})
return largestMatrix.x ? largestMatrix : null
}
const moveCameraPtzToMatrix = function(event,trackingTarget){
if(moveLock[event.ke + event.id])return;
clearTimeout(moveLock[event.ke + event.id])
moveLock[event.ke + event.id] = setTimeout(() => {
delete(moveLock[event.ke + event.id])
},1000)
const imgHeight = event.details.imgHeight
const imgWidth = event.details.imgWidth
const thresholdX = imgWidth * 0.125
const thresholdY = imgHeight * 0.125
const imageCenterX = imgWidth / 2
const imageCenterY = imgHeight / 2
const matrices = event.details.matrices
const largestMatrix = getLargestMatrix(matrices.filter(matrix => matrix.tag === (trackingTarget || 'person')))
// console.log(matrices.find(matrix => matrix.tag === 'person'))
if(!largestMatrix)return;
const matrixCenterX = largestMatrix.x + (largestMatrix.width / 2)
const matrixCenterY = largestMatrix.y + (largestMatrix.height / 2)
const rawDistanceX = (matrixCenterX - imageCenterX)
const rawDistanceY = (matrixCenterY - imageCenterY)
const distanceX = imgWidth / rawDistanceX
const distanceY = imgHeight / rawDistanceY
const axisX = rawDistanceX > thresholdX || rawDistanceX < -thresholdX ? distanceX : 0
const axisY = largestMatrix.y < 30 && largestMatrix.height > imgHeight * 0.8 ? 0.5 : rawDistanceY > thresholdY || rawDistanceY < -thresholdY ? -distanceY : 0
if(axisX !== 0 || axisY !== 0){
ptzControl({
axis: [
{direction: 'x', amount: axisX === 0 ? 0 : axisX > 0 ? 0.01 : -0.01},
{direction: 'y', amount: axisY === 0 ? 0 : axisY > 0 ? 0.01 : -0.01},
{direction: 'z', amount: 0},
],
// axis: [{direction: 'x', amount: 1.0}],
id: event.id,
ke: event.ke
},(msg) => {
s.userLog(event,msg)
// console.log(msg)
clearTimeout(ptzTimeoutsUntilResetToHome[event.ke + event.id])
ptzTimeoutsUntilResetToHome[event.ke + event.id] = setTimeout(() => {
moveToPresetPosition({
ke: event.ke,
id: event.id,
},(endData) => {
console.log(endData)
})
},7000)
})
}
}
return {
control: ptzControl,
ptzControl: ptzControl,
startMove: startMove,
stopMove: stopMove,
getPresetPositions: getPresetPositions,
setPresetForCurrentPosition: setPresetForCurrentPosition,
moveToPresetPosition: moveToPresetPosition,
moveCameraPtzToMatrix: moveCameraPtzToMatrix
}
}

View File

@ -10,7 +10,9 @@ var P = SAT.Polygon;
var B = SAT.Box;
// Matrix In Region Libs />
module.exports = function(s,config,lang){
const ptz = require('./control/ptz.js')(s,config,lang)
const {
moveCameraPtzToMatrix,
} = require('./control/ptz.js')(s,config,lang)
const countObjects = async (event) => {
const matrices = event.details.matrices
const eventsCounted = s.group[event.ke].activeMonitors[event.id].eventsCounted || {}
@ -78,54 +80,6 @@ module.exports = function(s,config,lang){
return collisions
}
const nonEmpty = (element) => element.length !== 0;
const moveLock = {}
const getLargestMatrix = (matrices) => {
var largestMatrix = {width: 0, height: 0}
matrices.forEach((matrix) => {
if(matrix.width > largestMatrix.width && matrix.height > largestMatrix.height)largestMatrix = matrix
})
return largestMatrix.x ? largestMatrix : null
}
const moveCameraPtzToMatrix = function(event,trackingTarget){
if(moveLock[event.ke + event.id])return;
clearTimeout(moveLock[event.ke + event.id])
moveLock[event.ke + event.id] = setTimeout(() => {
delete(moveLock[event.ke + event.id])
},1000)
const imgHeight = event.details.imgHeight
const imgWidth = event.details.imgWidth
const thresholdX = imgWidth * 0.125
const thresholdY = imgHeight * 0.125
const imageCenterX = imgWidth / 2
const imageCenterY = imgHeight / 2
const matrices = event.details.matrices
const largestMatrix = getLargestMatrix(matrices.filter(matrix => matrix.tag === (trackingTarget || 'person')))
// console.log(matrices.find(matrix => matrix.tag === 'person'))
if(!largestMatrix)return;
const matrixCenterX = largestMatrix.x + (largestMatrix.width / 2)
const matrixCenterY = largestMatrix.y + (largestMatrix.height / 2)
const rawDistanceX = (matrixCenterX - imageCenterX)
const rawDistanceY = (matrixCenterY - imageCenterY)
const distanceX = imgWidth / rawDistanceX
const distanceY = imgHeight / rawDistanceY
const axisX = rawDistanceX > thresholdX || rawDistanceX < -thresholdX ? distanceX : 0
const axisY = largestMatrix.y < 30 && largestMatrix.height > imgHeight * 0.8 ? 0.5 : rawDistanceY > thresholdY || rawDistanceY < -thresholdY ? -distanceY : 0
if(axisX !== 0 || axisY !== 0){
ptz.control({
axis: [
{direction: 'x', amount: axisX === 0 ? 0 : axisX > 0 ? 0.01 : -0.01},
{direction: 'y', amount: axisY === 0 ? 0 : axisY > 0 ? 0.01 : -0.01},
{direction: 'z', amount: 0},
],
// axis: [{direction: 'x', amount: 1.0}],
id: event.id,
ke: event.ke
},(msg) => {
s.userLog(event,msg)
// console.log(msg)
})
}
}
s.addEventDetailsToString = function(eventData,string,addOps){
//d = event data
if(!addOps)addOps = {}

View File

@ -13,6 +13,9 @@ const URL = require('url')
const { copyObject, createQueue } = require('./common.js')
module.exports = function(s,config,lang){
const { cameraDestroy } = require('./monitor/utils.js')(s,config,lang)
const {
setPresetForCurrentPosition
} = require('./control/ptz.js')(s,config,lang)
const startMonitorInQueue = createQueue(1, 3)
s.initiateMonitorObject = function(e){
if(!s.group[e.ke]){s.group[e.ke]={}};
@ -455,7 +458,6 @@ module.exports = function(s,config,lang){
ke: e.ke
},'GRP_'+e.ke)
}else{
console.log('not image')
s.tx({f:'monitor_snapshot',snapshot:e.mon.name,snapshot_format:'plc',mid:e.mid,ke:e.ke},'GRP_'+e.ke)
}
}else{
@ -1607,6 +1609,34 @@ module.exports = function(s,config,lang){
break;
}
}
if(e.details.detector_ptz_follow === '1'){
setTimeout(() => {
setPresetForCurrentPosition({
ke: e.ke,
id: e.id
},(endData) => {
if(endData.ok === false){
setTimeout(() => {
setPresetForCurrentPosition({
ke: e.ke,
id: e.id
},(endData) => {
if(endData.ok === false){
setTimeout(() => {
setPresetForCurrentPosition({
ke: e.ke,
id: e.id
},(endData) => {
console.log(endData)
})
},5000)
}
})
},5000)
}
})
},5000)
}
launchMonitorProcesses(e)
break;
default:

View File

@ -54,7 +54,7 @@ module.exports = function(s,config,lang,app,io){
ip = addressRange.join(',')
}
if(ports === ''){
ports = '80,8080,8000,7575,8081,9080,8090,8999'
ports = '80,8080,8000,7575,8081,9080,8090,8999,8899'
}
if(ports.indexOf('-') > -1){
ports = ports.split('-')

View File

@ -4,6 +4,9 @@ var exec = require('child_process').exec;
var spawn = require('child_process').spawn;
var jsonfile = require("jsonfile");
module.exports = function(s,config,lang,io){
const {
ptzControl
} = require('./control/ptz.js')(s,config,lang)
s.clientSocketConnection = {}
//send data to socket client function
s.tx = function(z,y,x){
@ -649,7 +652,7 @@ module.exports = function(s,config,lang,io){
}
break;
case'control':
s.cameraControl(d,function(msg){
ptzControl(d,function(msg){
s.userLog(d,msg)
tx({f:'control',response:msg})
})

View File

@ -12,6 +12,9 @@ var proxy = httpProxy.createProxyServer({})
var ejs = require('ejs');
var fileupload = require("express-fileupload");
module.exports = function(s,config,lang,app,io){
const {
ptzControl
} = require('./control/ptz.js')(s,config,lang,app,io)
if(config.productType === 'Pro'){
var LdapAuth = require('ldapauth-fork');
}
@ -1655,7 +1658,7 @@ module.exports = function(s,config,lang,app,io){
app.get(config.webPaths.apiPrefix+':auth/control/:ke/:id/:direction', function (req,res){
res.setHeader('Content-Type', 'application/json');
s.auth(req.params,function(user){
s.cameraControl(req.params,function(msg){
ptzControl(req.params,function(msg){
s.userLog({
id: req.params.id,
ke: req.params.ke,