Audio Detector, Detect Object in Region, and API Methods for Scheduling System
- Audio Detector measures decibels (dB). Section can be found under Motion Detection. - Regions can now be used with Object detection alone, find the option the Object Detection section. - Scheduling System will allow automatically activating Monitor States based on time. GUI will be posted in the next commit. + Update Installers + Update framework.sql + `npm test` will run the test + Minor Bug Fixesmerge-requests/49/head
parent
91f530c461
commit
afdc0cf568
|
@ -143,21 +143,14 @@ if [ "$mysqlDefaultData" = "y" ] || [ "$mysqlDefaultData" = "Y" ]; then
|
||||||
echo "====================================="
|
echo "====================================="
|
||||||
echo "====================================="
|
echo "====================================="
|
||||||
fi
|
fi
|
||||||
if [ ! "$sqliteormariadb" = "M" ] && [ ! "$sqliteormariadb" = "m" ]; then
|
echo "====================================="
|
||||||
echo "====================================="
|
echo "||===== Install Completed =====||"
|
||||||
echo "||===== Install Completed =====||"
|
echo "====================================="
|
||||||
echo "====================================="
|
echo "|| Login with the Superuser and create a new user!!"
|
||||||
echo "|| Login with the Superuser and create a new user!!"
|
echo "||==================================="
|
||||||
echo "||==================================="
|
echo "|| Open http://$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'):8080/super in your web browser."
|
||||||
echo "|| Open http://$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'):8080/super in your web browser."
|
echo "||==================================="
|
||||||
echo "||==================================="
|
echo "|| Default Superuser : admin@shinobi.video"
|
||||||
echo "|| Default Superuser : admin@shinobi.video"
|
echo "|| Default Password : admin"
|
||||||
echo "|| Default Password : admin"
|
echo "====================================="
|
||||||
echo "====================================="
|
echo "====================================="
|
||||||
echo "====================================="
|
|
||||||
else
|
|
||||||
echo "+=================================+"
|
|
||||||
echo "||===== Install Completed =====||"
|
|
||||||
echo "|| Access the main Shinobi panel at http://$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'):8080 in your web browser."
|
|
||||||
echo "+=================================+"
|
|
||||||
fi
|
|
||||||
|
|
|
@ -115,15 +115,6 @@ sudo chmod -R 755 .
|
||||||
touch INSTALL/installed.txt
|
touch INSTALL/installed.txt
|
||||||
dos2unix /home/Shinobi/INSTALL/shinobi
|
dos2unix /home/Shinobi/INSTALL/shinobi
|
||||||
ln -s /home/Shinobi/INSTALL/shinobi /usr/bin/shinobi
|
ln -s /home/Shinobi/INSTALL/shinobi /usr/bin/shinobi
|
||||||
if [ "$mysqlDefaultData" = "y" ] || [ "$mysqlDefaultData" = "Y" ]; then
|
|
||||||
echo "=====================================" > INSTALL/installed.txt
|
|
||||||
echo "======= Login Credentials =======" >> INSTALL/installed.txt
|
|
||||||
echo "|| Username : $userEmail" >> INSTALL/installed.txt
|
|
||||||
echo "|| Password : $userPasswordPlain" >> INSTALL/installed.txt
|
|
||||||
echo "|| API Key : $apiKey" >> INSTALL/installed.txt
|
|
||||||
echo "=====================================" >> INSTALL/installed.txt
|
|
||||||
echo "=====================================" >> INSTALL/installed.txt
|
|
||||||
fi
|
|
||||||
echo "Shinobi - Start Shinobi and set to start on boot?"
|
echo "Shinobi - Start Shinobi and set to start on boot?"
|
||||||
echo "(y)es or (N)o"
|
echo "(y)es or (N)o"
|
||||||
read startShinobi
|
read startShinobi
|
||||||
|
@ -134,31 +125,14 @@ if [ "$startShinobi" = "y" ] || [ "$startShinobi" = "Y" ]; then
|
||||||
sudo pm2 save
|
sudo pm2 save
|
||||||
sudo pm2 list
|
sudo pm2 list
|
||||||
fi
|
fi
|
||||||
if [ "$mysqlDefaultData" = "y" ] || [ "$mysqlDefaultData" = "Y" ]; then
|
echo "====================================="
|
||||||
echo "details written to INSTALL/installed.txt"
|
echo "||===== Install Completed =====||"
|
||||||
echo "====================================="
|
echo "====================================="
|
||||||
echo "======= Login Credentials ======="
|
echo "|| Login with the Superuser and create a new user!!"
|
||||||
echo "|| Username : $userEmail"
|
echo "||==================================="
|
||||||
echo "|| Password : $userPasswordPlain"
|
echo "|| Open http://$(/sbin/ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1):8080/super in your web browser."
|
||||||
echo "|| API Key : $apiKey"
|
echo "||==================================="
|
||||||
echo "====================================="
|
echo "|| Default Superuser : admin@shinobi.video"
|
||||||
echo "====================================="
|
echo "|| Default Password : admin"
|
||||||
fi
|
echo "====================================="
|
||||||
if [ ! "$sqliteormariadb" = "M" ] && [ ! "$sqliteormariadb" = "m" ]; then
|
echo "====================================="
|
||||||
echo "====================================="
|
|
||||||
echo "||===== Install Completed =====||"
|
|
||||||
echo "====================================="
|
|
||||||
echo "|| Login with the Superuser and create a new user!!"
|
|
||||||
echo "||==================================="
|
|
||||||
echo "|| Open http://$(/sbin/ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1):8080/super in your web browser."
|
|
||||||
echo "||==================================="
|
|
||||||
echo "|| Default Superuser : admin@shinobi.video"
|
|
||||||
echo "|| Default Password : admin"
|
|
||||||
echo "====================================="
|
|
||||||
echo "====================================="
|
|
||||||
else
|
|
||||||
echo "+=================================+"
|
|
||||||
echo "||===== Install Completed =====||"
|
|
||||||
echo "|| Access the main Shinobi panel at http://$(/sbin/ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1):8080 in your web browser."
|
|
||||||
echo "+=================================+"
|
|
||||||
fi
|
|
||||||
|
|
|
@ -30,12 +30,17 @@ if [ ! -e "./super.json" ]; then
|
||||||
echo "* You can edit these settings in \"super.json\" located in the Shinobi directory."
|
echo "* You can edit these settings in \"super.json\" located in the Shinobi directory."
|
||||||
sudo cp super.sample.json super.json
|
sudo cp super.sample.json super.json
|
||||||
fi
|
fi
|
||||||
|
if ! [ -x "$(command -v ifconfig)" ]; then
|
||||||
|
echo "============="
|
||||||
|
echo "Shinobi - Installing Net-Tools"
|
||||||
|
sudo apt install net-tools -y
|
||||||
|
fi
|
||||||
if ! [ -x "$(command -v node)" ]; then
|
if ! [ -x "$(command -v node)" ]; then
|
||||||
echo "============="
|
echo "============="
|
||||||
echo "Shinobi - Installing Node.js"
|
echo "Shinobi - Installing Node.js"
|
||||||
wget https://deb.nodesource.com/setup_9.x
|
wget https://deb.nodesource.com/setup_8.x
|
||||||
chmod +x setup_9.x
|
chmod +x setup_8.x
|
||||||
./setup_9.x
|
./setup_8.x
|
||||||
sudo apt install nodejs -y
|
sudo apt install nodejs -y
|
||||||
else
|
else
|
||||||
echo "Node.js Found..."
|
echo "Node.js Found..."
|
||||||
|
@ -132,21 +137,14 @@ if [ "$startShinobi" = "y" ] || [ "$startShinobi" = "y" ]; then
|
||||||
sudo pm2 save
|
sudo pm2 save
|
||||||
sudo pm2 list
|
sudo pm2 list
|
||||||
fi
|
fi
|
||||||
if [ ! "$sqliteormariadb" = "M" ] && [ ! "$sqliteormariadb" = "m" ]; then
|
echo "====================================="
|
||||||
echo "====================================="
|
echo "||===== Install Completed =====||"
|
||||||
echo "||===== Install Completed =====||"
|
echo "====================================="
|
||||||
echo "====================================="
|
echo "|| Login with the Superuser and create a new user!!"
|
||||||
echo "|| Login with the Superuser and create a new user!!"
|
echo "||==================================="
|
||||||
echo "||==================================="
|
echo "|| Open http://$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'):8080/super in your web browser."
|
||||||
echo "|| Open http://$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'):8080/super in your web browser."
|
echo "||==================================="
|
||||||
echo "||==================================="
|
echo "|| Default Superuser : admin@shinobi.video"
|
||||||
echo "|| Default Superuser : admin@shinobi.video"
|
echo "|| Default Password : admin"
|
||||||
echo "|| Default Password : admin"
|
echo "====================================="
|
||||||
echo "====================================="
|
echo "====================================="
|
||||||
echo "====================================="
|
|
||||||
else
|
|
||||||
echo "+=================================+"
|
|
||||||
echo "||===== Install Completed =====||"
|
|
||||||
echo "|| Access the main Shinobi panel at http://$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'):8080 in your web browser."
|
|
||||||
echo "+=================================+"
|
|
||||||
fi
|
|
||||||
|
|
|
@ -67,6 +67,8 @@ loadLib('ffmpeg')(s,config,function(){
|
||||||
loadLib('notification')(s,config,lang)
|
loadLib('notification')(s,config,lang)
|
||||||
//custom module loader
|
//custom module loader
|
||||||
loadLib('customAutoLoad')(s,config,lang,app,io)
|
loadLib('customAutoLoad')(s,config,lang,app,io)
|
||||||
|
//scheduling engine
|
||||||
|
loadLib('scheduler')(s,config,lang,app,io)
|
||||||
//on-start actions, daemon(s) starter
|
//on-start actions, daemon(s) starter
|
||||||
loadLib('startup')(s,config,lang)
|
loadLib('startup')(s,config,lang)
|
||||||
})
|
})
|
||||||
|
|
|
@ -329,6 +329,10 @@
|
||||||
"Filter for Objects only": "Filter for Objects only",
|
"Filter for Objects only": "Filter for Objects only",
|
||||||
"Custom": "Custom",
|
"Custom": "Custom",
|
||||||
"Detector": "Detector",
|
"Detector": "Detector",
|
||||||
|
"Audio Detector": "Audio Detector",
|
||||||
|
"Audio Detection": "Audio Detection",
|
||||||
|
"Minimum dB": "Minimum dB",
|
||||||
|
"Maximum dB": "Maximum dB",
|
||||||
"Connected": "Connected",
|
"Connected": "Connected",
|
||||||
"Not Saved": "Not Saved",
|
"Not Saved": "Not Saved",
|
||||||
"Not Connected": "Not Connected",
|
"Not Connected": "Not Connected",
|
||||||
|
@ -666,6 +670,10 @@
|
||||||
"Inserted State Configuration": "Inserted State Configuration",
|
"Inserted State Configuration": "Inserted State Configuration",
|
||||||
"Edited State Configuration": "Edited State Configuration",
|
"Edited State Configuration": "Edited State Configuration",
|
||||||
"Deleted State Configuration": "Deleted State Configuration",
|
"Deleted State Configuration": "Deleted State Configuration",
|
||||||
|
"Schedule Configuration Not Found": "Schedule Configuration Not Found",
|
||||||
|
"Inserted Schedule Configuration": "Inserted Schedule Configuration",
|
||||||
|
"Edited Schedule Configuration": "Edited Schedule Configuration",
|
||||||
|
"Deleted Schedule Configuration": "Deleted Schedule Configuration",
|
||||||
"Dashboard Language": "Dashboard Language",
|
"Dashboard Language": "Dashboard Language",
|
||||||
"Form Data Not Found": "Form Data Not Found",
|
"Form Data Not Found": "Form Data Not Found",
|
||||||
"File Not Found": "File Not Found",
|
"File Not Found": "File Not Found",
|
||||||
|
@ -792,6 +800,7 @@
|
||||||
"TV Channel ID":"TV Channel ID",
|
"TV Channel ID":"TV Channel ID",
|
||||||
"TV Channel Group":"TV Channel Group",
|
"TV Channel Group":"TV Channel Group",
|
||||||
"Emotion Average":"Emotion Average",
|
"Emotion Average":"Emotion Average",
|
||||||
|
"Require Object to be in Region":"Require Object to be in Region",
|
||||||
"Show Regions of Interest":"Show Regions of Interest",
|
"Show Regions of Interest":"Show Regions of Interest",
|
||||||
"Confidence of Detection":"Confidence of Detection",
|
"Confidence of Detection":"Confidence of Detection",
|
||||||
"Edit Selected":"Edit Selected",
|
"Edit Selected":"Edit Selected",
|
||||||
|
|
|
@ -33,7 +33,7 @@ module.exports = function(s,config){
|
||||||
s.parseJSON = function(string){
|
s.parseJSON = function(string){
|
||||||
var parsed
|
var parsed
|
||||||
try{
|
try{
|
||||||
string = JSON.parse(string)
|
parsed = JSON.parse(string)
|
||||||
}catch(err){
|
}catch(err){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
var P2P = require('pipe2pam');
|
// Matrix In Region Libs >
|
||||||
|
var SAT = require('sat')
|
||||||
|
var V = SAT.Vector;
|
||||||
|
var P = SAT.Polygon;
|
||||||
|
// Matrix In Region Libs />
|
||||||
|
var P2P = require('pipe2pam')
|
||||||
// pamDiff is based on https://www.npmjs.com/package/pam-diff
|
// pamDiff is based on https://www.npmjs.com/package/pam-diff
|
||||||
var PamDiff = require('./detectorPamDiff.js');
|
var PamDiff = require('pam-diff')
|
||||||
module.exports = function(s,config){
|
module.exports = function(s,config){
|
||||||
s.createPamDiffEngine = function(e){
|
s.createPamDiffEngine = function(e){
|
||||||
var width,
|
var width,
|
||||||
|
@ -46,7 +51,7 @@ module.exports = function(s,config){
|
||||||
[width,height],
|
[width,height],
|
||||||
[width,0]
|
[width,0]
|
||||||
]
|
]
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e.triggerTimer = {}
|
e.triggerTimer = {}
|
||||||
|
@ -58,7 +63,7 @@ module.exports = function(s,config){
|
||||||
regions : regions.forPam,
|
regions : regions.forPam,
|
||||||
drawMatrix : e.details.detector_show_matrix
|
drawMatrix : e.details.detector_show_matrix
|
||||||
});
|
});
|
||||||
s.group[e.ke].mon[e.id].p2p = new P2P();
|
s.group[e.ke].mon[e.id].p2p = new P2P()
|
||||||
var regionArray = Object.values(regionJson)
|
var regionArray = Object.values(regionJson)
|
||||||
if(config.detectorMergePamRegionTriggers === true){
|
if(config.detectorMergePamRegionTriggers === true){
|
||||||
// merge pam triggers for performance boost
|
// merge pam triggers for performance boost
|
||||||
|
@ -317,4 +322,39 @@ module.exports = function(s,config){
|
||||||
}
|
}
|
||||||
return trigger
|
return trigger
|
||||||
}
|
}
|
||||||
|
s.isAtleastOneMatrixInRegion = function(regions,matrices,callback){
|
||||||
|
var regionPolys = []
|
||||||
|
var matrixPoints = []
|
||||||
|
regions.forEach(function(region,n){
|
||||||
|
var polyPoints = []
|
||||||
|
region.points.forEach(function(point){
|
||||||
|
polyPoints.push(new V(parseInt(point[0]),parseInt(point[1])))
|
||||||
|
})
|
||||||
|
regionPolys[n] = new P(new V(0,0), polyPoints)
|
||||||
|
})
|
||||||
|
var collisions = []
|
||||||
|
var foundInRegion = false
|
||||||
|
matrices.forEach(function(matrix){
|
||||||
|
var matrixPoints = [
|
||||||
|
new V(matrix.x,matrix.y),
|
||||||
|
new V(matrix.width,matrix.y),
|
||||||
|
new V(matrix.width,matrix.height),
|
||||||
|
new V(matrix.x,matrix.height)
|
||||||
|
]
|
||||||
|
var matrixPoly = new P(new V(0,0), matrixPoints)
|
||||||
|
regionPolys.forEach(function(region,n){
|
||||||
|
var response = new SAT.Response()
|
||||||
|
var collided = SAT.testPolygonPolygon(matrixPoly, region, response)
|
||||||
|
if(collided === true){
|
||||||
|
collisions.push({
|
||||||
|
matrix: matrix,
|
||||||
|
region: regions[n]
|
||||||
|
})
|
||||||
|
foundInRegion = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if(callback)callback(foundInRegion,collisions)
|
||||||
|
return foundInRegion
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ module.exports = function(s,config,lang){
|
||||||
}
|
}
|
||||||
d.mon=s.group[d.ke].mon_conf[d.id];
|
d.mon=s.group[d.ke].mon_conf[d.id];
|
||||||
var currentConfig = s.group[d.ke].mon[d.id].details
|
var currentConfig = s.group[d.ke].mon[d.id].details
|
||||||
|
var hasMatrices = (d.details.matrices && d.details.matrices.length > 0)
|
||||||
//read filters
|
//read filters
|
||||||
if(
|
if(
|
||||||
currentConfig.use_detector_filters === '1' &&
|
currentConfig.use_detector_filters === '1' &&
|
||||||
|
@ -160,7 +161,7 @@ module.exports = function(s,config,lang){
|
||||||
})
|
})
|
||||||
if(d.details.matrices && d.details.matrices.length === 0 || filter.halt === true){
|
if(d.details.matrices && d.details.matrices.length === 0 || filter.halt === true){
|
||||||
return
|
return
|
||||||
}else if(d.details.matrices && d.details.matrices.length > 0){
|
}else if(hasMatrices){
|
||||||
var reviewedMatrix = []
|
var reviewedMatrix = []
|
||||||
d.details.matrices.forEach(function(matrix){
|
d.details.matrices.forEach(function(matrix){
|
||||||
if(matrix)reviewedMatrix.push(matrix)
|
if(matrix)reviewedMatrix.push(matrix)
|
||||||
|
@ -193,6 +194,16 @@ module.exports = function(s,config,lang){
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// check if object should be in region
|
||||||
|
if(hasMatrices && currentConfig.detector_obj_region === '1'){
|
||||||
|
var regions = s.group[d.ke].mon[d.id].parsedObjects.cords
|
||||||
|
var isMatrixInRegions = s.isAtleastOneMatrixInRegion(regions,d.details.matrices)
|
||||||
|
if(isMatrixInRegions){
|
||||||
|
s.debugLog('Matrix in region!')
|
||||||
|
}else{
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
// check modified indifference
|
// check modified indifference
|
||||||
if(filter.indifference !== false && d.details.confidence < parseFloat(filter.indifference)){
|
if(filter.indifference !== false && d.details.confidence < parseFloat(filter.indifference)){
|
||||||
// fails indifference check for modified indifference
|
// fails indifference check for modified indifference
|
||||||
|
|
|
@ -735,6 +735,17 @@ module.exports = function(s,config,onFinish){
|
||||||
x.record_string+=x.vcodec+x.record_fps+x.record_video_filters+x.record_dimensions+x.segment;
|
x.record_string+=x.vcodec+x.record_fps+x.record_video_filters+x.record_dimensions+x.segment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ffmpeg.buildAudioDetector = function(e,x){
|
||||||
|
if(e.details.detector_audio === '1'){
|
||||||
|
if(e.details.input_map_choices&&e.details.input_map_choices.detector_audio){
|
||||||
|
//add input feed map
|
||||||
|
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector_audio)
|
||||||
|
}else{
|
||||||
|
x.pipe += ' -map 0:a'
|
||||||
|
}
|
||||||
|
x.pipe += ' -acodec pcm_s16le -f s16le -ac 1 -ar 16000 pipe:6'
|
||||||
|
}
|
||||||
|
}
|
||||||
ffmpeg.buildMainDetector = function(e,x){
|
ffmpeg.buildMainDetector = function(e,x){
|
||||||
//e = monitor object
|
//e = monitor object
|
||||||
//x = temporary values
|
//x = temporary values
|
||||||
|
@ -761,10 +772,10 @@ module.exports = function(s,config,onFinish){
|
||||||
if(e.details.detector_use_detect_object === '1'){
|
if(e.details.detector_use_detect_object === '1'){
|
||||||
//for object detection
|
//for object detection
|
||||||
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector)
|
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector)
|
||||||
x.pipe += ' -f singlejpeg '+x.detector_vf+x.cust_detect+x.dratio+' pipe:4';
|
x.pipe += ' -an -f singlejpeg '+x.detector_vf+x.cust_detect+x.dratio+' pipe:4';
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
x.pipe+=' -f image2pipe '+x.detector_vf+x.cust_detect+x.dratio+' pipe:3';
|
x.pipe+=' -an -f image2pipe '+x.detector_vf+x.cust_detect+x.dratio+' pipe:3';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Traditional Recording Buffer
|
//Traditional Recording Buffer
|
||||||
|
@ -886,6 +897,7 @@ module.exports = function(s,config,onFinish){
|
||||||
ffmpeg.buildMainInput(e,x)
|
ffmpeg.buildMainInput(e,x)
|
||||||
ffmpeg.buildMainStream(e,x)
|
ffmpeg.buildMainStream(e,x)
|
||||||
ffmpeg.buildMainRecording(e,x)
|
ffmpeg.buildMainRecording(e,x)
|
||||||
|
ffmpeg.buildAudioDetector(e,x)
|
||||||
ffmpeg.buildMainDetector(e,x)
|
ffmpeg.buildMainDetector(e,x)
|
||||||
s.onFfmpegCameraStringCreationExtensions.forEach(function(extender){
|
s.onFfmpegCameraStringCreationExtensions.forEach(function(extender){
|
||||||
extender(e,x)
|
extender(e,x)
|
||||||
|
|
106
libs/monitor.js
106
libs/monitor.js
|
@ -6,6 +6,7 @@ var Mp4Frag = require('mp4frag');
|
||||||
var onvif = require('node-onvif');
|
var onvif = require('node-onvif');
|
||||||
var request = require('request');
|
var request = require('request');
|
||||||
var connectionTester = require('connection-tester')
|
var connectionTester = require('connection-tester')
|
||||||
|
var SoundDetection = require('shinobi-sound-detection')
|
||||||
var URL = require('url')
|
var URL = require('url')
|
||||||
module.exports = function(s,config,lang){
|
module.exports = function(s,config,lang){
|
||||||
s.initiateMonitorObject = function(e){
|
s.initiateMonitorObject = function(e){
|
||||||
|
@ -21,6 +22,7 @@ module.exports = function(s,config,lang){
|
||||||
if(!s.group[e.ke].mon[e.mid].eventBasedRecording){s.group[e.ke].mon[e.mid].eventBasedRecording={}};
|
if(!s.group[e.ke].mon[e.mid].eventBasedRecording){s.group[e.ke].mon[e.mid].eventBasedRecording={}};
|
||||||
if(!s.group[e.ke].mon[e.mid].watch){s.group[e.ke].mon[e.mid].watch={}};
|
if(!s.group[e.ke].mon[e.mid].watch){s.group[e.ke].mon[e.mid].watch={}};
|
||||||
if(!s.group[e.ke].mon[e.mid].fixingVideos){s.group[e.ke].mon[e.mid].fixingVideos={}};
|
if(!s.group[e.ke].mon[e.mid].fixingVideos){s.group[e.ke].mon[e.mid].fixingVideos={}};
|
||||||
|
if(!s.group[e.ke].mon[e.mid].parsedObjects){s.group[e.ke].mon[e.mid].parsedObjects={}};
|
||||||
if(!s.group[e.ke].mon[e.mid].isStarted){s.group[e.ke].mon[e.mid].isStarted = false};
|
if(!s.group[e.ke].mon[e.mid].isStarted){s.group[e.ke].mon[e.mid].isStarted = false};
|
||||||
if(s.group[e.ke].mon[e.mid].delete){clearTimeout(s.group[e.ke].mon[e.mid].delete)}
|
if(s.group[e.ke].mon[e.mid].delete){clearTimeout(s.group[e.ke].mon[e.mid].delete)}
|
||||||
if(!s.group[e.ke].mon_conf){s.group[e.ke].mon_conf={}}
|
if(!s.group[e.ke].mon_conf){s.group[e.ke].mon_conf={}}
|
||||||
|
@ -282,12 +284,20 @@ module.exports = function(s,config,lang){
|
||||||
s.cameraCheckObjectsInDetails = function(e){
|
s.cameraCheckObjectsInDetails = function(e){
|
||||||
//parse Objects
|
//parse Objects
|
||||||
(['detector_cascades','cords','detector_filters','input_map_choices']).forEach(function(v){
|
(['detector_cascades','cords','detector_filters','input_map_choices']).forEach(function(v){
|
||||||
if(e.details&&e.details[v]&&(e.details[v] instanceof Object)===false){
|
if(e.details && e.details[v]){
|
||||||
try{
|
try{
|
||||||
if(e.details[v] === '') e.details[v] = '{}'
|
if(!e.details[v] || e.details[v] === '')e.details[v] = '{}'
|
||||||
e.details[v]=JSON.parse(e.details[v]);
|
e.details[v] = s.parseJSON(e.details[v])
|
||||||
if(!e.details[v])e.details[v]={};
|
if(!e.details[v])e.details[v] = {}
|
||||||
s.group[e.ke].mon[e.id].details = e.details;
|
s.group[e.ke].mon[e.id].details = e.details
|
||||||
|
switch(v){
|
||||||
|
case'cords':
|
||||||
|
s.group[e.ke].mon[e.id].parsedObjects[v] = Object.values(s.parseJSON(e.details[v]))
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s.group[e.ke].mon[e.id].parsedObjects[v] = s.parseJSON(e.details[v])
|
||||||
|
break;
|
||||||
|
}
|
||||||
}catch(err){
|
}catch(err){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -776,6 +786,46 @@ module.exports = function(s,config,lang){
|
||||||
if(e.type==='jpeg'){
|
if(e.type==='jpeg'){
|
||||||
s.cameraPullJpegStream(e)
|
s.cameraPullJpegStream(e)
|
||||||
}
|
}
|
||||||
|
if(e.details.detector_audio === '1'){
|
||||||
|
var triggerLevel
|
||||||
|
var triggerLevelMax
|
||||||
|
if(e.details.detector_audio_min_db && e.details.detector_audio_min_db !== ''){
|
||||||
|
triggerLevel = parseInt(e.details.detector_audio_min_db)
|
||||||
|
}else{
|
||||||
|
triggerLevel = 5
|
||||||
|
}
|
||||||
|
if(e.details.detector_audio_max_db && e.details.detector_audio_max_db !== ''){
|
||||||
|
triggerLevelMax = parseInt(e.details.detector_audio_max_db)
|
||||||
|
}
|
||||||
|
var audioDetector = new SoundDetection({
|
||||||
|
format: {
|
||||||
|
bitDepth: 16,
|
||||||
|
numberOfChannels: 1,
|
||||||
|
signed: true
|
||||||
|
},
|
||||||
|
triggerLevel: triggerLevel,
|
||||||
|
triggerLevelMax: triggerLevelMax
|
||||||
|
},function(dB) {
|
||||||
|
s.triggerEvent({
|
||||||
|
f:'trigger',
|
||||||
|
id:e.id,
|
||||||
|
ke:e.ke,
|
||||||
|
name: 'db',
|
||||||
|
details:{
|
||||||
|
plug:'audio',
|
||||||
|
name:'db',
|
||||||
|
reason:'soundChange',
|
||||||
|
confidence:dB
|
||||||
|
},
|
||||||
|
plates:[],
|
||||||
|
imgHeight:e.details.detector_scale_y,
|
||||||
|
imgWidth:e.details.detector_scale_x
|
||||||
|
})
|
||||||
|
})
|
||||||
|
s.group[e.ke].mon[e.id].audioDetector = audioDetector
|
||||||
|
audioDetector.start()
|
||||||
|
s.group[e.ke].mon[e.id].spawn.stdio[6].pipe(audioDetector.streamDecoder)
|
||||||
|
}
|
||||||
if(e.details.detector === '1'){
|
if(e.details.detector === '1'){
|
||||||
s.ocvTx({f:'init_monitor',id:e.id,ke:e.ke})
|
s.ocvTx({f:'init_monitor',id:e.id,ke:e.ke})
|
||||||
//frames from motion detect
|
//frames from motion detect
|
||||||
|
@ -1435,7 +1485,7 @@ module.exports = function(s,config,lang){
|
||||||
s.group[e.ke].mon[e.mid].isRecording = false
|
s.group[e.ke].mon[e.mid].isRecording = false
|
||||||
}
|
}
|
||||||
//set up fatal error handler
|
//set up fatal error handler
|
||||||
if(e.details.fatal_max===''){
|
if(e.details.fatal_max === ''){
|
||||||
e.details.fatal_max = 10
|
e.details.fatal_max = 10
|
||||||
}else{
|
}else{
|
||||||
e.details.fatal_max = parseFloat(e.details.fatal_max)
|
e.details.fatal_max = parseFloat(e.details.fatal_max)
|
||||||
|
@ -1454,4 +1504,48 @@ module.exports = function(s,config,lang){
|
||||||
}
|
}
|
||||||
if(typeof cn === 'function'){setTimeout(function(){cn()},1000)}
|
if(typeof cn === 'function'){setTimeout(function(){cn()},1000)}
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
s.activateMonitorStates = function(groupKey,stateName,user,callback){
|
||||||
|
var endData = {
|
||||||
|
ok: false
|
||||||
|
}
|
||||||
|
s.findPreset([groupKey,'monitorStates',stateName],function(notFound,preset){
|
||||||
|
if(notFound === false){
|
||||||
|
var sqlQuery = 'SELECT * FROM Monitors WHERE ke=? AND '
|
||||||
|
var monitorQuery = []
|
||||||
|
var sqlQueryValues = [groupKey]
|
||||||
|
var monitorPresets = {}
|
||||||
|
preset.details.monitors.forEach(function(monitor){
|
||||||
|
monitorQuery.push('mid=?')
|
||||||
|
sqlQueryValues.push(monitor.mid)
|
||||||
|
monitorPresets[monitor.mid] = monitor
|
||||||
|
})
|
||||||
|
sqlQuery += '('+monitorQuery.join(' OR ')+')'
|
||||||
|
s.sqlQuery(sqlQuery,sqlQueryValues,function(err,monitors){
|
||||||
|
if(monitors && monitors[0]){
|
||||||
|
monitors.forEach(function(monitor){
|
||||||
|
s.checkDetails(monitor)
|
||||||
|
s.checkDetails(monitorPresets[monitor.mid])
|
||||||
|
var monitorPreset = monitorPresets[monitor.mid]
|
||||||
|
monitorPreset.details = Object.assign(monitor.details,monitorPreset.details)
|
||||||
|
monitor = s.cleanMonitorObjectForDatabase(Object.assign(monitor,monitorPreset))
|
||||||
|
monitor.details = JSON.stringify(monitor.details)
|
||||||
|
s.addOrEditMonitor(Object.assign(monitor,{}),function(err,endData){
|
||||||
|
|
||||||
|
},user)
|
||||||
|
})
|
||||||
|
endData.ok = true
|
||||||
|
s.tx({f:'change_group_state',ke:groupKey,name:stateName},'GRP_'+groupKey)
|
||||||
|
callback(endData)
|
||||||
|
}else{
|
||||||
|
endData.msg = user.lang['State Configuration has no monitors associated']
|
||||||
|
callback(endData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
endData.msg = user.lang['State Configuration Not Found']
|
||||||
|
callback(endData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,257 @@
|
||||||
|
module.exports = function(s,config,lang,app,io){
|
||||||
|
s.schedules = {}
|
||||||
|
//Get all Schedules
|
||||||
|
s.getAllSchedules = function(callback){
|
||||||
|
s.schedules = {}
|
||||||
|
s.sqlQuery('SELECT * FROM Schedules',function(err,rows){
|
||||||
|
rows.forEach(function(schedule){
|
||||||
|
s.updateSchedule(schedule)
|
||||||
|
})
|
||||||
|
if(callback)callback()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//update schedule
|
||||||
|
s.updateSchedule = function(row){
|
||||||
|
var schedule = Object.assign(row,{})
|
||||||
|
if(!s.schedules[schedule.ke])s.schedules[schedule.ke] = {}
|
||||||
|
s.checkDetails(schedule)
|
||||||
|
if(!s.schedules[schedule.ke][schedule.name]){
|
||||||
|
s.schedules[schedule.ke][schedule.name] = schedule
|
||||||
|
}else{
|
||||||
|
s.schedules[schedule.ke][schedule.name] = Object.assign(s.schedules[schedule.ke][schedule.name],schedule)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//check time in schedule
|
||||||
|
s.checkTimeAgainstSchedule = function(start,end,callback){
|
||||||
|
try{
|
||||||
|
if(
|
||||||
|
start
|
||||||
|
){
|
||||||
|
var checkStartTime = new Date()
|
||||||
|
var startSplit = start.split(':')
|
||||||
|
var startHour = parseInt(startSplit[0])
|
||||||
|
var startMin = parseInt(startSplit[1])
|
||||||
|
checkStartTime.setHours(startHour)
|
||||||
|
checkStartTime.setMinutes(startMin)
|
||||||
|
if(end){
|
||||||
|
var checkEndTime = new Date()
|
||||||
|
var endSplit = end.split(':')
|
||||||
|
var endHour = parseInt(endSplit[0])
|
||||||
|
var endMin = parseInt(endSplit[1])
|
||||||
|
checkEndTime.setHours(endHour)
|
||||||
|
checkEndTime.setMinutes(endMin)
|
||||||
|
}
|
||||||
|
var currentDate = new Date()
|
||||||
|
if(
|
||||||
|
(
|
||||||
|
currentDate >= checkStartTime &&
|
||||||
|
currentDate <= checkEndTime
|
||||||
|
) ||
|
||||||
|
currentDate >= checkStartTime && !end
|
||||||
|
){
|
||||||
|
callback()
|
||||||
|
}else{
|
||||||
|
callback({
|
||||||
|
currentDate : currentDate,
|
||||||
|
startTime : checkStartTime,
|
||||||
|
endTime : checkEndTime
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}catch(err){
|
||||||
|
console.log(err)
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//check all Schedules
|
||||||
|
s.checkSchedules = function(v,callback){
|
||||||
|
var groupKeys = Object.keys(s.schedules)
|
||||||
|
groupKeys.forEach(function(key){
|
||||||
|
var scheduleNames = Object.keys(s.schedules[key])
|
||||||
|
scheduleNames.forEach(function(name){
|
||||||
|
var schedule = s.schedules[key][name]
|
||||||
|
if(!schedule.active && schedule.enabled === 1 && schedule.start && schedule.details.monitorStates){
|
||||||
|
s.checkTimeAgainstSchedule(schedule.start,schedule.end,function(err){
|
||||||
|
if(!err){
|
||||||
|
schedule.active = true
|
||||||
|
var monitorStates = schedule.details.monitorStates
|
||||||
|
monitorStates.forEach(function(stateName){
|
||||||
|
s.activateMonitorStates(key,stateName,{
|
||||||
|
ke: key,
|
||||||
|
uid: 'System',
|
||||||
|
details: {},
|
||||||
|
permissions: {},
|
||||||
|
lang: lang
|
||||||
|
},function(endData){
|
||||||
|
// console.log(endData)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
schedule.active = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//
|
||||||
|
s.findSchedule = function(groupKey,name,callback){
|
||||||
|
//presetQueryVals = [ke, type, name]
|
||||||
|
s.sqlQuery("SELECT * FROM Schedules WHERE ke=? AND name=? LIMIT 1",[groupKey,name],function(err,schedules){
|
||||||
|
var schedule
|
||||||
|
var notFound = false
|
||||||
|
if(schedules && schedules[0]){
|
||||||
|
schedule = schedules[0]
|
||||||
|
s.checkDetails(schedule)
|
||||||
|
}else{
|
||||||
|
notFound = true
|
||||||
|
}
|
||||||
|
callback(notFound,schedule)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//
|
||||||
|
var onProcessReady = function(){
|
||||||
|
s.getAllSchedules(function(){
|
||||||
|
s.checkSchedules()
|
||||||
|
})
|
||||||
|
setInterval(function(){
|
||||||
|
s.checkSchedules()
|
||||||
|
},1000 * 60 * 5)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* WebServerPath : API : Update Schedule
|
||||||
|
*/
|
||||||
|
app.all([
|
||||||
|
config.webPaths.apiPrefix+':auth/schedule/:ke',
|
||||||
|
config.webPaths.adminApiPrefix+':auth/schedule/:ke',
|
||||||
|
config.webPaths.apiPrefix+':auth/schedule/:ke/:name',
|
||||||
|
config.webPaths.adminApiPrefix+':auth/schedule/:ke/:name',
|
||||||
|
],function (req,res){
|
||||||
|
s.auth(req.params,function(user){
|
||||||
|
var endData = {
|
||||||
|
ok : false
|
||||||
|
}
|
||||||
|
if(user.details.sub){
|
||||||
|
endData.msg = user.lang['Not Permitted']
|
||||||
|
s.closeJsonResponse(res,endData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var theQuery = "SELECT * FROM Schedules WHERE ke=?"
|
||||||
|
var theQueryValues = [req.params.ke]
|
||||||
|
if(req.params.name){
|
||||||
|
theQuery += ' AND name=?'
|
||||||
|
theQueryValues.push(req.params.name)
|
||||||
|
}
|
||||||
|
s.sqlQuery(theQuery,theQueryValues,function(err,schedules){
|
||||||
|
if(schedules && schedules[0]){
|
||||||
|
endData.ok = true
|
||||||
|
schedules.forEach(function(schedule){
|
||||||
|
s.checkDetails(schedule)
|
||||||
|
})
|
||||||
|
endData.schedules = schedules
|
||||||
|
}else{
|
||||||
|
endData.msg = user.lang['Not Found']
|
||||||
|
}
|
||||||
|
s.closeJsonResponse(res,endData)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
/**
|
||||||
|
* WebServerPath : API : Update Schedule
|
||||||
|
*/
|
||||||
|
app.all([
|
||||||
|
config.webPaths.apiPrefix+':auth/schedule/:ke/:name/:action',
|
||||||
|
config.webPaths.adminApiPrefix+':auth/schedule/:ke/:name/:action'
|
||||||
|
],function (req,res){
|
||||||
|
s.auth(req.params,function(user){
|
||||||
|
var endData = {
|
||||||
|
ok : false
|
||||||
|
}
|
||||||
|
if(user.details.sub){
|
||||||
|
endData.msg = user.lang['Not Permitted']
|
||||||
|
s.closeJsonResponse(res,endData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch(req.params.action){
|
||||||
|
case'insert':case'edit':
|
||||||
|
var form = s.getPostData(req)
|
||||||
|
s.checkDetails(form)
|
||||||
|
if(!form || !form.details){
|
||||||
|
endData.msg = user.lang['Form Data Not Found']
|
||||||
|
s.closeJsonResponse(res,endData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
form.enabled = parseInt(form.enabled) || 1;
|
||||||
|
s.findSchedule(req.params.ke,req.params.name,function(notFound,preset){
|
||||||
|
if(notFound === true){
|
||||||
|
endData.msg = lang["Inserted Schedule Configuration"]
|
||||||
|
var insertData = {
|
||||||
|
ke: req.params.ke,
|
||||||
|
name: req.params.name,
|
||||||
|
details: s.stringJSON(form.details),
|
||||||
|
start: form.start,
|
||||||
|
end: form.end,
|
||||||
|
enabled: form.enabled
|
||||||
|
}
|
||||||
|
s.sqlQuery('INSERT INTO Schedules ('+Object.keys(insertData).join(',')+') VALUES (?,?,?,?,?,?)',Object.values(insertData))
|
||||||
|
s.tx({
|
||||||
|
f: 'add_schedule',
|
||||||
|
insertData: insertData,
|
||||||
|
ke: req.params.ke,
|
||||||
|
name: req.params.name
|
||||||
|
},'GRP_'+req.params.ke)
|
||||||
|
}else{
|
||||||
|
endData.msg = lang["Edited Schedule Configuration"]
|
||||||
|
var insertData = {
|
||||||
|
details: s.stringJSON(form.details),
|
||||||
|
start: form.start,
|
||||||
|
end: form.end,
|
||||||
|
enabled: form.enabled,
|
||||||
|
ke: req.params.ke,
|
||||||
|
name: req.params.name
|
||||||
|
}
|
||||||
|
s.sqlQuery('UPDATE Schedules SET details=?,start=?,end=?,enabled=? WHERE ke=? AND name=?',Object.values(insertData))
|
||||||
|
s.tx({
|
||||||
|
f: 'edit_schedule',
|
||||||
|
insertData: insertData,
|
||||||
|
ke: req.params.ke,
|
||||||
|
name: req.params.name
|
||||||
|
},'GRP_'+req.params.ke)
|
||||||
|
}
|
||||||
|
s.updateSchedule({
|
||||||
|
ke: req.params.ke,
|
||||||
|
name: req.params.name,
|
||||||
|
details: s.stringJSON(form.details),
|
||||||
|
start: form.start,
|
||||||
|
end: form.end,
|
||||||
|
enabled: form.enabled
|
||||||
|
})
|
||||||
|
endData.ok = true
|
||||||
|
s.closeJsonResponse(res,endData)
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case'delete':
|
||||||
|
s.findSchedule(req.params.ke,req.params.name,function(notFound,schedule){
|
||||||
|
if(notFound === true){
|
||||||
|
endData.msg = user.lang['Schedule Configuration Not Found']
|
||||||
|
s.closeJsonResponse(res,endData)
|
||||||
|
}else{
|
||||||
|
s.sqlQuery('DELETE FROM Schedules WHERE ke=? AND name=?',[req.params.ke,req.params.name],function(err){
|
||||||
|
if(!err){
|
||||||
|
endData.msg = lang["Deleted Schedule Configuration"]
|
||||||
|
endData.ok = true
|
||||||
|
if(s.schedules[schedule.ke])delete(s.schedules[schedule.ke][schedule.name])
|
||||||
|
}
|
||||||
|
s.closeJsonResponse(res,endData)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
//bind events
|
||||||
|
s.onProcessReady(onProcessReady)
|
||||||
|
}
|
|
@ -1365,7 +1365,7 @@ module.exports = function(s,config,lang,io){
|
||||||
if(cn.cron){
|
if(cn.cron){
|
||||||
delete(s.cron);
|
delete(s.cron);
|
||||||
}
|
}
|
||||||
if(cn.ocv){
|
if(cn.ocv && s.ocv){
|
||||||
s.tx({f:'detector_unplugged',plug:s.ocv.plug},'CPU')
|
s.tx({f:'detector_unplugged',plug:s.ocv.plug},'CPU')
|
||||||
delete(s.ocv);
|
delete(s.ocv);
|
||||||
delete(s.api[cn.id])
|
delete(s.api[cn.id])
|
||||||
|
|
10
libs/sql.js
10
libs/sql.js
|
@ -10,6 +10,12 @@ module.exports = function(s,config){
|
||||||
if(s.databaseOptions.client.indexOf('sqlite')>-1){
|
if(s.databaseOptions.client.indexOf('sqlite')>-1){
|
||||||
s.databaseOptions.client = 'sqlite3';
|
s.databaseOptions.client = 'sqlite3';
|
||||||
s.databaseOptions.useNullAsDefault = true;
|
s.databaseOptions.useNullAsDefault = true;
|
||||||
|
try{
|
||||||
|
require('sqlite3')
|
||||||
|
}catch(err){
|
||||||
|
console.log('Installing SQlite3 Module...')
|
||||||
|
require('child_process').execSync('npm install sqlite3 --unsafe-perm')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(s.databaseOptions.client === 'sqlite3' && s.databaseOptions.connection.filename === undefined){
|
if(s.databaseOptions.client === 'sqlite3' && s.databaseOptions.connection.filename === undefined){
|
||||||
s.databaseOptions.connection.filename = s.mainDirectory+"/shinobi.sqlite"
|
s.databaseOptions.connection.filename = s.mainDirectory+"/shinobi.sqlite"
|
||||||
|
@ -99,6 +105,10 @@ module.exports = function(s,config){
|
||||||
},true)
|
},true)
|
||||||
}
|
}
|
||||||
},true)
|
},true)
|
||||||
|
//add Schedules table, will remove in future
|
||||||
|
s.sqlQuery("CREATE TABLE IF NOT EXISTS `Schedules` (`ke` varchar(50) DEFAULT NULL,`name` text,`details` text,`start` varchar(10) DEFAULT NULL,`end` varchar(10) DEFAULT NULL,`enabled` int(1) NOT NULL DEFAULT '1')" + mySQLtail + ';',[],function(err){
|
||||||
|
if(err)console.error(err)
|
||||||
|
},true)
|
||||||
//add Cloud Videos table, will remove in future
|
//add Cloud Videos table, will remove in future
|
||||||
s.sqlQuery('CREATE TABLE IF NOT EXISTS `Cloud Videos` (`mid` varchar(50) NOT NULL,`ke` varchar(50) DEFAULT NULL,`href` text NOT NULL,`size` float DEFAULT NULL,`time` timestamp NULL DEFAULT NULL,`end` timestamp NULL DEFAULT NULL,`status` int(1) DEFAULT \'0\',`details` text)' + mySQLtail + ';',[],function(err){
|
s.sqlQuery('CREATE TABLE IF NOT EXISTS `Cloud Videos` (`mid` varchar(50) NOT NULL,`ke` varchar(50) DEFAULT NULL,`href` text NOT NULL,`size` float DEFAULT NULL,`time` timestamp NULL DEFAULT NULL,`end` timestamp NULL DEFAULT NULL,`status` int(1) DEFAULT \'0\',`details` text)' + mySQLtail + ';',[],function(err){
|
||||||
if(err)console.error(err)
|
if(err)console.error(err)
|
||||||
|
|
|
@ -4,16 +4,15 @@ var moment = require('moment');
|
||||||
var crypto = require('crypto');
|
var crypto = require('crypto');
|
||||||
var exec = require('child_process').exec;
|
var exec = require('child_process').exec;
|
||||||
var execSync = require('child_process').execSync;
|
var execSync = require('child_process').execSync;
|
||||||
module.exports = function(s,config,lang,io,processReady){
|
module.exports = function(s,config,lang,io,){
|
||||||
console.log('FFmpeg version : '+s.ffmpegVersion)
|
console.log('FFmpeg version : '+s.ffmpegVersion)
|
||||||
console.log('Node.js version : '+execSync("node -v"))
|
console.log('Node.js version : '+execSync("node -v"))
|
||||||
s.processReady = function(){
|
s.processReady = function(){
|
||||||
s.systemLog(lang.startUpText5)
|
s.systemLog(lang.startUpText5)
|
||||||
process.send('ready')
|
|
||||||
s.onProcessReadyExtensions.forEach(function(extender){
|
s.onProcessReadyExtensions.forEach(function(extender){
|
||||||
extender(true)
|
extender(true)
|
||||||
})
|
})
|
||||||
if(processReady)processReady()
|
process.send('ready')
|
||||||
}
|
}
|
||||||
var loadedAccounts = []
|
var loadedAccounts = []
|
||||||
var loadMonitors = function(callback){
|
var loadMonitors = function(callback){
|
||||||
|
|
14
libs/user.js
14
libs/user.js
|
@ -308,4 +308,18 @@ module.exports = function(s,config){
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
s.findPreset = function(presetQueryVals,callback){
|
||||||
|
//presetQueryVals = [ke, type, name]
|
||||||
|
s.sqlQuery("SELECT * FROM Presets WHERE ke=? AND type=? AND name=? LIMIT 1",presetQueryVals,function(err,presets){
|
||||||
|
var preset
|
||||||
|
var notFound = false
|
||||||
|
if(presets && presets[0]){
|
||||||
|
preset = presets[0]
|
||||||
|
s.checkDetails(preset)
|
||||||
|
}else{
|
||||||
|
notFound = true
|
||||||
|
}
|
||||||
|
callback(notFound,preset)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -419,19 +419,7 @@ module.exports = function(s,config,lang,app){
|
||||||
s.closeJsonResponse(res,endData)
|
s.closeJsonResponse(res,endData)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var findPreset = function(callback){
|
var presetQueryVals = [req.params.ke,'monitorStates',req.params.stateName]
|
||||||
s.sqlQuery("SELECT * FROM Presets WHERE ke=? AND type=? AND name=? LIMIT 1",[req.params.ke,'monitorStates',req.params.stateName],function(err,presets){
|
|
||||||
var preset
|
|
||||||
var notFound = false
|
|
||||||
if(presets && presets[0]){
|
|
||||||
preset = presets[0]
|
|
||||||
s.checkDetails(preset)
|
|
||||||
}else{
|
|
||||||
notFound = true
|
|
||||||
}
|
|
||||||
callback(notFound,preset)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
switch(req.params.action){
|
switch(req.params.action){
|
||||||
case'insert':case'edit':
|
case'insert':case'edit':
|
||||||
var form = s.getPostData(req)
|
var form = s.getPostData(req)
|
||||||
|
@ -441,7 +429,7 @@ module.exports = function(s,config,lang,app){
|
||||||
s.closeJsonResponse(res,endData)
|
s.closeJsonResponse(res,endData)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
findPreset(function(notFound,preset){
|
s.findPreset(presetQueryVals,function(notFound,preset){
|
||||||
if(notFound === true){
|
if(notFound === true){
|
||||||
endData.msg = lang["Inserted State Configuration"]
|
endData.msg = lang["Inserted State Configuration"]
|
||||||
var details = {
|
var details = {
|
||||||
|
@ -478,7 +466,7 @@ module.exports = function(s,config,lang,app){
|
||||||
})
|
})
|
||||||
break;
|
break;
|
||||||
case'delete':
|
case'delete':
|
||||||
findPreset(function(notFound,preset){
|
s.findPreset(presetQueryVals,function(notFound,preset){
|
||||||
if(notFound === true){
|
if(notFound === true){
|
||||||
endData.msg = user.lang['State Configuration Not Found']
|
endData.msg = user.lang['State Configuration Not Found']
|
||||||
s.closeJsonResponse(res,endData)
|
s.closeJsonResponse(res,endData)
|
||||||
|
@ -494,43 +482,8 @@ module.exports = function(s,config,lang,app){
|
||||||
})
|
})
|
||||||
break;
|
break;
|
||||||
default://change monitors according to state
|
default://change monitors according to state
|
||||||
findPreset(function(notFound,preset){
|
s.activateMonitorStates(req.params.ke,req.params.stateName,user,function(endData){
|
||||||
if(notFound === false){
|
s.closeJsonResponse(res,endData)
|
||||||
var sqlQuery = 'SELECT * FROM Monitors WHERE ke=? AND '
|
|
||||||
var monitorQuery = []
|
|
||||||
var sqlQueryValues = [req.params.ke]
|
|
||||||
var monitorPresets = {}
|
|
||||||
preset.details.monitors.forEach(function(monitor){
|
|
||||||
monitorQuery.push('mid=?')
|
|
||||||
sqlQueryValues.push(monitor.mid)
|
|
||||||
monitorPresets[monitor.mid] = monitor
|
|
||||||
})
|
|
||||||
sqlQuery += '('+monitorQuery.join(' OR ')+')'
|
|
||||||
s.sqlQuery(sqlQuery,sqlQueryValues,function(err,monitors){
|
|
||||||
if(monitors && monitors[0]){
|
|
||||||
monitors.forEach(function(monitor){
|
|
||||||
s.checkDetails(monitor)
|
|
||||||
s.checkDetails(monitorPresets[monitor.mid])
|
|
||||||
var monitorPreset = monitorPresets[monitor.mid]
|
|
||||||
monitorPreset.details = Object.assign(monitor.details,monitorPreset.details)
|
|
||||||
monitor = s.cleanMonitorObjectForDatabase(Object.assign(monitor,monitorPreset))
|
|
||||||
monitor.details = JSON.stringify(monitor.details)
|
|
||||||
s.addOrEditMonitor(Object.assign(monitor,{}),function(err,endData){
|
|
||||||
|
|
||||||
},user)
|
|
||||||
})
|
|
||||||
endData.ok = true
|
|
||||||
s.tx({f:'change_group_state',ke:req.params.ke,name:req.params.stateName},'GRP_'+req.params.ke)
|
|
||||||
s.closeJsonResponse(res,endData)
|
|
||||||
}else{
|
|
||||||
endData.msg = user.lang['State Configuration has no monitors associated']
|
|
||||||
s.closeJsonResponse(res,endData)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
endData.msg = user.lang['State Configuration Not Found']
|
|
||||||
s.closeJsonResponse(res,endData)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
29
package.json
29
package.json
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "shinobi",
|
"name": "shinobi",
|
||||||
"productName": "Shinobi",
|
"productName": "Shinobi",
|
||||||
"version": "1.0.38",
|
"version": "2.0.0",
|
||||||
"description": "CCTV and NVR in Node.js",
|
"description": "CCTV and NVR in Node.js",
|
||||||
"main": "camera.js",
|
"main": "camera.js",
|
||||||
"bin": "camera.js",
|
"bin": "camera.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node test.js",
|
"test": "node camera.js test",
|
||||||
"start": "chmod +x INSTALL/start.sh && INSTALL/start.sh"
|
"start": "chmod +x INSTALL/start.sh && INSTALL/start.sh"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -19,30 +19,33 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://gitlab.com/Shinobi-Systems/Shinobi#readme",
|
"homepage": "https://gitlab.com/Shinobi-Systems/Shinobi#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"aws-sdk": "^2.279.1",
|
||||||
|
"backblaze-b2": "^1.0.4",
|
||||||
"body-parser": "^1.15.2",
|
"body-parser": "^1.15.2",
|
||||||
"circular-json": "0.3.1",
|
"circular-json": "0.3.1",
|
||||||
"connection-tester": "^0.1.1",
|
"connection-tester": "^0.1.1",
|
||||||
"mp4frag": "^0.0.22",
|
"discord.js": "^11.3.2",
|
||||||
"ejs": "^2.5.5",
|
"ejs": "^2.5.5",
|
||||||
"express": "^4.14.0",
|
"express": "^4.14.0",
|
||||||
|
"http-proxy": "^1.17.0",
|
||||||
"jsonfile": "^3.0.1",
|
"jsonfile": "^3.0.1",
|
||||||
"moment": "^2.17.0",
|
|
||||||
"mysql": "^2.12.0",
|
|
||||||
"knex": "^0.14.2",
|
"knex": "^0.14.2",
|
||||||
"aws-sdk": "^2.279.1",
|
"ldapauth-fork": "^4.0.2",
|
||||||
"pam-diff": "^0.10.2",
|
"moment": "^2.17.0",
|
||||||
"pipe2pam": "^0.6.2",
|
"mp4frag": "^0.0.22",
|
||||||
"nodemailer": "^4.0.1",
|
"mysql": "^2.12.0",
|
||||||
"node-onvif": "^0.1.4",
|
"node-onvif": "^0.1.4",
|
||||||
|
"nodemailer": "^4.0.1",
|
||||||
|
"pam-diff": "^0.10.2",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
|
"pipe2pam": "^0.6.2",
|
||||||
"request": "^2.79.0",
|
"request": "^2.79.0",
|
||||||
"socket.io": "^1.7.1",
|
"socket.io": "^1.7.1",
|
||||||
"socket.io-client": "^1.7.2",
|
"socket.io-client": "^1.7.2",
|
||||||
"http-proxy": "^1.17.0",
|
"sqlite3": "^4.0.4",
|
||||||
"webdav-fs": "^1.11.0",
|
"webdav-fs": "^1.11.0",
|
||||||
"discord.js": "^11.3.2",
|
"sat": "^0.7.1",
|
||||||
"backblaze-b2": "^1.0.4",
|
"shinobi-sound-detection": "^0.1.7"
|
||||||
"ldapauth-fork": "^4.0.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {}
|
"devDependencies": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,6 +125,18 @@ CREATE TABLE IF NOT EXISTS `Files` (
|
||||||
`status` int(1) NOT NULL DEFAULT '0'
|
`status` int(1) NOT NULL DEFAULT '0'
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
ALTER TABLE `Files` ADD COLUMN `time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `status`;
|
ALTER TABLE `Files` ADD COLUMN `time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `status`;
|
||||||
|
|
||||||
|
-- Data exporting was unselected.
|
||||||
|
-- Dumping structure for table ccio.Schedules
|
||||||
|
CREATE TABLE IF NOT EXISTS `Schedules` (
|
||||||
|
`ke` varchar(50) DEFAULT NULL,
|
||||||
|
`name` text,
|
||||||
|
`details` text,
|
||||||
|
`start` varchar(10) DEFAULT NULL,
|
||||||
|
`end` varchar(10) DEFAULT NULL,
|
||||||
|
`enabled` int(1) NOT NULL DEFAULT '1'
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
-- Data exporting was unselected.
|
-- Data exporting was unselected.
|
||||||
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
|
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
|
||||||
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
|
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
|
||||||
|
|
|
@ -12,7 +12,7 @@ processArgv.forEach(function(val) {
|
||||||
var theSplit = val.split('=');
|
var theSplit = val.split('=');
|
||||||
var index = theSplit[0];
|
var index = theSplit[0];
|
||||||
var value = theSplit[1];
|
var value = theSplit[1];
|
||||||
if(index === 'addToConfig'){
|
if(index.indexOf('addToConfig') > -1){
|
||||||
try{
|
try{
|
||||||
value = JSON.parse(value)
|
value = JSON.parse(value)
|
||||||
config = Object.assign(config,value)
|
config = Object.assign(config,value)
|
||||||
|
|
|
@ -1065,14 +1065,6 @@
|
||||||
</select></div>
|
</select></div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group h_det_pam_input h_det_pam_1">
|
|
||||||
<label><div><span><%-lang['Show Matrices']%></span></div>
|
|
||||||
<div><select class="form-control" detail="detector_show_matrix">
|
|
||||||
<option value="0" selected><%-lang.No%></option>
|
|
||||||
<option value="1"><%-lang.Yes%></option>
|
|
||||||
</select></div>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label><div><span><%-lang['Indifference']%></span></div>
|
<label><div><span><%-lang['Indifference']%></span></div>
|
||||||
<div><input class="form-control" detail="detector_sensitivity" placeholder="0.5"></div>
|
<div><input class="form-control" detail="detector_sensitivity" placeholder="0.5"></div>
|
||||||
|
@ -1159,6 +1151,14 @@
|
||||||
</select></div>
|
</select></div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label><div><span><%-lang['Require Object to be in Region']%></span></div>
|
||||||
|
<div><select class="form-control" detail="detector_obj_region">
|
||||||
|
<option value="0" selected><%-lang.No%></option>
|
||||||
|
<option value="1"><%-lang.Yes%></option>
|
||||||
|
</select></div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label><div><span><%-lang['Check for Motion First']%></span></div>
|
<label><div><span><%-lang['Check for Motion First']%></span></div>
|
||||||
<div><select class="form-control" detail="detector_use_motion" selector="h_det_mot_fir">
|
<div><select class="form-control" detail="detector_use_motion" selector="h_det_mot_fir">
|
||||||
|
@ -1294,6 +1294,29 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Start of Audio Detection -->
|
||||||
|
<div class="form-group-group orange" section id="monSectionAudioDetector">
|
||||||
|
<h4><%-lang['Audio Detector']%></h4>
|
||||||
|
<div class="form-group">
|
||||||
|
<label><div><span><%-lang['Enabled']%></span></div>
|
||||||
|
<div><select class="form-control" detail="detector_audio">
|
||||||
|
<option value="0" selected><%-lang.No%></option>
|
||||||
|
<option value="1"><%-lang.Yes%></option>
|
||||||
|
</select></div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label><div><span><%-lang['Minimum dB']%></span></div>
|
||||||
|
<div><input class="form-control" detail="detector_audio_min_db" placeholder="5"></div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label><div><span><%-lang['Maximum dB']%></span></div>
|
||||||
|
<div><input class="form-control" detail="detector_audio_max_db" placeholder=""></div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- END of Audio Detection --/>
|
||||||
<!-- END of Motion -->
|
<!-- END of Motion -->
|
||||||
<div class="form-group-group blue" section id="monSectionControl">
|
<div class="form-group-group blue" section id="monSectionControl">
|
||||||
<h4><%-lang['Control']%></h4>
|
<h4><%-lang['Control']%></h4>
|
||||||
|
|
Loading…
Reference in New Issue