2020-12-04 04:38:37 +00:00
// relies on https://gitlab.com/Shinobi-Systems/shinobi-onvif
const {
mergeDeep
} = require ( '../common.js' )
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 ) => {
return new Promise ( ( resolve , reject ) => {
const onvifDevice = onvifOptions . device
var response = { ok : false }
var errorMessage = function ( msg , error ) {
response . ok = false
response . msg = msg
response . error = error
resolve ( response )
}
var actionCallback = function ( onvifActionResponse ) {
response . ok = true
if ( onvifActionResponse . data ) {
response . responseFromDevice = onvifActionResponse . data
} else {
response . responseFromDevice = onvifActionResponse
}
if ( onvifActionResponse . soap ) response . soap = onvifActionResponse . soap
resolve ( response )
}
var isEmpty = function ( obj ) {
for ( var key in obj ) {
if ( obj . hasOwnProperty ( key ) )
return false ;
}
return true ;
}
var completeAction = function ( command ) {
if ( command && command . then ) {
command . then ( actionCallback ) . catch ( function ( error ) {
errorMessage ( 'Device Action responded with an error' , error )
} )
} else if ( command ) {
response . ok = true
response . repsonseFromDevice = command
resolve ( response )
} else {
response . error = 'Big Errors, Please report it to Shinobi Development'
resolve ( response )
}
}
var action
if ( onvifOptions . service ) {
if ( onvifDevice . services [ onvifOptions . service ] === undefined ) {
return errorMessage ( 'This is not an available service. Please use one of the following : ' + Object . keys ( onvifDevice . services ) . join ( ', ' ) )
}
if ( onvifDevice . services [ onvifOptions . service ] === null ) {
return errorMessage ( 'This service is not activated. Maybe you are not connected through ONVIF. You can test by attempting to use the "Control" feature with ONVIF in Shinobi.' )
}
action = onvifDevice . services [ onvifOptions . service ] [ onvifOptions . action ]
} else {
action = onvifDevice [ onvifOptions . action ]
}
if ( ! action || typeof action !== 'function' ) {
errorMessage ( onvifOptions . action + ' is not an available ONVIF function. See https://github.com/futomi/node-onvif for functions.' )
} else {
var argNames = s . getFunctionParamNames ( action )
var options
var command
if ( argNames [ 0 ] === 'options' || argNames [ 0 ] === 'params' ) {
options = replaceDynamicInOptions ( onvifDevice , onvifOptions . options || { } )
response . options = options
}
if ( onvifOptions . service ) {
command = onvifDevice . services [ onvifOptions . service ] [ onvifOptions . action ] ( options )
} else {
command = onvifDevice [ onvifOptions . action ] ( options )
}
completeAction ( command )
}
} )
}
const getDeviceInformation = async ( onvifDevice , options ) => {
// const options = {
// protocols: true,
// networkInterface: true,
// gateway: true,
// dns: true,
// ntp: true,
// }
const response = {
ok : true ,
}
try {
if ( options . all || options . protocols ) {
response . protocols = ( await onvifDevice . services . device . getNetworkProtocols ( ) ) . data . GetNetworkProtocolsResponse . NetworkProtocols
}
if ( options . all || options . networkInterface ) {
response . networkInterface = ( await onvifDevice . services . device . getNetworkInterfaces ( ) ) . data . GetNetworkInterfacesResponse . NetworkInterfaces
}
if ( options . all || options . gatewayAddress ) {
response . gateway = ( await onvifDevice . services . device . getNetworkDefaultGateway ( ) ) . data . GetNetworkDefaultGatewayResponse . NetworkGateway . IPv4Address
}
if ( options . all || options . dns ) {
response . dns = ( await onvifDevice . services . device . getDNS ( ) ) . data . GetDNSResponse . DNSInformation
}
if ( options . all || options . ntp ) {
response . ntp = ( await onvifDevice . services . device . getNTP ( ) ) . data . GetNTPResponse . NTPInformation
}
if ( options . all || options . date ) {
response . date = ( await onvifDevice . services . device . getSystemDateAndTime ( ) ) . data . GetSystemDateAndTimeResponse . SystemDateAndTime
}
if ( options . all || options . users ) {
response . users = ( await onvifDevice . services . device . getUsers ( ) ) . data . GetUsersResponse . User
}
if ( options . all || options . hostname ) {
response . hostname = ( await onvifDevice . services . device . getHostname ( ) ) . data . GetHostnameResponse . HostnameInformation . Name
}
if ( options . all || options . discoveryMode ) {
response . discoveryMode = ( await onvifDevice . services . device . getDiscoveryMode ( ) ) . data . GetDiscoveryModeResponse . DiscoveryMode
}
if ( options . all || options . videoEncoders ) {
response . videoEncoders = ( await onvifDevice . services . media . getVideoEncoderConfigurations ( ) ) . data . GetVideoEncoderConfigurationsResponse . Configurations
}
if ( options . all || options . videoEncoderOptions ) {
response . videoEncoderOptions = ( await runOnvifMethod ( {
device : onvifDevice ,
action : 'getVideoEncoderConfigurationOptions' ,
service : 'media' ,
options : { }
} ) ) . responseFromDevice . GetVideoEncoderConfigurationOptionsResponse . Options
}
if ( options . all || options . imagingSettings ) {
const imagingSettings = ( await runOnvifMethod ( {
device : onvifDevice ,
action : 'getImagingSettings' ,
2020-12-04 17:41:49 +00:00
service : 'imaging' ,
2020-12-04 04:38:37 +00:00
options : { "ConfigurationToken" : "__CURRENT_TOKEN" }
} ) ) ;
2020-12-04 17:41:49 +00:00
response . imagingSettings = imagingSettings . responseFromDevice ? imagingSettings . responseFromDevice . GetImagingSettingsResponse . ImagingSettings : imagingSettings
2020-12-04 04:38:37 +00:00
}
} catch ( err ) {
response . ok = false
2020-12-05 07:11:13 +00:00
response . error = err . stack . toString ( ) . toString ( )
2020-12-04 04:38:37 +00:00
s . debugLog ( err )
2021-11-24 05:05:56 +00:00
s . debugLog ( onvifDevice )
2020-12-04 04:38:37 +00:00
}
return response
}
2020-12-05 07:11:13 +00:00
const setProtocols = async ( onvifDevice , saveSet ) => {
2020-12-04 04:38:37 +00:00
// const saveSet = {
// "HTTP": "80",
// "RTSP": "554",
// }
const response = {
ok : false
}
try {
const saveKeys = Object . keys ( saveSet )
2020-12-05 07:11:13 +00:00
const protocols = ( await getDeviceInformation ( onvifDevice , { protocols : true } ) ) . protocols
2020-12-04 04:38:37 +00:00
protocols . forEach ( ( item ) => {
saveKeys . forEach ( ( key ) => {
if ( item . Name === key . toUpperCase ( ) ) {
2020-12-05 07:11:13 +00:00
const port = saveSet [ key ] && ! isNaN ( saveSet [ key ] ) ? parseInt ( saveSet [ key ] ) : item . Name === 'RTSP' ? 554 : 80
console . log ( 'PORT' , port )
2020-12-04 04:38:37 +00:00
item . Port = port
item . Enabled = true
}
} )
} )
2020-12-05 07:11:13 +00:00
console . log ( 'protocols' , protocols )
2020-12-04 04:38:37 +00:00
const onvifResponse = await onvifDevice . services . device . setNetworkProtocols ( {
NetworkProtocols : protocols
} )
response . ok = true
response . onvifResponse = onvifResponse
} catch ( err ) {
2020-12-05 07:11:13 +00:00
response . error = err . stack . toString ( )
2020-12-04 04:38:37 +00:00
}
return response
}
const setNetworkInterface = async ( onvifDevice , options ) => {
// const options = {
// interface: 'eth0',
// ipv4: '10.1.103.158',
// dhcp: false,
// }
const response = {
ok : false
}
try {
2020-12-05 07:11:13 +00:00
const { networkInterface } = await getDeviceInformation ( onvifDevice , { networkInterface : true } )
const onvifParams = {
2020-12-04 04:38:37 +00:00
SetNetworkInterfaces : {
2020-12-05 07:11:13 +00:00
InterfaceToken : options . interface || networkInterface . $ . token ,
2020-12-04 04:38:37 +00:00
NetworkInterface : {
Enabled : true ,
IPv4 : {
Enabled : true ,
Manual : {
2020-12-05 07:11:13 +00:00
Address : options . ipv4 || networkInterface . IPv4 . Config . Manual . Address ,
2020-12-04 04:38:37 +00:00
PrefixLength : '24' ,
} ,
2020-12-05 07:11:13 +00:00
'DHCP' : options . dhcp === undefined || options . dhcp === null ? networkInterface . IPv4 . Config . DHCP === 'true' ? true : false : options . dhcp ,
2020-12-04 04:38:37 +00:00
}
}
}
2020-12-05 07:11:13 +00:00
}
const onvifResponse = await onvifDevice . services . device . setNetworkInterfaces ( onvifParams )
2020-12-04 04:38:37 +00:00
response . ok = true
response . onvifResponse = onvifResponse
} catch ( err ) {
2020-12-05 07:11:13 +00:00
response . error = err . stack . toString ( )
2020-12-04 04:38:37 +00:00
}
return response
}
const setGateway = async ( onvifDevice , options ) => {
// const options = {
// ipv4: '1.1.1.1,8.8.8.8',
// }
const response = {
ok : false
}
try {
2020-12-05 07:11:13 +00:00
const gatewayAddress = ( await getDeviceInformation ( onvifDevice , { gateway : true } ) ) . gateway
2020-12-04 04:38:37 +00:00
const onvifResponse = await onvifDevice . services . device . setNetworkDefaultGateway ( {
'NetworkGateway' : [
{ 'IPv4Address' : options . ipv4 || gatewayAddress }
]
} )
response . ok = true
response . onvifResponse = onvifResponse
} catch ( err ) {
2020-12-05 07:11:13 +00:00
response . error = err . stack . toString ( )
2020-12-04 04:38:37 +00:00
}
return response
}
const setDNS = async ( onvifDevice , options ) => {
2020-12-05 07:11:13 +00:00
options = Object . assign ( {
dns : '1.1.1.1,8.8.8.8' ,
searchDomain : 'localhost' ,
dhcp : false ,
} , options )
2020-12-04 04:38:37 +00:00
const response = {
ok : false
}
try {
const dnsArray = [ ]
const searchDomain = ( options . searchDomain || '' ) . split ( ',' )
const dnsList = ( options . dns || '1.1.1.1' ) . split ( ',' )
dnsList . forEach ( ( item ) => {
dnsArray . push ( {
Type : 'IPv4' ,
IPv4Address : item ,
} )
} )
2020-12-05 07:11:13 +00:00
const dnsInfo = ( await getDeviceInformation ( onvifDevice , { dns : true } ) ) . dns
2020-12-04 04:38:37 +00:00
const onvifResponse = await onvifDevice . services . device . setDNS ( {
'FromDHCP' : ! options . dhcp ? false : true ,
'SearchDomain' : searchDomain ,
'DNSManual' : dnsArray
} )
response . ok = true
response . onvifResponse = onvifResponse
} catch ( err ) {
2020-12-05 07:11:13 +00:00
response . error = err . stack . toString ( )
2020-12-04 04:38:37 +00:00
}
return response
}
const setNTP = async ( onvifDevice , options ) => {
// const options = {
// ipv4: '1.1.1.1,8.8.8.8',
// dhcp: false,
// }
const response = {
ok : false
}
try {
2020-12-05 07:11:13 +00:00
const ntpInfo = ( await getDeviceInformation ( onvifDevice , { ntp : true } ) ) . ntp
2020-12-04 04:38:37 +00:00
const ipv4 = options . ipv4 || ntpInfo . NTPManual . IPv4Address
const onvifResponse = await onvifDevice . services . device . setNTP ( {
FromDHCP : ! options . dhcp ? false : true ,
NTPManual : { 'Type' : "IPv4" , 'IPv4Address' : ipv4 }
} )
response . ok = true
response . onvifResponse = onvifResponse
} catch ( err ) {
2020-12-05 07:11:13 +00:00
response . error = err . stack . toString ( )
2020-12-04 04:38:37 +00:00
}
return response
}
const setHostname = async ( onvifDevice , options ) => {
// const options = {
// name: 'hostname',
// }
const response = {
ok : false
}
try {
2020-12-05 07:11:13 +00:00
const hostname = options . name || ( await getDeviceInformation ( onvifDevice , { hostname : true } ) ) . hostname
2020-12-04 04:38:37 +00:00
const onvifResponse = await onvifDevice . services . device . setHostname ( {
Name : hostname
} )
response . ok = true
response . onvifResponse = onvifResponse
} catch ( err ) {
2020-12-05 07:11:13 +00:00
response . error = err . stack . toString ( )
2020-12-04 04:38:37 +00:00
}
return response
}
const rebootCamera = async ( onvifDevice , options ) => {
const response = {
ok : false
}
try {
const onvifResponse = await onvifDevice . services . device . reboot ( )
response . ok = true
response . onvifResponse = onvifResponse
} catch ( err ) {
2020-12-05 07:11:13 +00:00
response . error = err . stack . toString ( )
2020-12-04 04:38:37 +00:00
}
return response
}
const setDateAndTime = async ( onvifDevice , options ) => {
// const options = {
2020-12-05 07:22:59 +00:00
// dateTimeType: 'ntp',
2020-12-04 04:38:37 +00:00
// daylightSavings: false,
2020-12-05 07:22:59 +00:00
// timezone: 'XXXX',
// utcDateTime: 'XXXX',
2020-12-04 04:38:37 +00:00
// }
const response = {
ok : false
}
try {
// const dateInfo = await onvifDevice.services.device.getSystemDateAndTime().GetSystemDateAndTimeResponse.SystemDateAndTime
const onvifResponse = await onvifDevice . services . device . setSystemDateAndTime ( {
2020-12-05 19:54:40 +00:00
DateTimeType : options . dateTimeType ,
2020-12-04 04:38:37 +00:00
DaylightSavings : ! options . daylightSavings ? false : true ,
2020-12-05 07:22:59 +00:00
// TimeZone: options.timezone,
UTCDateTime : new Date ( options . utcDateTime ) ,
2020-12-04 04:38:37 +00:00
} )
response . ok = true
response . onvifResponse = onvifResponse
} catch ( err ) {
2020-12-05 07:11:13 +00:00
response . error = err . stack . toString ( )
2020-12-04 04:38:37 +00:00
}
return response
}
const createUser = async ( onvifDevice , options ) => {
// const options = {
// name: 'user1',
// password: '123',
// level: 'Administrator' || 'Operator' || 'User',
// }
const response = {
ok : false
}
try {
const onvifResponse = await onvifDevice . services . device . createUsers ( {
'User' : [
{ 'Username' : options . name , 'Password' : options . password , 'UserLevel' : options . level }
]
} )
response . ok = true
response . onvifResponse = onvifResponse
} catch ( err ) {
2020-12-05 07:11:13 +00:00
response . error = err . stack . toString ( )
2020-12-04 04:38:37 +00:00
}
return response
}
const deleteUser = async ( onvifDevice , options ) => {
// const options = {
// name: 'user1',
// }
const response = {
ok : false
}
try {
const onvifResponse = await onvifDevice . services . device . deleteUsers ( {
'User' : [
{ 'Username' : options . name }
]
} )
response . ok = true
response . onvifResponse = onvifResponse
} catch ( err ) {
2020-12-05 07:11:13 +00:00
response . error = err . stack . toString ( )
2020-12-04 04:38:37 +00:00
}
return response
}
const validateEncoderOptions = ( chosenOptions , videoEncoderOptions ) => {
const resolutions = [ ]
const minQuality = parseInt ( videoEncoderOptions . QualityRange . Min ) || 1
const maxQuality = parseInt ( videoEncoderOptions . QualityRange . Max ) || 6
const quality = ! isNaN ( chosenOptions . Quality ) ? parseInt ( chosenOptions . Quality ) : 1
const minGovLength = parseInt ( videoEncoderOptions . H264 . GovLengthRange . Min ) || 0
const maxGovLength = parseInt ( videoEncoderOptions . H264 . GovLengthRange . Max ) || 100
const govLength = ! isNaN ( chosenOptions . H264 . GovLength ) ? parseInt ( chosenOptions . H264 . GovLength ) : 10
const minFrameRateLimit = parseInt ( videoEncoderOptions . H264 . FrameRateRange . Min ) || 1
const maxFrameRateLimit = parseInt ( videoEncoderOptions . H264 . FrameRateRange . Max ) || 30
const frameRateLimit = ! isNaN ( chosenOptions . RateControl . FrameRateLimit ) ? parseInt ( chosenOptions . RateControl . FrameRateLimit ) : 15
const minEncodingInterval = parseInt ( videoEncoderOptions . H264 . EncodingIntervalRange . Min ) || 1
const maxEncodingInterval = parseInt ( videoEncoderOptions . H264 . EncodingIntervalRange . Max ) || 30
const encodingInterval = ! isNaN ( chosenOptions . RateControl . EncodingInterval ) ? parseInt ( chosenOptions . RateControl . EncodingInterval ) : 1
videoEncoderOptions . H264 . ResolutionsAvailable . forEach ( ( resolution ) => {
resolutions . push ( ` ${ resolution . Width } x ${ resolution . Height } ` )
} )
2020-12-05 07:11:13 +00:00
if ( resolutions . indexOf ( ` ${ chosenOptions . Resolution . Width } x ${ chosenOptions . Resolution . Height } ` ) === - 1 ) {
chosenOptions . Resolution . Width = resolutions [ 0 ] . Width
chosenOptions . Resolution . Height = resolutions [ 0 ] . Height
2020-12-04 04:38:37 +00:00
}
if ( quality < minQuality || quality > maxQuality ) {
chosenOptions . Quality = 1
}
if ( govLength < minGovLength || govLength > maxGovLength ) {
chosenOptions . H264 . GovLength = 10
}
if ( frameRateLimit < minFrameRateLimit || frameRateLimit > maxFrameRateLimit ) {
chosenOptions . RateControl . FrameRateLimit = 15
}
if ( encodingInterval < minEncodingInterval || encodingInterval > maxEncodingInterval ) {
chosenOptions . RateControl . EncodingInterval = 1
}
}
const setVideoConfiguration = async ( onvifDevice , options ) => {
const response = {
ok : false
}
try {
const {
videoEncoders ,
videoEncoderOptions
} = await getDeviceInformation ( onvifDevice , {
videoEncoders : true ,
videoEncoderOptions : true
} )
const videoEncoderIndex = { }
videoEncoders . forEach ( ( encoder ) => { videoEncoderIndex [ encoder . $ . token ] = encoder } )
2020-12-05 07:11:13 +00:00
const chosenToken = ` ${ options . videoToken || videoEncoders [ 0 ] . $ . token } `
2020-12-04 04:38:37 +00:00
const videoEncoder = videoEncoderIndex [ chosenToken ] || { }
const onvifParams = mergeDeep ( videoEncoder , options , {
Multicast : {
2020-12-05 07:11:13 +00:00
AutoStart : ! options . Multicast || ! options . Multicast . AutoStart ? 'false' : 'true'
2020-12-04 04:38:37 +00:00
} ,
} )
const validatedEncoderOptions = validateEncoderOptions ( onvifParams , videoEncoderOptions )
const onvifResponse = await onvifDevice . services . media . setVideoEncoderConfiguration ( {
2020-12-05 07:11:13 +00:00
Configuration : onvifParams ,
ConfigurationToken : chosenToken
2020-12-04 04:38:37 +00:00
} )
response . ok = true
response . onvifResponse = onvifResponse
} catch ( err ) {
2020-12-05 07:11:13 +00:00
response . error = err . stack . toString ( )
2020-12-04 04:38:37 +00:00
}
return response
}
const setImagingSettings = async ( onvifDevice , options ) => {
const response = {
ok : false
}
try {
const { imagingSettings } = await getDeviceInformation ( onvifDevice , { imagingSettings : true } )
const onvifParams = mergeDeep ( imagingSettings , options )
const onvifResponse = await onvifDevice . services . imaging . setImagingSettings ( {
2020-12-05 07:11:13 +00:00
ConfigurationToken : options . videoToken || onvifDevice . current _profile . token ,
ImagingSettings : onvifParams
2020-12-04 04:38:37 +00:00
} )
response . ok = true
response . onvifResponse = onvifResponse
} catch ( err ) {
2020-12-05 07:11:13 +00:00
response . error = err . stack . toString ( )
2020-12-04 04:38:37 +00:00
}
return response
}
const setDiscoveryMode = async ( onvifDevice , options ) => {
const response = {
ok : false
}
try {
const onvifResponse = await onvifDevice . services . device . setDiscoveryMode ( options . mode === 'Discoverable' || options . mode === 'NonDiscoverable' ? options . mode : 'Discoverable' )
response . ok = true
response . onvifResponse = onvifResponse
} catch ( err ) {
2020-12-05 07:11:13 +00:00
response . error = err . stack . toString ( )
2020-12-04 04:38:37 +00:00
}
return response
}
const getUIFieldValues = async ( onvifDevice ) => {
return await getDeviceInformation ( onvifDevice , {
all : true ,
} )
}
module . exports = {
getDeviceInformation : getDeviceInformation ,
setHostname : setHostname ,
2020-12-05 07:11:13 +00:00
setProtocols : setProtocols ,
2020-12-04 04:38:37 +00:00
setGateway : setGateway ,
setDNS : setDNS ,
setNTP : setNTP ,
rebootCamera : rebootCamera ,
setDateAndTime : setDateAndTime ,
createUser : createUser ,
deleteUser : deleteUser ,
setVideoConfiguration : setVideoConfiguration ,
setImagingSettings : setImagingSettings ,
setDiscoveryMode : setDiscoveryMode ,
2020-12-05 02:02:24 +00:00
setNetworkInterface : setNetworkInterface ,
2020-12-04 04:38:37 +00:00
getUIFieldValues : getUIFieldValues ,
}