UNPKG

onvif

Version:

Client to ONVIF NVT devices Profile S: cameras

469 lines (436 loc) 16.9 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>JSDoc: Source: ptz.js</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: ptz.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>/** * @namespace cam * @description PTZ section for Cam class * @author Andrew D.Laptev &lt;a.d.laptev@gmail.com> * @licence MIT */ const Cam = require('./cam').Cam , extend = require('util')._extend , linerase = require('./utils').linerase , url = require('url') ; /** * Receive cam presets * @param {object} [options] * @param {string} [options.profileToken] * @param [callback] */ Cam.prototype.getPresets = function(options, callback) { if (callback === undefined) { callback = options; options = {}; } this._request({ service: 'ptz' , body: this._envelopeHeader() + '&lt;GetPresets xmlns="http://www.onvif.org/ver20/ptz/wsdl">' + '&lt;ProfileToken>' + (options.profileToken || this.activeSource.profileToken) +'&lt;/ProfileToken>' + '&lt;/GetPresets>' + this._envelopeFooter() }, function(err, data, xml) { if (!err) { this.presets = {}; var presets = linerase(data).getPresetsResponse.preset; if (typeof presets !== 'undefined') { if (!Array.isArray(presets)) { presets = [presets]; } presets.forEach(function(preset) { this.presets[preset.name] = preset.$.token; }.bind(this)); } } if (callback) { callback.call(this, err, this.presets, xml); } }.bind(this)); }; /** * /PTZ/ Go to preset * @param {object} options * @param {string} [options.profileToken] * @param {string} options.preset PresetName from {@link Cam#presets} property * @param {function} callback */ Cam.prototype.gotoPreset = function(options, callback) { this._request({ service: 'ptz' , body: this._envelopeHeader() + '&lt;GotoPreset xmlns="http://www.onvif.org/ver20/ptz/wsdl">' + '&lt;ProfileToken>' + (options.profileToken || this.activeSource.profileToken) + '&lt;/ProfileToken>' + '&lt;PresetToken>' + options.preset + '&lt;/PresetToken>' + (options.speed ? '&lt;Speed>' + this._panTiltZoomVectors(options.speed) + '&lt;/Speed>' : '') + '&lt;/GotoPreset>' + this._envelopeFooter() }, callback.bind(this)); }; /** * @typedef {object} Cam~PTZStatus * @property {object} position * @property {number} position.x * @property {number} position.y * @property {number} position.zoom * @property {string} moveStatus * @property {?Error} error * @property {Date} utcTime */ /** * @callback Cam~GetPTZStatusCallback * @property {?Error} error * @property {Cam~PTZStatus} status */ /** * /PTZ/ Receive cam status * @param {Object} [options] * @param {string} [options.profileToken={@link Cam#activeSource.profileToken}] * @param {Cam~GetPTZStatusCallback} callback */ Cam.prototype.getStatus = function(options, callback) { if (callback === undefined) { callback = options; options = {}; } this._request({ service: 'ptz' , body: this._envelopeHeader() + '&lt;GetStatus xmlns="http://www.onvif.org/ver20/ptz/wsdl">' + '&lt;ProfileToken>' + (options.profileToken || this.activeSource.profileToken) +'&lt;/ProfileToken>' + '&lt;/GetStatus>' + this._envelopeFooter() }, function(err, data, xml) { if (!err) { var res = linerase(data).getStatusResponse.PTZStatus; var status = { position: { x: res.position.panTilt.$.x , y: res.position.panTilt.$.y , zoom: res.position.zoom.$.x } , moveStatus: res.moveStatus , error: res.error , utcTime: res.utcTime }; } callback.call(this, err, err ? null : status, xml); }.bind(this)); }; /** * /PTZ/ Returns the properties of the requested PTZ node, if it exists. * Use this function to get maximum number of presets, ranges of admitted values for x, y, zoom, iris, focus * @param {Function} callback */ Cam.prototype.getNodes = function(callback) { this._request({ service: 'ptz' , body: this._envelopeHeader() + '&lt;GetNodes xmlns="http://www.onvif.org/ver20/ptz/wsdl" />' + this._envelopeFooter() }, function(err, data, xml) { if (!err) { var nodes = this.nodes = {}; data[0]['getNodesResponse'].forEach(function(ptzNode) { nodes[ptzNode['PTZNode'][0].$.token] = linerase(ptzNode['PTZNode'][0]); delete nodes[ptzNode['PTZNode'][0].$.token].$; }); } callback.call(this, err, nodes, xml); }.bind(this)); }; /** * /PTZ/ Get an array with configuration names * @param {Function} callback */ Cam.prototype.getConfigurations = function(callback) { this._request({ service: 'ptz' , body: this._envelopeHeader() + '&lt;GetConfigurations xmlns="http://www.onvif.org/ver20/ptz/wsdl">' + '&lt;/GetConfigurations>' + this._envelopeFooter() }, function(err, data, xml) { if (!err) { var configurations = {}; data[0]['getConfigurationsResponse'].forEach(function(configuration) { configurations[configuration['PTZConfiguration'][0]['name']] = { useCount: parseInt(configuration['PTZConfiguration'][0]['useCount']) , nodeToken: configuration['PTZConfiguration'][0]['nodeToken'][0] , defaultPTZSpeed: { x: configuration['PTZConfiguration'][0]['defaultPTZSpeed'][0]['panTilt'][0].$.x , y: configuration['PTZConfiguration'][0]['defaultPTZSpeed'][0]['panTilt'][0].$.y , zoom: configuration['PTZConfiguration'][0]['defaultPTZSpeed'][0]['zoom'][0].$.x } , defaultPTZTimeout: configuration['PTZConfiguration'][0]['defaultPTZTimeout'][0] }; }); this.configurations = configurations; } if (callback) { callback.call(this, err, this.configurations, xml); } }.bind(this)); }; /** * /PTZ/ Get options for the PTZ configuration * @param {string} configurationToken * @param {Function} callback */ Cam.prototype.getConfigurationOptions = function(configurationToken, callback) { this._request({ service: 'ptz' , body: this._envelopeHeader() + '&lt;GetConfigurationOptions xmlns="http://www.onvif.org/ver20/ptz/wsdl">' + '&lt;ConfigurationToken>' + configurationToken + '&lt;/ConfigurationToken>' + '&lt;/GetConfigurationOptions>' + this._envelopeFooter() }, function(err, data, xml) { var configOptions; if (!err) { var sp = data[0]['getConfigurationOptionsResponse'][0]['PTZConfigurationOptions'][0]['spaces'][0]; configOptions = { ptzTimeout: { min: data[0]['getConfigurationOptionsResponse'][0]['PTZConfigurationOptions'][0]['PTZTimeout'][0]['min'] , max: data[0]['getConfigurationOptionsResponse'][0]['PTZConfigurationOptions'][0]['PTZTimeout'][0]['max'] } , spaces: { absolute: { x: { min: parseFloat(sp['absolutePanTiltPositionSpace'][0]['XRange'][0]['min'][0]) , max: parseFloat(sp['absolutePanTiltPositionSpace'][0]['XRange'][0]['max'][0]) , uri: sp['absolutePanTiltPositionSpace'][0]['URI'] } , y: { min: parseFloat(sp['absolutePanTiltPositionSpace'][0]['YRange'][0]['min'][0]) , max: parseFloat(sp['absolutePanTiltPositionSpace'][0]['YRange'][0]['max'][0]) , uri: sp['absolutePanTiltPositionSpace'][0]['URI'] } , zoom: { min: parseFloat(sp['absoluteZoomPositionSpace'][0]['XRange'][0]['min'][0]) , max: parseFloat(sp['absoluteZoomPositionSpace'][0]['XRange'][0]['max'][0]) , uri: sp['absoluteZoomPositionSpace'][0]['URI'] } } , relative: { x: { min: parseFloat(sp['relativePanTiltTranslationSpace'][0]['XRange'][0]['min'][0]) , max: parseFloat(sp['relativePanTiltTranslationSpace'][0]['XRange'][0]['max'][0]) , uri: sp['relativePanTiltTranslationSpace'][0]['URI'] } , y: { min: parseFloat(sp['relativePanTiltTranslationSpace'][0]['YRange'][0]['min'][0]) , max: parseFloat(sp['relativePanTiltTranslationSpace'][0]['YRange'][0]['max'][0]) , uri: sp['relativePanTiltTranslationSpace'][0]['URI'] } , zoom: { min: parseFloat(sp['relativeZoomTranslationSpace'][0]['XRange'][0]['min'][0]) , max: parseFloat(sp['relativeZoomTranslationSpace'][0]['XRange'][0]['max'][0]) , uri: sp['relativeZoomTranslationSpace'][0]['URI'] } } , continuous: { x: { min: parseFloat(sp['continuousPanTiltVelocitySpace'][0]['XRange'][0]['min'][0]) , max: parseFloat(sp['continuousPanTiltVelocitySpace'][0]['XRange'][0]['max'][0]) , uri: sp['continuousPanTiltVelocitySpace'][0]['URI'] } , y: { min: parseFloat(sp['continuousPanTiltVelocitySpace'][0]['YRange'][0]['min'][0]) , max: parseFloat(sp['continuousPanTiltVelocitySpace'][0]['YRange'][0]['max'][0]) , uri: sp['continuousPanTiltVelocitySpace'][0]['URI'] } , zoom: { min: parseFloat(sp['continuousZoomVelocitySpace'][0]['XRange'][0]['min'][0]) , max: parseFloat(sp['continuousZoomVelocitySpace'][0]['XRange'][0]['max'][0]) , uri: sp['continuousZoomVelocitySpace'][0]['URI'] } } , common: { x: { min: parseFloat(sp['panTiltSpeedSpace'][0]['XRange'][0]['min'][0]) , max: parseFloat(sp['panTiltSpeedSpace'][0]['XRange'][0]['max'][0]) , uri: sp['panTiltSpeedSpace'][0]['URI'] } , zoom: { min: parseFloat(sp['zoomSpeedSpace'][0]['XRange'][0]['min'][0]) , max: parseFloat(sp['zoomSpeedSpace'][0]['XRange'][0]['max'][0]) , uri: sp['zoomSpeedSpace'][0]['URI'] } } } }; if (this.configurations[configurationToken]) { extend(this.configurations[configurationToken], configOptions); } } if (callback) { callback.call(this, err, configOptions, xml); } }.bind(this)); }; /** * /PTZ/ relative move * @param {object} options * @param {string} [options.profileToken=Cam#activeSource.profileToken] * @param {number} [options.x=0] Pan, float within -1 to 1 * @param {number} [options.y=0] Tilt, float within -1 to 1 * @param {number} [options.zoom=0] Zoom, float within 0 to 1 * @param {object} [options.speed] If the speed argument is omitted, the default speed set by the PTZConfiguration will be used. * @param {number} [options.speed.x] Pan speed, float within 0 to 1 * @param {number} [options.speed.y] Tilt speed, float within 0 to 1 * @param {number} [options.speed.zoom] Zoom speed, float within 0 to 1 * @param {Cam~RequestCallback} [callback] */ Cam.prototype.relativeMove = function(options, callback) { callback = callback ? callback.bind(this) : function() {}; // Due to some glitches in testing cam forcibly set undefined move parameters to zero options.x = options.x || 0; options.y = options.y || 0; options.zoom = options.zoom || 0; this._request({ service: 'ptz' , body: this._envelopeHeader() + '&lt;RelativeMove xmlns="http://www.onvif.org/ver20/ptz/wsdl">' + '&lt;ProfileToken>' + (options.profileToken || this.activeSource.profileToken) + '&lt;/ProfileToken>' + '&lt;Translation>' + this._panTiltZoomVectors(options) + '&lt;/Translation>' + (options.speed ? '&lt;Speed>' + this._panTiltZoomVectors(options.speed) + '&lt;/Speed>' : '') + '&lt;/RelativeMove>' + this._envelopeFooter() }, callback.bind(this)); }; /** * /PTZ/ absolute move * @param {object} options * @param {string} [options.profileToken=Cam#activeSource.profileToken] * @param {number} [options.x] Pan, float within -1 to 1 * @param {number} [options.y] Tilt, float within -1 to 1 * @param {number} [options.zoom] Zoom, float within 0 to 1 * @param {object} [options.speed] If the speed argument is omitted, the default speed set by the PTZConfiguration will be used. * @param {number} [options.speed.x] Pan speed, float within 0 to 1 * @param {number} [options.speed.y] Tilt speed, float within 0 to 1 * @param {number} [options.speed.zoom] Zoom speed, float within 0 to 1 * @param {Cam~RequestCallback} [callback] */ Cam.prototype.absoluteMove = function(options, callback) { callback = callback ? callback.bind(this) : function() {}; // Due to some glitches in testing cam forcibly set undefined move parameters to zero options.x = options.x || 0; options.y = options.y || 0; options.zoom = options.zoom || 0; this._request({ service: 'ptz' , body: this._envelopeHeader() + '&lt;AbsoluteMove xmlns="http://www.onvif.org/ver20/ptz/wsdl">' + '&lt;ProfileToken>' + (options.profileToken || this.activeSource.profileToken) + '&lt;/ProfileToken>' + '&lt;Position>' + this._panTiltZoomVectors(options) + '&lt;/Position>' + (options.speed ? '&lt;Speed>' + this._panTiltZoomVectors(options.speed) + '&lt;/Speed>' : '') + '&lt;/AbsoluteMove>' + this._envelopeFooter() }, callback.bind(this)); }; /** * /PTZ/ Operation for continuous Pan/Tilt and Zoom movements * @param options * @param {string} [options.profileToken=Cam#activeSource.profileToken] * @param {number} [options.x=0] pan velocity, float within 0 to 1 * @param {number} [options.y=0] tilt velocity, float within 0 to 1 * @param {number} [options.zoom=0] zoom velocity, float within 0 to 1 * @param {number} [options.timeout=Infinity] timeout in milliseconds * @param {Cam~RequestCallback} callback */ Cam.prototype.continuousMove = function(options, callback) { callback = callback ? callback.bind(this) : function() {}; // Due to some glitches in testing cam forcibly set undefined move parameters to zero options.x = options.x || 0; options.y = options.y || 0; options.zoom = options.zoom || 0; this._request({ service: 'ptz' , body: this._envelopeHeader() + '&lt;ContinuousMove xmlns="http://www.onvif.org/ver20/ptz/wsdl">' + '&lt;ProfileToken>' + (options.profileToken || this.activeSource.profileToken) + '&lt;/ProfileToken>' + '&lt;Velocity>' + this._panTiltZoomVectors(options) + '&lt;/Velocity>' + (options.timeout ? '&lt;Timeout>PT' + (options.timeout / 1000) + 'S&lt;/Timeout>' : '') + '&lt;/ContinuousMove>' + this._envelopeFooter() }, callback.bind(this)); }; /** * Stop ongoing pan, tilt and zoom movements of absolute relative and continuous type * @param {object} [options] * @param {string} [options.profileToken] * @param {boolean|string} [options.panTilt] * @param {boolean|string} [options.zoom] * @param {Cam~RequestCallback} [callback] */ Cam.prototype.stop = function(options, callback) { if (callback === undefined) { switch (typeof options) { case 'object': callback = function() {}; break; case 'function': callback = options; options = {}; break; default: callback = function() {}; options = {}; } } this._request({ service: 'ptz' , body: this._envelopeHeader() + '&lt;Stop xmlns="http://www.onvif.org/ver20/ptz/wsdl">' + '&lt;ProfileToken>' + (options.profileToken || this.activeSource.profileToken) + '&lt;/ProfileToken>' + (options.panTilt ? '&lt;PanTilt>' + options.panTilt + '&lt;/PanTilt>' : '') + (options.zoom ? '&lt;Zoom>' + options.zoom + '&lt;/Zoom>' : '') + '&lt;/Stop>' + this._envelopeFooter() }, callback.bind(this)); }; /** * Create ONVIF soap vector * @param [ptz.x] * @param [ptz.y] * @param [ptz.zoom] * @return {string} * @private */ Cam.prototype._panTiltZoomVectors = function(ptz) { return ptz ? (ptz.x !== undefined &amp;&amp; ptz.y !== undefined ? '&lt;PanTilt x="' + ptz.x + '" y="' + ptz.y + '" xmlns="http://www.onvif.org/ver10/schema"/>' : '') + (ptz.zoom !== undefined ? '&lt;Zoom x="' + ptz.zoom + '" xmlns="http://www.onvif.org/ver10/schema"/>' : '') : ''; }; </code></pre> </article> </section> </div> <nav> <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Cam_.html">Cam</a></li><li><a href="Discovery_.html">Discovery</a></li></ul><h3>Events</h3><ul><li><a href="Cam_.html#event:event">event</a></li><li><a href="Cam_.html#event:rawResponse">rawResponse</a></li><li><a href="Discovery_.html#event:device">device</a></li><li><a href="Discovery_.html#event:error">error</a></li></ul><h3>Namespaces</h3><ul><li><a href="cam.html">cam</a></li><li><a href="discovery.html">discovery</a></li><li><a href="utils.html">utils</a></li></ul><h3>Global</h3><ul><li><a href="global.html#guid">guid</a></li><li><a href="global.html#linerase">linerase</a></li><li><a href="global.html#parseSOAPString">parseSOAPString</a></li></ul> </nav> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.0</a> on Mon Jun 20 2016 15:42:17 GMT+0300 (MSK) </footer> <script> prettyPrint(); </script> <script src="scripts/linenumber.js"> </script> </body> </html>