Coder Social home page Coder Social logo

guilhermec18 / node-onvif Goto Github PK

View Code? Open in Web Editor NEW
437.0 30.0 196.0 237 KB

The node-onvif is a Node.js module which allows you to communicate with the network camera which supports the ONVIF specifications.

License: MIT License

JavaScript 100.00%

node-onvif's Introduction

node-onvif

The node-onvif is a Node.js module which allows you to communicate with the network camera which supports the ONVIF specifications.

The ONVIF (Open Network Video Interface) is an open industry forum promoting and developing global standards for interfaces of IP-based physical security products such as network cameras. The ONVIF specifications are available in their web site.

Recently, most of network cameras for business support the ONVIF standard. Furthermore, some network cameras for home support it though the implementation is partial. The node-onvif allows you to control network cameras which implement the ONVIF standard.

The node-onvif provides you with the APIs as follows:

  • Discovery the ONVIF network cameras
  • Access some services supported by the ONVIF network cameras as follows:
    • Device Management Service
    • Media Service
    • PTZ Service

Besides, the node-onvif provides you with simple APIs that allow you to control ONVIF network cameras easily even if you are not familiar with the ONVIF specifications.

Installation

$ npm install -s node-onvif

Sample Application

This package includes a sample application "ONVIF Network Camera Manager". You can try this module with your PTZ ONVIF network camera easily.

ONVIF Network Camera Manager


Table of Contents


This section shows how to discover ONVIF network cameras, how to get the device information, and how to control the PTZ of the device.

This sample code shows how to discover ONVIF network cameras.

const onvif = require('node-onvif');

console.log('Start the discovery process.');
// Find the ONVIF network cameras.
// It will take about 3 seconds.
onvif.startProbe().then((device_info_list) => {
  console.log(device_info_list.length + ' devices were found.');
  // Show the device name and the URL of the end point.
  device_info_list.forEach((info) => {
    console.log('- ' + info.urn);
    console.log('  - ' + info.name);
    console.log('  - ' + info.xaddrs[0]);
  });
}).catch((error) => {
  console.error(error);
});

The code above will output the result like this:

Start the discovery process.
5 devices were found.
- urn:uuid:cd279d60-afd3-3a22-00dc-daaa234e772c
  - Canon VB-S30D
  - http://192.168.10.10:80/onvif/device_service
- urn:uuid:13814000-8752-1052-bfff-045d4b150782
  - Sony
  - http://192.168.10.14/onvif/device_service
- urn:uuid:4d454930-0000-1000-8000-bcc34217e292
  - Panasonic BB-SC384B
  - http://192.168.10.12/onvif/device_service
- urn:uuid:00030050-0000-1000-8000-104fa8e2cc96
  - Sony
  - http://192.168.10.25/onvif/device_service
- urn:uuid:8b10a2e0-3302-48df-9d1a-1197c360e6ca
  - Avantgarde-Test
  - http://192.168.10.27:36000/onvif/device_service

The most important information for controlling the device is the URL of the end point of the device. You can get the URL from the code info.xaddrs[0] above.

In order to control the ONVIF network camera, you have to create an OnfivDevice object for the device, then initialize the object using the init() method. This sample code shows how to create an OnvifDevice object and get the detailed information of the device.

const onvif = require('node-onvif');

// Create an OnvifDevice object
let device = new onvif.OnvifDevice({
  xaddr: 'http://192.168.10.10:80/onvif/device_service',
  user : 'admin',
  pass : '123456'
});

// Initialize the OnvifDevice object
device.init().then((info) => {
  // Show the detailed information of the device.
  console.log(JSON.stringify(info, null, '  '));
}).catch((error) => {
  console.error(error);
});

The code above will output the result like this:

{
  "Manufacturer": "Canon",
  "Model": "VB-S30D",
  "FirmwareVersion": "Ver. 1.3.3",
  "SerialNumber": "999999999999",
  "HardwareId": "1D"
}

This sample code shows how to get the UDP stream URL.

const onvif = require('node-onvif');

// Create an OnvifDevice object
let device = new onvif.OnvifDevice({
  xaddr: 'http://192.168.10.14:10080/onvif/device_service',
  user : 'admin',
  pass : '123456'
});

// Initialize the OnvifDevice object
device.init().then(() => {
  // Get the UDP stream URL
  let url = device.getUdpStreamUrl();
  console.log(url);
}).catch((error) => {
  console.error(error);
});

The code above will output the result like this:

rtsp://192.168.10.14:10554/tcp/av0_0

This sample code shows how to get the data of the snapshot and save it to a file.

const onvif = require('node-onvif');
const fs = require('fs');

// Create an OnvifDevice object
let device = new onvif.OnvifDevice({
  xaddr: 'http://192.168.10.14:10080/onvif/device_service',
  user : 'admin',
  pass : '123456'
});

// Initialize the OnvifDevice object
device.init().then(() => {
  // Get the data of the snapshot
  console.log('fetching the data of the snapshot...');
  return device.fetchSnapshot();
}).then((res) => {
  // Save the data to a file
  fs.writeFileSync('snapshot.jpg', res.body, {encoding: 'binary'});
  console.log('Done!');
}).catch((error) => {
  console.error(error);
});

The code above will output the result like this:

fetching the data of the snapshot...
Done!

You will find a JPEG file named snapshot.jpg in the current directory.

This sample code shows how to pan, tilt, and zoom the ONVIF network camera.

const onvif = require('node-onvif');

// Create an OnvifDevice object
let device = new onvif.OnvifDevice({
  xaddr: 'http://192.168.10.14:10080/onvif/device_service',
  user : 'admin',
  pass : '123456'
});

// Initialize the OnvifDevice object
device.init().then(() => {
  // Move the camera
  return device.ptzMove({
    'speed': {
      x: 1.0, // Speed of pan (in the range of -1.0 to 1.0)
      y: 0.0, // Speed of tilt (in the range of -1.0 to 1.0)
      z: 0.0  // Speed of zoom (in the range of -1.0 to 1.0)
    },
    'timeout': 1 // seconds
  });
}).then(() => {
  console.log('Done!');
}).catch((error) => {
  console.error(error);
});

If this code has been successfully finished, you could find that the camera turns to the right for a second at the highest speed.


Asynchronous methods implemented in this module return a Promise object. In the other hand, such methods support callback coding style as well.

device.fetchSnapshot().then((res) => {
  // Do something
}).catch((error) => {
  console.error(error); 
});
device.fetchSnapshot((error, res) => {
  if(error) {
    console.error(error);
  } else {
    // Do something
  }
});

Though the results of the codes above will be completely same, it is strongly recommended to use the Promise style. The callback style will be deprecated in the future.

The callback style remains only for backward compatibility becase the versions earlier than v0.1.0 supported only the callback style.


In order to use the node-onvif module, you have to load the node-onvif module as follows:

const onvif = require('node-onvif');

The variable onvif in the code above is the Onvif object.

This section describes the methods implemented in the Onvif object.

This method starts the discovery process and tries to find the ONVIF network camera devices. This method returns a Promise object if the callback is not passed.

The discovery process will take about 3 seconds. Once the process finished, the resolve() function will be called with an Array object containing hash objects representing the found devices. The hash object contains the properties as follows:

Property Type Description
urn String The URN (Uniform Resource Name) assigned to the device (e.g., "urn:uuid:6b2be733-6ad1-4467-8bd0-747bd8efd206")
name String The product name of the device (e.g., "Panasonic BB-SC384B").
hardware String The description of the hardware of the device (e.g., "BB-SC384B").
location String The physical location of the device (e.g., "China", "shenzhen", "office").
types Array The list of types supported by the device (e.g., "dn:NetworkVideoTransmitter", "tds:Device"). Basically, this module is for "dn:NetworkVideoTransmitter".
xaddrs Array The list of URLs of the end points (e.g., "http://192.168.10.17/onvif/device_service", "http://[2408:12:2e20:d000:bec3:42ff:fe17:e292]/onvif/device_service").
scopes Array The list of scopes set to the device (e.g., "onvif://www.onvif.org/Profile/Streaming", "onvif://www.onvif.org/location/office").

The sample code below shows the structure of the hash object representing the found device.

const onvif = require('node-onvif');

// Find the ONVIF network cameras
onvif.startProbe().then((device_list) => {
  // Show the information of the found devices
  console.log(JSON.stringify(device_list, null, '  '));
}).catch((error) => {
  console.error(error);
});

The code above will output the result like this:

[
  {
    "urn": "urn:uuid:4d454930-0000-1000-8000-bcc34217e292",
    "name": "Panasonic BB-SC384B",
    "hardware": "BB-SC384B",
    "location": "office",
    "types": [
      "dn:NetworkVideoTransmitter",
      "tds:Device"
    ],
    "xaddrs": [
      "http://192.168.10.12/onvif/device_service",
      "http://[2408:12:2e20:d000:bec3:42ff:fe17:e292]/onvif/device_service"
    ],
    "scopes": [
      "onvif://www.onvif.org/Profile/Streaming",
      "onvif://www.onvif.org/hardware/BB-SC384B",
      "onvif://www.onvif.org/location/office",
      "onvif://www.onvif.org/name/Panasonic_BB-SC384B",
      ""
    ]
  },
  {
    "urn": "urn:uuid:cd279d60-afd3-3a22-00dc-daaa234e772c",
    "name": "Canon VB-S30D",
    "hardware": "VB-S30D",
    "location": "Canon",
    "types": [
      "dn:NetworkVideoTransmitter",
      "tds:Device"
    ],
    "xaddrs": [
      "http://192.168.10.10:80/onvif/device_service",
      "http://169.254.240.48:80/onvif/device_service",
      "http://[2408:12:2e20:d000:1a0c:acff:fee9:c231]:80/onvif/device_service",
      "http://[fe80::1a0c:acff:fee9:c231]:80/onvif/device_service"
    ],
    "scopes": [
      "onvif://www.onvif.org/type/video_encoder",
      "onvif://www.onvif.org/type/ptz",
      "onvif://www.onvif.org/name/Canon_VB-S30D",
      "onvif://www.onvif.org/hardware/VB-S30D",
      "onvif://www.onvif.org/type/audio_encoder",
      "onvif://www.onvif.org/type/video_analytics",
      "onvif://www.onvif.org/type/Network_Video_Transmitter",
      "onvif://www.onvif.org/Profile/Streaming",
      "onvif://www.onvif.org/location/Canon"
    ]
  }
]

This method aborts the discovery process asynchronously. This method returns a Promise object if the callback is not passed.

onvif.stopProbe().then(() => {
  console.log('Aborted the discovery process.');
}).catch((error) => {
  console.error(error);
});

If the discovery process has been finished when the stopProbe() method is called, this method do nothing and the resolve() function will be called.

In most cases, you do not have to call this method because the discovery process is automatically finished in 3 seconds after the startProbe() method was called.

This method is deprecated. Do not use this method now. It will be deleted in the future.

This method starts the discovery process and tries to find the ONVIF network camera devices. Whenever an ONVIF network camera device is found, the callback function specified to the 1st argument will be called.

When a device is found, the callback will be passed a hash object as the 1st argument. The properties set to the hash object are as follows:

Property Type Description
urn String The URN (Uniform Resource Name) assigned to the device (e.g., "urn:uuid:6b2be733-6ad1-4467-8bd0-747bd8efd206")
name String The product name of the device (e.g., "Panasonic BB-SC384B").
hardware String The description of the hardware of the device (e.g., "BB-SC384B").
location String The physical location of the device (e.g., "China", "shenzhen", "office").
types Array The list of types supported by the device (e.g., "dn:NetworkVideoTransmitter", "tds:Device"). Basically, this module is for "dn:NetworkVideoTransmitter".
xaddrs Array The list of URLs of the end points (e.g., "http://192.168.10.17/onvif/device_service", "http://[2408:12:2e20:d000:bec3:42ff:fe17:e292]/onvif/device_service").
scopes Array The list of scopes set to the device (e.g., "onvif://www.onvif.org/Profile/Streaming", "onvif://www.onvif.org/location/office").

The sample code below shows the structure of the hash object representing the found device.

const onvif = require('node-onvif');

// Find the ONVIF network cameras
onvif.startDiscovery((info) => {
  // Show the information of the found device
  console.log(JSON.stringify(info, null, '  '));
});

The code above will output the result like this:

{
  "urn": "urn:uuid:4d454930-0000-1000-8000-bcc34217e292",
  "name": "Panasonic BB-SC384B",
  "hardware": "BB-SC384B",
  "location": "office",
  "types": [
    "dn:NetworkVideoTransmitter",
    "tds:Device"
  ],
  "xaddrs": [
    "http://192.168.10.17/onvif/device_service",
    "http://[2408:12:2e20:d000:bec3:42ff:fe17:e292]/onvif/device_service"
  ],
  "scopes": [
    "onvif://www.onvif.org/Profile/Streaming",
    "onvif://www.onvif.org/hardware/BB-SC384B",
    "onvif://www.onvif.org/location/office",
    "onvif://www.onvif.org/name/Panasonic_BB-SC384B",
    ""
  ]
}

This method is deprecated. Do not use this method now. It will be deleted in the future.

This method stops the discovery process asynchronously. If you want to do something waiting for stopping the discovery process successfully, you can pass a callback function to this method as the 1st argument.

const onvif = require('node-onvif');

// Start the discovery process
onvif.startDiscovery((info) => {
  // Do something
});

// Stop the discovery process in 3 seconds
setTimeout(() => {
  onvif.stopDiscovery(() => {
    // If you want to do something after stopping
    // the discovery process successfully, write
    // codes here.
  });
}, 3000);

If you don't need to do anything after the discovery process has been terminated successfully, you can do this:

onvif.stopDiscovery();

The OnvifDevice object represents an ONVIF network camera device. You can control the ONVIF network camera through this object.

In order to control an ONVIF network camera, you have to create an OnvifDevice object from the OnvifDevice constructor by yourself as follows:

const onvif = require('node-onvif');

// Create an OnvifDevice object
let device = new onvif.OnvifDevice({
  xaddr: 'http://192.168.10.14:10080/onvif/device_service',
  user : 'admin',
  pass : '123456'
});

The variable device represents an OnvifDevice object in the code above. The OnvifDevice constructor requires a hash object containing some properties as follows:

Property Type Required Description
xaddr String required URL of the end point of the targeted device.
user String optional User name for the user authentication.
pass String optional Password for the user authentication.

If you know the value of the xaddr property (the URL of the end point of the targeted device) in advance, you don't need to run the discover process(i.e., you don't need to call the startDiscovery() method).

The OnvifDevice object provides some properties as follows:

Property Type Description
services Object
+- device Object OnvifServiceDevice object
+- media Object OnvifServiceMedia object
+- ptz Object OnvifServicePtz object

These objects will be set when the initialization process is completed calling the init() method. See the section "ONVIF commands" for details.

This method initializes the OnvifDevice object. This method must be called before you control the targeted device. Actually, this method retrieves several information essential to control the device. The process of this method takes a little time to be completed because this method sends several commands to the targeted device and waits for the all relevant responses. Note that you have to wait for the completion of this method to control the device.

This method returns a Promise object if the callback is not passed. If the initialization process is completed, the resolve() function will be called with a hash obect containing the properties as follows:

Property Type Description
Manufacturer String The manufactor of the device.
Model String The device model.
FirmwareVersion String The firmware version in the device.
SerialNumber String The serial number of the device.
HardwareId String The hardware ID of the device.
const onvif = require('node-onvif');

// Create an OnvifDevice object
let device = new onvif.OnvifDevice({
  xaddr: 'http://192.168.10.14:10080/onvif/device_service',
  user : 'admin',
  pass : '888888'
});

// Initialize the OnvifDevice object
device.init().then((info) => {
  console.log('The OnvifDevice object has been initialized successfully.');
  console.log(JSON.stringify(info, null, '  '));
}).catch((error) => {
  console.log('[ERROR] ' + error.message);
});

The code above will output the result as follow:

{
  "Manufacturer": "Canon",
  "Model": "VB-S30D",
  "FirmwareVersion": "Ver. 1.3.3",
  "SerialNumber": "999999999999",
  "HardwareId": "1D"
}

This method returns a hash object consisting of several device information as follow:

Property Type Description
Manufacturer String The manufactor of the device.
Model String The device model.
FirmwareVersion String The firmware version in the device.
SerialNumber String The serial number of the device.
HardwareId String The hardware ID of the device.

This object is as same as the object obtained by the init() method. Actually, the information has been already retreaved when the initialization process was completed (the init() method was called) and stored in the OnvifDevice object. The getInformation() method just returns the stored information.

let info = device.getInformation();
console.log(JSON.stringify(info, null, '  '));

The code above will output the result like this:

{
  "Manufacturer": "Vstarcam",
  "Model": "Hi3518eV100",
  "FirmwareVersion": "2.4",
  "SerialNumber": "3056894",
  "HardwareId": "1.0"
}

The ONVIF network cameras have several profiles by default. The profile is a set of configuration values such as the resolution of the video encoder, the URL of the snapshot, the URL of the video stream, the range of PTZ, and so on.

The OnvifDevice object is sure to select one of them and each method implemented in the OnvifDevice object is executed using the selected profile. By default, the OnvifDevice object selects the profile found first in the initialization process.

This method returns a hash object containing the information of the profile currently selected by the OnvifDevice object.

let profile = device.getCurrentProfile();
console.log(JSON.stringify(profile, null, '  '));

The code above will output the result like this:

{
  "token": "PROFILE_000",
  "name": "PROFILE_000",
  "snapshot": "http://192.168.10.14:81/snapshot.cgi",
  "stream": {
    "udp": "rtsp://192.168.10.14:10554/tcp/av0_0",
    "http": "rtsp://192.168.10.14:10554/tcp/av0_0",
    "rtsp": "rtsp://192.168.10.14:10554/tcp/av0_0"
  },
  "video": {
    "source": {
      "token": "V_SRC_000",
      "name": "V_SRC_000",
      "bounds": {
        "width": 1280,
        "height": 720,
        "x": 0,
        "y": 0
      }
    },
    "encoder": {
      "token": "V_ENC_000",
      "name": "V_ENC_000",
      "resolution": {
        "width": 1280,
        "height": 720
      },
      "quality": 4,
      "framerate": 25,
      "bitrate": 2048,
      "encoding": "H264"
    }
  },
  "audio": {
    "source": {
      "token": "A_SRC_000",
      "name": "A_SRC_000"
    },
    "encoder": {
      "token": "A_ENC_000",
      "name": "A_ENC_000",
      "bitrate": 64,
      "samplerate": 8,
      "encoding": "G711"
    }
  },
  "ptz": {
    "range": {
      "x": {
        "min": -1,
        "max": 1
      },
      "y": {
        "min": -1,
        "max": 1
      },
      "z": {
        "min": 0,
        "max": 1
      }
    }
  }
}

This method returns a list of the profiles set to the device as an Array object. Each element in the Array object is a hash object whose structure is as same as the hash object which can be retrieved by the getCurrentProfile() method.

See the section "changeProfile() method" for details.

This method changes the current profile to the profile corresponding to the index specified as the 1st argument, then returns a hash object representing the newly selected profile. The index is the position in the profile list which can be obtained through the getProfileList() method, which is in the range of 0 to the length of the list minus 1.

You can pass the profile token instead of the index. If a Number value is passed, this method assumes the a index is passed. If a String value is passed, this method assumes that a token is passed.

The sample code below shows how to change the current profile to the profile whose video resolution is the smallest:

// Get the current profile
let profile = device.getCurrentProfile();
// Show the video resolution of the current profile
let reso = profile['video']['encoder']['resolution'];
console.log('- Before: ' + reso['width'] + ' x ' + reso['height']);

// Get a list of the profiles set in the device
let profile_list = device.getProfileList();

// Find the profile whose video resolution is the smallest
let min_square = 4000 * 2000;
let min_index = 0;
for(let i=0; i<profile_list.length; i++) {
  let resolution = profile_list[i]['video']['encoder']['resolution'];
  let square = resolution['width'] * resolution['height'];
  if(square < min_square) {
    min_square = square;
    min_index = i;
  }
}
// Change the current profile
profile = device.changeProfile(min_index);
// Show the video resolution
reso = profile['video']['encoder']['resolution'];
console.log('- After: ' + reso['width'] + ' x ' + reso['height']);

This sample code will output the result like this:

- Before: 1280 x 720
- After: 320 x 180

This method returns the UDP Stream URL. Though the URL can be obtained from the result of the getCurrentProfile() method as well, this method makes that easy.

let url = device.getUdpStreamUrl();
console.log(url);

The code above will output the result like this:

rtsp://192.168.10.14:10554/tcp/av0_0

This method fetches a snapshot captured by the camera at the time. The snapshot is obtained as a Buffer object representing the image data of the snapshot. This method returns a Promise object if the callback is not passed.

If the snapshot is captured successfully, a hash object is passed to the resolve() function. The hash object consists of some properties as follows:

Property Type Description
headers Object headers object representing the HTTP response header. This object is of the http module of Node.js.
body Object Buffer object representing the image data of the snapshot.

The code blow shows how to get the snapshot and save it as an image file:

device.fetchSnapshot().then((res) => {
  // Determine the file extention
  let ext = 'bin';
  let mime_pair = res.headers['content-type'].split('/');
  if(mime_pair[0] === 'image') {
    ext = mime_pair[1];
  }
  // Save the data to a file
  let fname = 'snapshot.' + ext;
  fs.writeFileSync(fname, res.body, {encoding: 'binary'});
  console.log('Done!');
}).catch((error) => {
  console.error(error);
});

This method pans, tilts, zooms the camera if the ONVIF network camera supports the PTZ service. This method returns a Promise object if the callback is not passed.

This method takes a hash object as the 1st argument. The structure of the hash object is as follows:

Property Type Required Description
speed Object required
+- x Float required Speed of pan in the range of -1.0 to 1.0.
+- y Float required Speed of tilt in the range of -1.0 to 1.0.
+- z Float required Speed of zoom in the range of -1.0 to 1.0.
timeout Integer optional Timeout in seconds (Default: 1)

The speed.x represents the speed of horizontal movement of the camera. If the value of the speed.x is positive, the camera will turn to the right. If the value is negative, the camera will turn to the left. If the value is zero, the camera won't move in a horizontal direction.

The speed.y represents the speed of vertical movement of the camera. If the value of the speed.y is positive, the camera will turn to the top. If the value is negative, the camera will turn to the bottom. If the value is zero, the camera won't move in a vertical direction.

The speed.z represents the speed of the zoom of the camera. If the value of the speed.z is positive, the camera will zoom in. If the value is negative, the camera will zoom out. if the value is zero, the camera won't zoom.

The code below will make the camera turn to the left at the highest speed for 1 second.

let params = {
  'speed': {
    x: 1.0, // Speed of pan (in the range of -1.0 to 1.0)
    y: 0.0, // Speed of tilt (in the range of -1.0 to 1.0)
    z: 0.0  // Speed of zoom (in the range of -1.0 to 1.0)
  },
  'timeout': 1 // seconds
};
// Move the camera
device.ptzMove(params).then(() => {
  console.log('Done!');
}).catch((error) => {
  console.error(error);
});

This method stops the movement of the camera caused by the ptzMove() method. This method returns a Promise object if the callback is not passed.

// Create the parameters
let params = {
  'speed': {x: 0.5, y: 0.0, z: 0.0},
  'timeout': 60 // seconds
};
// Supposed to move the camera for 60 seconds
device.ptzMove(params).then(() => {
  console.log('Succeeded to move.');
  // Stop to the PTZ in 2 seconds
  setTimeout(() => {
    device.ptzStop().then(() => {
      console.log('Succeeded to stop.');
    }).catch((error) => {
      console.error(error);
    });
  }, 2000);
}).catch((error) => {
  console.error(error);
});

Note that the all sections below are for those who are familiar with the ONVIF specifications.

The ONVIF specifications define a lot of SOAP-based commands. This module implements part of the commands. Actually, most of the methods described in the previous sections are implemented using the methods representing the commands described the sections below.

The methods for the ONVIF commands are exposed in the OnvifServiceDevice object, the OnvifServiceMedia object, and OnvifServicePtz object, which are available from the OnvifDevice.device property, the OnvifDevice.media property, and the OnvifDevice.ptz property, respectively.

For example, if you want to call the GotoHomePosition command, you can use the gotoHomePosition method implemented in the OnvifServicePtz object like this:

// Create a OnvifDevice object
let device = new onvif.OnvifDevice({
  xaddr: 'http://192.168.10.14:10080/onvif/device_service',
  user : 'admin',
  pass : '123456'
});

// Initialize the OnvifDevice object
device.init().then(() => {
  // The OnvifServicePtz object
  let ptz = device.services.ptz;
  if(!ptz) {
    throw new Error('Your ONVIF network camera does not support the PTZ service.');
  }
  // The parameters for the gotoHomePosition() method
  let profile = device.getCurrentProfile();
  let params = {
    'ProfileToken': profile['token'],
    'Speed'       : 1
  };
  // Send the GotoHomePosition command using the gotoHomePosition() method
  return ptz.gotoHomePosition(params);
}).then((result) => {
  console.log(JSON.stringify(result.data, null, '  '));
}).catch((error) => {
  console.error(error);
});

The code above will output the result like this:

{
  "GotoHomePositionResponse": {
    "$": {
      "xmlns": "http://www.onvif.org/ver20/ptz/wsdl"
    }
  }
}

Actually, the response from the targeted ONVIF network camera is SOAP. This module provides some representations of the response. the variable result in the code above consists of some properties as follows:

Property Type Description
soap String Raw SOAP response
formatted String Formatted SOAP response in order to be human readable
converted Object JavaScript object converted from SOAP response by xml2js module
data Object JavaScript object converted from the data in the <Body> element in the SOAP response

In most cases, only data property would be enough. If you need to evaluate the response in more detail, you can use the preferable property other than the data property.

The value of the soap property would be:

<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:enc="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:rpc="http://www.w3.org/2003/05/soap-rpc" xmlns:xop="http://www.w3.org/2004/08/xop/include"  xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:tt="http://www.onvif.org/ver10/schema"><env:Body><GotoHomePositionResponse xmlns="http://www.onvif.org/ver20/ptz/wsdl"></GotoHomePositionResponse></env:Body></env:Envelope>

The value of the formatted property would be:

<?xml version="1.0" encoding="UTF-8" ?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:enc="http://www.w3.org/2003/05/soap-encoding"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:rpc="http://www.w3.org/2003/05/soap-rpc" xmlns:xop="http://www.w3.org/2004/08/xop/include"
xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:tt="http://www.onvif.org/ver10/schema">
  <env:Body>
    <GotoHomePositionResponse xmlns="http://www.onvif.org/ver20/ptz/wsdl"></GotoHomePositionResponse>
  </env:Body>
</env:Envelope>

The value of the converted property would be:

{
  "$": {
    "xmlns:env": "http://www.w3.org/2003/05/soap-envelope",
    "xmlns:enc": "http://www.w3.org/2003/05/soap-encoding",
    "xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
    "xmlns:xsd": "http://www.w3.org/2001/XMLSchema",
    "xmlns:rpc": "http://www.w3.org/2003/05/soap-rpc",
    "xmlns:xop": "http://www.w3.org/2004/08/xop/include",
    "xmlns:tptz": "http://www.onvif.org/ver20/ptz/wsdl",
    "xmlns:tt": "http://www.onvif.org/ver10/schema"
  },
  "Body": {
    "GotoHomePositionResponse": {
      "$": {
        "xmlns": "http://www.onvif.org/ver20/ptz/wsdl"
      }
    }
  }
}

All methods representing the ONVIF commands return the same structured object as one described above. So in the description for each methods described in the sections below, only parameters to be passed to the method are listed.

Note that the first character of the method name implemented in this module is lower case though the corresponding letter of the ONVIF command name is upper case. For example, the ContinuousMove command specified in the ONVIF specification corresponds to the continuousMove method implemented in the OnvifServicePtz object.


This object represents the ONVIF Device Management Service.

This method sends a GetCapabilities command.

This method sends a GetWsdlUrl command.

This method sends a GetDiscoveryMode command.

This method sends a GetScopes command.

This method sends a SetScopes command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
Scopes Array required a list of URI

The code below shows how to set some scopes:

let params = {
  'Scopes': [
    'onvif://www.onvif.org/location/town/Nerima',
    'onvif://www.onvif.org/location/city/Tokyo'
  ]
};

device.services.device.setScopes(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

If you want to delete all configurable scopes, specify an empty Array object as the Scope property:

let params = {'Scopes': []}

This method sends a AddScopes command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
Scopes Array required a list of URI

The code below shows how to set some scopes:

let params = {
  'Scopes': [
    'onvif://www.onvif.org/location/town/Nerima',
    'onvif://www.onvif.org/location/city/Tokyo'
  ]
};

device.services.device.addScopes(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a RemoveScopes command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
Scopes Array required a list of URI

The code below shows how to set some scopes:

let params = {
  'Scopes': [
    'onvif://www.onvif.org/location/city/Tokyo',
    'onvif://www.onvif.org/location/town/Nerima'
  ]
};

device.services.device.removeScopes(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetHostname command.

This method sends a SetHostname command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
Name String required a host name

The code below shows how to set some scopes:

let params = {
  'Name': 'cam001'
};

device.services.device.setHostname(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetDNS command.

This method sends a SetDNS command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
FromDHCP boolean required true or false
SearchDomain Array optional a list of search domains
DNSManual Array optional a list of DNS addresses
+- Type String required "IPv4" or "IPv6"
+- IPv4Address String optional IPv4 address
+- IPv6Address String optional IPv6 address
let params = {
  'FromDHCP'    : false,
  'SearchDomain': ['futomi.gr.jp', 'hatano.gr.jp'],
  'DNSManual'   : [
    {'Type': 'IPv4', 'IPv4Address': '192.168.10.1'},
    {'Type': 'IPv4', 'IPv4Address': '192.168.10.3'}
  ]
};

return device.services.device.setDNS(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetNetworkProtocols command.

This method sends a GetNetworkProtocols command.

This method sends a SetNetworkProtocols command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
NetworkProtocols Array required
+- Name String required
+- Enabled Boolean optional
+- Port Integer optional
let params = {
  'NetworkProtocols': [
    {'Name': 'HTTP', 'Enabled': true, 'Port': 80},
    {'Name': 'RTSP', 'Enabled': true, 'Port': 554},
  ]
};

device.services.device.setNetworkProtocols(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetNetworkDefaultGateway command.

This method sends a SetNetworkDefaultGateway command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
NetworkGateway Array required a list of IP addresses of gateways
let params = {
  'NetworkGateway': [
    {'IPv4Address': '192.168.10.1'}
  ]
};

device.services.device.setNetworkDefaultGateway(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetDeviceInformation command.

This method sends a GetSystemDateAndTime command.

This method sends a Reboot command.

This method sends a GetUsers command.

This method sends a CreateUsers command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
User Array required a list of users
+- Username String required Username
+- Password String required Password
+- UserLevel String required Either "Administrator", "Operator", "User", or "Anonymous"
let params = {
  'User' : [
    {'Username': 'test1', 'Password' : 'password', 'UserLevel': 'Administrator'},
    {'Username': 'test2', 'Password' : 'password', 'UserLevel': 'Operator'},
    {'Username': 'test3', 'Password' : 'password', 'UserLevel': 'User'}
  ]
};

device.services.device.createUsers(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a DeleteUsers command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
User Array required a list of users
+- Username String required Username
let params = {
  'User' : [
    {'Username': 'test1'},
    {'Username': 'test2'},
    {'Username': 'test3'}
  ]
};

device.services.device.deleteUsers(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a SetUser command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
User Array required a list of users
+- Username String required Username
+- Password String required Password
+- UserLevel String required Either "Administrator", "Operator", "User", or "Anonymous"
let params = {
  'User' : [
    {'Username': 'test1', 'Password' : 'password', 'UserLevel': 'Administrator'},
    {'Username': 'test2', 'Password' : 'password', 'UserLevel': 'Operator'},
    {'Username': 'test3', 'Password' : 'password', 'UserLevel': 'User'}
  ]
};

device.services.device.setUser(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a RetRelayOutputs command.

This method sends a GetNTP command.

This method sends a SetNTP command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
FromDHCP Boolean required true or false
NTPManual Object optional
+- Type String required "IPv4" or "IPv6"
+- IPv4Address String optional IPv4 address
+- IPv6Address String optional IPv6 address
let params = {
  'FromDHCP': false,
  'NTPManual': {'Type': "IPv4", 'IPv4Address': '192.168.10.1'}
};

device.services.device.setNTP(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetDynamicDNS command.

This method sends a GetZeroConfiguration command.

This method sends a GetServices command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
IncludeCapability Boolean required true or false
let params = {
  'IncludeCapability': true
};

device.services.device.getServices(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetServiceCapabilities command.


This object represents the ONVIF Media Service.

This method sends a GetStreamUri command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
Protocol String required "UDP", "HTTP", or "RTSP"
let params = {
  'ProfileToken': '2_def_profile6',
  'Protocol': 'UDP',
};

device.services.media.getStreamUri(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetVideoEncoderConfigurations command.

This method sends a GetVideoEncoderConfiguration command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ConfigurationToken String required a token of the configurationToken
let params = {
  'ConfigurationToken': '2_def_conf6'
};

device.services.media.getVideoEncoderConfiguration(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetCompatibleVideoEncoderConfigurations command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
let params = {
  'ProfileToken': '2_def_profile6'
};
device.services.media.getCompatibleVideoEncoderConfigurations(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetVideoEncoderConfigurationOptions command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String optional a token of the profile
ConfigurationToken String optional a token of the configuration
let params = {
  'ProfileToken': '2_def_profile6',
  'ConfigurationToken': '2_def_conf6'
};

device.services.media.getVideoEncoderConfigurationOptions(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetGuaranteedNumberOfVideoEncoderInstances command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ConfigurationToken String required a token of the configuration
let params = {
  'ConfigurationToken': '2_def_conf6',
};

device.services.media.getGuaranteedNumberOfVideoEncoderInstances(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetProfiles command.

This method sends a GetProfile command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
let params = {
  'ProfileToken': '2_def_profile6'
};

device.services.media.getProfile(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a CreateProfile command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
Name String required a name of the profile
Token String optional a token of the profile
let params = {
  'Name': 'TestProfile1',
  'Token': 'TestProfile1'
};

device.services.media.createProfile(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a DeleteProfile command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
Token String required a token of the profile
let params = {
  'ProfileToken': 'TestProfile1'
};

device.services.media.deleteProfile(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetVideoSources command.

This method sends a GetVideoSourceConfiguration command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ConfigurationToken String required a token of the configuration
let params = {
  'ConfigurationToken': '2_def_conf6'
};

device.services.media.getVideoSourceConfiguration(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetVideoSourceConfigurations command.

This method sends a GetCompatibleVideoSourceConfigurations command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
Token String required a token of the profile
let params = {
  'ProfileToken': '2_def_profile6'
};

device.services.media.getCompatibleVideoSourceConfigurations(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetVideoSourceConfigurationOptions command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String optional a token of the profile
ConfigurationToken String optional a token of the configuration
let params = {
  'ProfileToken': '2_def_profile6',
  'ConfigurationToken': '2_def_conf6'
};

device.services.media.getVideoSourceConfigurationOptions(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetMetadataConfiguration command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ConfigurationToken String required a token of the configuration
let params = {
  'ConfigurationToken': 'metadata1',
};

device.services.media.getMetadataConfiguration(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetMetadataConfigurations command.

This method sends a GetCompatibleMetadataConfigurations command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
let params = {
  'ProfileToken': '2_def_profile6'
};

device.services.media.getCompatibleMetadataConfigurations(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetMetadataConfigurationOptions command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String optional a token of the profile
ConfigurationToken String optional a token of the configuration
let params = {
  'ProfileToken': '2_def_profile6',
  'ConfigurationToken': 'Conf001'
};

device.services.media.getMetadataConfigurationOptions(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetAudioSources command.

This method sends a GetAudioSourceConfiguration command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ConfigurationToken String required a token of the configuration
let params = {
  'ConfigurationToken': 'AudioSourceConfig',
};

device.services.media.getAudioSourceConfiguration(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetAudioSourceConfigurations command.

This method sends a GetCompatibleAudioSourceConfigurations command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
let params = {
  'ProfileToken': '2_def_profile6'
};

device.services.media.getCompatibleAudioSourceConfigurations(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetAudioSourceConfigurationOptions command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String optional a token of the profile
ConfigurationToken String optional a token of the configuration
let params = {
  'ConfigurationToken': 'AudioSourceConfig'
};

device.services.media.getAudioSourceConfigurationOptions(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetAudioEncoderConfiguration command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ConfigurationToken String required a token of the configuration
let params = {
  'ConfigurationToken': 'AudioSourceConfig'
};

device.services.media.getAudioEncoderConfiguration(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetAudioEncoderConfigurations command.

This method sends a GetCompatibleAudioEncoderConfigurations command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
let params = {
  'ProfileToken': '2_def_profile6'
};

device.services.media.getCompatibleAudioEncoderConfigurations(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetAudioEncoderConfigurationOptions command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String optional a token of the profile
ConfigurationToken String optional a token of the configuration
let params = {
  'ProfileToken': '2_def_profile6',
  'ConfigurationToken': 'AudioSourceConfig'
};

device.services.media.getAudioEncoderConfigurationOptions(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a getSnapshotUri command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
let params = {
  'ProfileToken': '2_def_profile6'
};

device.services.media.getSnapshotUri(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This object represents the ONVIF PTZ Service.

This method sends a getNodes command.

This method sends a GetNode command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
NodeToken String required a token of the node
let params = {
  'NodeToken': 'PtzNode'
};

device.services.ptz.getNode(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetConfigurations command.

This method sends a GetConfiguration command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ConfigurationToken String required a token of the targeted PTZ configuration
let params = {
  'ConfigurationToken': 'PtzConf1'
};

device.services.ptz.getConfiguration(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetConfigurationOptions command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ConfigurationToken String required a token of the targeted PTZ node
let params = {
  'ConfigurationToken': 'PtzConf1'
};

device.services.ptz.getConfigurationOptions(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetStatus command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the targeted PTZ node
let params = {
  'ProfileToken': 'PtzConf1'
};

device.services.ptz.getStatus(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a ContinuousMove command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
Velocity Object required
+- x Float required Speed of pan (in the range of -1.0 to 1.0)
+- y Float required Speed of tilt (in the range of -1.0 to 1.0)
+- z Float required Speed of zoom (in the range of -1.0 to 1.0)
Timeout Intenger optional Timeout (seconds)
let params = {
  'ProfileToken': '2_def_profile6',
  'Velocity'    : {'x': -1, 'y': 0, 'z': 0},
  'Timeout'     : 1 
};

device.services.ptz.continuousMove(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a AbsoluteMove command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
Position Object required
+- x Float required Position of pan (The range depends on the profile)
+- y Float required Position of tilt (The range depends on the profile)
+- z Float required Position of zoom (The range depends on the profile)
Speed Object required
+- x Float required Speed of pan (in the range of -1.0 to 1.0)
+- y Float required Speed of tilt (in the range of -1.0 to 1.0)
+- z Float required Speed of zoom (in the range of -1.0 to 1.0)
let params = {
  'ProfileToken': cam['ProfileToken'],
  'Position'    : {'x': 0, 'y': 0, 'z': 0.003},
  'Speed'       : {'x': 1, 'y': 1, 'z': 1}
};

device.services.ptz.absoluteMove(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a RelativeMove command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
Translation Object required
           | `x` | Float    | required | Translation of pan (in the range of -1.0 to 1.0)
           | `y` | Float    | required | Translation of tilt (in the range of -1.0 to 1.0)
           | `z` | Float    | required | Translation of zoom (in the range of -1.0 to 1.0)

Speed | | Object | required | | x | Float | required | Speed of pan (in the range of -1.0 to 1.0) | y | Float | required | Speed of tilt (in the range of -1.0 to 1.0) | z | Float | required | Speed of zoom (in the range of -1.0 to 1.0)

let params = {
  'ProfileToken': '2_def_profile6',
  'Translation' : {'x': 0.1, 'y': 0.1, 'z': 0},
  'Speed'       : {'x': 1, 'y': 1, 'z': 1}
};

device.services.ptz.relativeMove(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a stop command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
PanTilt Boolean optional true or false
Zoom Boolean optional true or false
let params = {
  'ProfileToken': '2_def_profile6',
  'PanTilt': true,
  'Zoom': true
};

device.services.ptz.stop(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GotoHomePosition command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
Speed Float optional Speed in the range of 0.0 to 1.0
let params = {
  'ProfileToken': '2_def_profile6',
  'Speed': 0.5
};

device.services.ptz.gotoHomePosition(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a SetHomePosition command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
let params = {
  'ProfileToken': '2_def_profile6'
};

device.services.ptz.setHomePosition(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a SetPreset command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
PresetToken String optional a token of the preset
PresetName String optional a name of the preset
let params = {
  'ProfileToken': '2_def_profile6',
  'PresetName'  : 'PresetTest1'
};

device.services.ptz.setPreset(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GetPresets command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
let params = {
  'ProfileToken': '2_def_profile6'
};

device.services.ptz.getPresets(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a GotoPreset command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
PresetToken String required a token of the preset
Speed Object required
+- x Float required Speed of pan (in the range of 0.0 to 1.0)
+- y Float required Speed of tilt (in the range of 0.0 to 1.0)
+- z Float required Speed of zoom (in the range of 0.0 to 1.0)
let params = {
  'ProfileToken': '2_def_profile6',
  'PresetToken' : '12',
  'Speed'       : {'x': 1, 'y': 1, 'z': 1}
};

device.services.ptz.gotoPreset(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This method sends a RemovePreset command. The 1st argument params must be a hash object consisting of the properties as follows:

Property Type Required Description
ProfileToken String required a token of the profile
PresetToken String required a token of the preset
let params = {
  'ProfileToken': '2_def_profile6',
  'PresetToken' : '12'
};

device.services.ptz.removePreset(params).then((result) => {
  console.log(JSON.stringify(result['data'], null, '  '));
}).catch((error) => {
  console.error(error);
});

This module is based on the ONVIF specifications:


  • v0.1.7 (2018-08-14)
    • Newly added the lastResponse property to the OnvifDevice object for debug. This property is used to investigate SOAP parse error.
  • v0.1.6 (2018-08-13)
    • Fixed the bug of SOAP name space handling. (Issue #38)
  • v0.1.5 (2018-08-13)
  • v0.1.4 (2018-03-25)
    • Clarified the instruction of the installation in the README.md and Added the engines section to the package.json. (Pull Request #24)
    • Fixed the bug of the loop of SearchDomain. (Pull Request #23)
  • v0.1.3 (2018-02-11)
  • v0.1.0 (2017-08-30)
    • Rewrote all scripts to be modern coding style such as let, const, and Promise. All of the asynchronous methods now return a Promise object.
    • Dramatically improved the discovery processs.
    • Supported the devices which do not support the GetSystemDateAndTime command. In the earlier versions, the init method failed if the targeted device did not support the command. Now the init() method will work well with such devices.
    • The startDiscovery() and stopDiscovery() mehtods became deprecated.
    • Newly added the startProbe() and stopProbe() methods.
    • Appended a failure reason text to an Error.message parsing a SOAP message from a device.
    • Fixed bugs of the OnvifServicePtz.getNode(), OnvifServicePtz.getConfiguration(), and OnvifServicePtz.getConfigurationOptions() methods. The methods sent a wrong SOAP message.
    • Implemented the Speed parameter in the OnvifServicePtz.relativeMove() method.

The MIT License (MIT)

Copyright (c) 2016 - 2018 Futomi Hatano

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

node-onvif's People

Contributors

davidgatti avatar futomi avatar hawkeye64 avatar seudut avatar youkinjoh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-onvif's Issues

Callback when PTZ move is finished

I'm trying to move the camera and then take a snapshot, something like below:

const cameraDevice = new onvif.OnvifDevice( params );

cameraDevice
  .init()
  .then( () => {
    cameraDevice.services.ptz
      .absoluteMove( {
        ProfileToken: cameraDevice.getCurrentProfile().token,
        Position: { x: 0.5, y: -0.5, z: 0.1 },
        Speed: { x: 1, y: 1, z: 1 },
      } )
      .then( () => {
        console.log( 'Snap: this should only be called when PTZ has finished moving' );
      } )
  } )

However, I'm the promise for absoluteMove is resolving almost immediately, not when the camera has finished moving, like how I expected.

Anyone knows any workaround to this?

"profiles.forEach is not a function" exception

OnvifDevice.prototype._mediaGetProfiles = function(callback) {

....
profiles.forEach((p) => { <== exception

events.js:163
throw er; // Unhandled 'error' event
^

TypeError: profiles.forEach is not a function
at OnvifDevice._mediaGetProfiles.callback.services.media.getProfiles (g:\Nodeproject\onvif\node-onvif\lib\modules\device.js:385:12)
at OnvifServiceMedia.getProfiles.mOnvifSoap.requestCommand (g:\Nodeproject\onvif\node-onvif\lib\modules\service-media.js:312:3)
at OnvifSoap.requestCommand.callback._request.parse (g:\Nodeproject\onvif\node-onvif\lib\modules\soap.js:71:8)
at OnvifSoap.parse.mXml2Js.parseString (g:\Nodeproject\onvif\node-onvif\lib\modules\soap.js:39:3)
at Parser. (g:\Nodeproject\onvif\node-onvif\node_modules\xml2js\lib\xml2js.js:489:18)
at emitOne (events.js:96:13)
at Parser.emit (events.js:191:7)
at SAXParser.onclosetag (g:\Nodeproject\onvif\node-onvif\node_modules\xml2js\lib\xml2js.js:447:26)
at emit (g:\Nodeproject\onvif\node-onvif\node_modules\sax\lib\sax.js:640:35)

-> looks like profiles is not array but object.

with soap message below

"
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope"
xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:chan="http://schemas.microsoft.com/ws/2005/02/duplex"
xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:c14n="http://www.w3.org/2001/10/xml-exc-c14n#"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:wsc="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:xmime="http://tempuri.org/xmime.xsd" xmlns:xop="http://www.w3.org/2004/08/xop/include"
xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:wsrfbf="http://docs.oasis-open.org/wsrf/bf-2"
xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:wsrfr="http://docs.oasis-open.org/wsrf/r-2"
xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:tev="http://www.onvif.org/ver10/events/wsdl"
xmlns:trt="http://www.onvif.org/ver10/media/wsdl" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2"
xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" xmlns:tmd="http://www.onvif.org/ver10/deviceIO/wsdl"
xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:tns1="http://www.onvif.org/ver10/topics"
xmlns:ter="http://www.onvif.org/ver10/error">
SOAP-ENV:Header</SOAP-ENV:Header>
SOAP-ENV:Body
trt:GetProfilesResponse
<trt:Profiles token="profile1" fixed="true">
tt:Nameprofile1</tt:Name>
<tt:VideoSourceConfiguration token="vsrc1">
tt:NameVideoSource1</tt:Name>
tt:UseCount1</tt:UseCount>
tt:SourceTokenvsrc1</tt:SourceToken>
<tt:Bounds x="0" y="0" width="1280" height="720"></tt:Bounds>
</tt:VideoSourceConfiguration>
<tt:VideoEncoderConfiguration token="venc1">
tt:NameVideoEncoder1</tt:Name>
tt:UseCount1</tt:UseCount>
tt:EncodingH264</tt:Encoding>
tt:Resolution
tt:Width1280</tt:Width>
tt:Height720</tt:Height>
</tt:Resolution>
tt:Quality50</tt:Quality>
tt:RateControl
tt:FrameRateLimit30</tt:FrameRateLimit>
tt:EncodingInterval1</tt:EncodingInterval>
tt:BitrateLimit30</tt:BitrateLimit>
</tt:RateControl>
tt:H264
tt:GovLength30</tt:GovLength>
tt:H264ProfileBaseline</tt:H264Profile>
</tt:H264>
tt:Multicast
tt:Address
tt:TypeIPv4</tt:Type>
tt:IPv4Address0.0.0.0</tt:IPv4Address>
</tt:Address>
tt:Port0</tt:Port>
tt:TTL0</tt:TTL>
tt:AutoStartfalse</tt:AutoStart>
</tt:Multicast>
tt:SessionTimeoutPT60S</tt:SessionTimeout>
</tt:VideoEncoderConfiguration>
</trt:Profiles>
</trt:GetProfilesResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>"

The action requested requires authorization

Despite using correct URL and credentials (username + password), the connection to IPCam fails:

Error: Failed to initialize the device: Error: 400 Bad Request - The action requested requires authorization and the sender is not authorized
    at services.device.getDeviceInformation ([...]/node_modules/node-onvif/lib/modules/device.js:453:12)
    at promise.then.catch ([...]/node_modules/node-onvif/lib/modules/service-device.js:853:4)
    at process._tickCallback (internal/process/next_tick.js:68:7)

Sending a onvif request from browser

Is it possible to send a onvif request / response straight from the browser without going though node. I would like communicate staright with camera from the browser without going through node.js

Handle Digest On Fetch Snapshot Issue

When I access the snapshot URL through a browser the following digest is sent and works:

Digest username="root", realm="AXIS_WS_ACCC8E494578", nonce="/QcV7p11BQA=2e07815dfad0fe310a9c42609dc869e920fb0efc", uri="/onvif-cgi/jpg/image.cgi?resolution=1280x720&compression=30", algorithm=MD5, response="a873fc750b676f59586b8d758d8ac22e", qop=auth, nc=00000001, cnonce="1c8a3e9fb1c1b19b"

When the node-onvif encounters the same issue the following digest is sent an http status of 401 is returned:
{"date":"Tue, 11 Sep 2018 20:22:17 GMT","server":"Apache/2.4.27 (Unix) OpenSSL/1.0.2k","www-authenticate":"Digest realm="AXIS_WS_ACCC8E494578", nonce="t6fuOp51BQA=f644e559881cb59b13221e8f9b63747f39e342c7", algorithm=MD5, qop="auth"","content-length":"381","connection":"close","content-type":"text/html; charset=iso-8859-1"}

Different values - would expect the content to be similar. Any ideas?

Tim McClure

Discovery Packets can not be sent due to this._udp being null

For some reason, sending some discovery packets is taking a couple seconds before they actually go out and invoke the next one. This means if the discovery is stopped (via setTimeout) in between the packets, then this._udp will already be null. The next packet can not be sent and throws an (uncatchable) error ("TypeError: Cannot read property 'send' of null" at line 214) instead.
let send = () => {...} is simply missing a check if this._udp ist still set properly.

I think it can easily be reproduced by setting _DISCOVERY_WAIT smaller than _DISCOVERY_RETRY_MAX * _DISCOVERY_INTERVAL * 3.

The WebSocket connection was closed

Hi,

thanks for your help.
I now use:
node -v
v4.4.2

I am running on an rasspberry pi 3.

After starting and seeing the UI i get a POP up with:
Error
The WebSocket connection was closed. Check if the server.js is running.

The Server shows:
Listening on port 8880
HTTP : 200 OK : /
HTTP : 200 OK : /style.css
HTTP : 200 OK : /onvif.js

Do you have an idea?

Thanks,
Stefan

Xampp server

Hi do you work with xampp server? I could not run

can i snapshot multiple ip cam addrs by looping from array?

const onvif = require('node-onvif');
const fs = require('fs');

let yuhu=['http://192.168.57.11/onvif/device_service',
'http://192.168.57.12/onvif/device_service',
'http://192.168.57.13/onvif/device_service',
'http://192.168.57.14/onvif/device_service'
,'http://192.168.57.15/onvif/device_service']

for (i = 0; i < yuhu.length; i++) {

// Create an OnvifDevice object
let device = new onvif.OnvifDevice({
xaddr: yuhu[i],
user : 'admin',
pass : 'xxxx!!!'
});
// Initialize the OnvifDevice object
device.init().then(() => {
// Get the data of the snapshot
console.log('fetching the data of the snapshot...');
return device.fetchSnapshot();
}).then((res) => {
// Save the data to a file
fs.writeFileSync('s'+i+'.jpg', res.body, {encoding: 'binary'});
console.log('sDone!');
})
.catch((error) => {
console.error(error);
});
}

Add support for events

ONVIF supports events, such as motion and sound. Would it be possible to add support for these?

400 Bad Request

Hey there,

I am currently trying to control PTZ on a Reolink C1 Pro. I am able to control it using ptzMove() but neither services.ptz.gotoPreset() nor services.ptz.absoluteMove() works for me. Both throw Error: 400 Bad Request.

Please have a look at the following sample code:

let camInstance = new Cam.OnvifDevice({
    xaddr: 'http://192.168.0.1:8000/',
    user: 'admin',
    pass: 'administrator'
});

camInstance.init().then(() => {
    let currentProfile = camInstance.getCurrentProfile();
    camInstance.services.ptz.gotoPreset({
        ProfileToken: currentProfile.token,
        PresetToken: 'test',
        Speed: { x: 1, y: 1, z: 1 }
    }).then((result) => {
        console.log(JSON.stringify(result['data'], null, '  '));
    }).catch((error) => {
        console.error(error);
    });
}).catch((error) => {
    console.error(error);
});

The sample above always ends with the following trace:

Error: 400 Bad Request
    at IncomingMessage.<anonymous> (/Users/julian/WebstormProjects/cctv-bridge/node_modules/node-onvif/lib/modules/soap.js:130:16)
    at IncomingMessage.emit (events.js:215:7)
    at endReadableNT (_stream_readable.js:1183:12)
    at processTicksAndRejections (internal/process/task_queues.js:80:21)

Any hints appreciated!

Table layouts on readme page

Hi @futomi,

Thanks for this great piece of software!

A very minor issue with the tables on the README page, that are a bit messed up:

image

I have it on Chrome, Edge and Firefox. So it seems not to be a browser specific layout problem.

Kind regards,
Bart Butenaers

RTSP instead HTTP

Hello

This project is very amazing and I ran it without any problems in my IP Camera
My all devices support Onvif,

The question is
My IP & Analog cameras are connected to XVR device, Can I access one of XVR channel through XVR ip address?
Or
Can I use rtsp url instead of http in this project?

Another question is:
My devices have two streaming quality (main & extra). Can I choose lower quality?

Thanks a lot

async problem?

I am using your library to fetch a snapshot from multiple cameras at once and save them to the local filesystem.
Sometimes it is just working fine, sometimes I have the problem that the same image from the same camera is saved in the wrong file.

I am assuming I've did something wrong with the async function or something similar, so I am looking for help here. :)

const` onvif = require('node-onvif');
const fs = require('fs');

async function kamera_screenshot(ip) {
    let device = new onvif.OnvifDevice({
        xaddr: "http://" + ip + "/onvif/device_service",
        user : 'admin',
        pass : 'admin'
    });
    device.init().then(() => {
        return device.fetchSnapshot().then((res) => {
            fs.writeFile("/tmp/" + ip + ".jpg", res.body, {encoding: 'binary'}, function (fd, err) {
                if (err) throw err;
            });
        });
        });
    return;
}

kamera_screenshot("192.168.0.1");
kamera_screenshot("192.168.0.2");
kamera_screenshot("192.168.0.3");
kamera_screenshot("192.168.0.4");

So, in this example, I have two pictures from camera 192.168.0.1 in the 192.168.0.1.jpg AND 192.168.0.2.jpg (or any other combination)

Event service usage

Hi Futomi (@futomi),

I need your help once again ...
My (OnVif) IP camera's have a PIR detector, so I would like to receive events as soon as motion is detected.

Did some reading about it and it seems that WS notifications are being used in OnVif to accomplish this. Can I use perhaps your service-events.js for this purpose?

When I get the available services from my camera, it 'looks' to me that the event service is available:

image

Thanks in advance for your time !!

Bart Butenaers

Quick fix Missing RateControl element in Tenvis cameras

Hi there,

Just wanted to let you know that Tenvis cameras are not sending RateControl data that becomes a reason for your lib to fire an error.

I've fixed the issue through this (code from line 636 and further):

if (p.VideoEncoderConfiguration.RateControl === undefined)
                    {
                        p.VideoEncoderConfiguration.RateControl = {
                            FrameRateLimit: 10,
                            BitrateLimit: 10
                        };
                    }

                    profile['video']['encoder'] = {

[ERROR] Failed to initialize the device: Error: Failed to run the GetProfiles() method: Error: socket hang up

Getting this error with a Hikvision camera using this code:

#!/usr/bin/env node

var onvif = require('./lib/node-onvif.js');

// Create an OnvifDevice object
var device = new onvif.OnvifDevice({
  xaddr: 'http://some.host:8080/onvif/device_service',
  user : 'username',
  pass : 'password'
});

// Initialize the OnvifDevice object
device.init((error) => {
  if(error) {
    console.log('[ERROR] ' + error.message);
  } else {
    console.log('The OnvifDevice object has been initialized successfully.');
    // Do something.
  }
});

PTZ Test failed on D-Link DCS 5222L B

1) PTZ Test on D-Link DCS 5222L B

  • using node v6.12.2 (npm v3.10.10) or
  • using node v7.10.0 (npm v5.6.0):

"Manufacturer": "D-Link Corporation",
"Model": "DCS-5222LB",
"FirmwareVersion": "2.14.04",

PTZ test non passed. It returns Done without moving/tilting/zooming the camera.

XML in 192.168.x.x/onvif/device_service:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:xmime5="http://www.w3.org/2005/05/xmlmime" xmlns:xop="http://www.w3.org/2004/08/xop/include" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:tptz="http://www.onvif.org/ver20/ptz/wsdl" xmlns:tev="http://www.onvif.org/ver10/events/wsdl" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" xmlns:timg="http://www.onvif.org/ver20/imaging/wsdl" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:ter="http://www.onvif.org/ver10/error" xmlns:tns1="http://www.onvif.org/ver10/topics" xmlns:wstop="http://docs.oasis-open.org/wsn/t-1">
<SOAP-ENV:Body>
<SOAP-ENV:Fault SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring>
End of file or no input: Operation interrupted or timed out
</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

2) ONVIF Network Camera Manager

  • works using node v4.8.7 (npm v2.15.11)
  • works using node v6.12.2 (npm v3.10.10)
  • does not work using node v7.10.0 (npm v5.6.0):
Socket.prototype.__proto__ = EventEmitter.prototype;
TypeError: Cannot read property 'prototype' of undefined

setVideoEncoderConfiguration missing

Hi

This library has almost all the capability typically required for onvif usage, except I don't see setting configurations such as setVideoEncoderConfiguration in the code or documentation.

TypeError: Cannot read property 'Width' of undefined

Using this example code below and of course changing the IP and login info

const onvif = require('node-onvif');

// Create an OnvifDevice object
let device = new onvif.OnvifDevice({
  xaddr: 'http://192.168.10.10:80/onvif/device_service',
  user : 'admin',
  pass : '123456'
});

// Initialize the OnvifDevice object
device.init().then((info) => {
  // Show the detailed information of the device.
  console.log(JSON.stringify(info, null, '  '));
}).catch((error) => {
  console.error(error);
});

I get the folowing response from a camera

The OnvifDevice object has been initialized successfully.
{
  "Manufacturer": "Honeywell",
  "Model": "H4D2F",
  "FirmwareVersion": "42.0.7",
  "SerialNumber": "00000",
  "HardwareId": "DM368"
}

when I try with a newer version of the camera I get this

Error: Failed to initialize the device: TypeError: Cannot read property 'Width' of undefined
    at services.media.getProfiles (/home/user/node_modules/node-onvif/lib/modules/device.js:464:12)
    at promise.then.catch (/home/user/node_modules/node-onvif/lib/modules/service-media.js:392:4)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)

I was wondering what info might be needed to help this issue.

Thanks

fetchSnapshot: Content-Type multiplart/replace

Hi,

some cameras return non image/jpeg content-types for snapshots, for example "multipart/x-mixed-replace;boundary=ipcam264". The content fetched by node.js is still jpeg.
I would like to suggest an option to either ignore the content-type and/or disable the check, or to add a small hack checking for a jpeg marker (ff d8 ff ...) and overwrite the content type with image/jpeg then.

I could provide a pull request if needed

Error: Network Error: socket hang up

Hello,
I want tu use your code with a sricam camera.

When I test the code for use preset or 'homeposition', I have an error :

The code :

// Create an OnvifDevice object
let device = new onvif.OnvifDevice({
  xaddr: 'http://x.x.x.x/onvif/device_service',
  user : 'user',
  pass : 'password'
});

// Initialize the OnvifDevice object
device.init().then(() => {
  console.log("Connect");
  // The OnvifServicePtz object
  let ptz = device.services.ptz;
  if(!ptz) {
    throw new Error('Your ONVIF network camera does not support the PTZ service.');
  }
  // The parameters for the gotoHomePosition() method
  let profile = device.getCurrentProfile();
  let params = {
    'ProfileToken': profile['token'],
    'Speed'       : 1
  };
  // Send the GotoHomePosition command using the gotoHomePosition() method
  return ptz.gotoHomePosition(params);
}).then((result) => {
  console.log(JSON.stringify(result.data, null, '  '));
}).catch((error) => {
  console.log("> error");
  console.error(error);
});

The response :

$ node preset_test.js  2
myArgs:  [ '2' ]
Connect
> error
Error: Network Error: socket hang up
    at ClientRequest.req.on (/home/user/node_modules/node-onvif/lib/modules/soap.js:168:11)
    at ClientRequest.emit (events.js:182:13)
    at Socket.socketOnEnd (_http_client.js:425:9)
    at Socket.emit (events.js:187:15)
    at endReadableNT (_stream_readable.js:1092:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)

Thanks for your help.
Julien
(from France)

Enhancement: Consider passing in a port with address

All the ONVIF cameras I have worked with allow the User to change the port to access the device. I think it would be great if the port (optional: default 80) could be passed in at the same time as the address.

name space handling (xmlns:)

I think this library suffers from the same problem that onvif had; namely that when the camera is sending xmlns: name spaces with all of its elements, the xml to json parser is not doing the right thing. My camera outputs something like this:

<tt:Uri xmlns:tt="http://www.onvif.org/ver10/schema">http://169.254.72.162:8081/web/snapshot.jpg</tt:Uri>

Which produces json that looks like this:

    "snapshot": {
      "_": "http://169.254.72.162:8081/web/snapshot.jpg",
      "$": {
        "xmlns:tt": "http://www.onvif.org/ver10/schema"
      }
    },

If I apply the same "fix" as described in the linked ticket, namely:

soap = soap.replace(/xmlns(.*?)=(".*?")/g,'');
mXml2Js.parseString(soap, opts, (error, result) => {
...
});

in lib/modules/soap.js::parse(), then the problem goes away and I get this json:

    "snapshot": "http://169.254.72.162:8081/web/snapshot.jpg",

I realize this is just how xml2js works, but higher level apps (like samples/manager) break when the camera is sending xmlns:

fetchSnapshot socket hang up error

Hi,
i'm testing node-onvif with a Vitorcam CA-31.

All works properly (discovery, get profile, change profile, get info ...) but fetchSnapshot fails with

{ Error: socket hang up
at createHangUpError (_http_client.js:331:15)
at Socket.socketOnEnd (_http_client.js:423:23)
at emitNone (events.js:111:20)
at Socket.emit (events.js:208:7)
at endReadableNT (_stream_readable.js:1064:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9) code: 'ECONNRESET' }

it seems as cam close connection, what's happening ?

How to set Default videoSourceConfiguration and videoEncoderConfiguration

Hi,
I'm pretty new to onvif protocol. I have the following requirements:-

  1. Change default video source config (I hope setVideoSourceConfiguration may be helpful here), where I want to change the camera's default resolution and FPS. (For streaming and everything else).

  2. I want to record camera streaming at multiple resolutions (let's say 1920x1080, 720x480, etc) and FPS, how to do that? (I guess I need to create a new profile with required videoEncoderConfiguration). Is that right?

  3. I want to change the camera's default contrast, saturation, hue, and other images params and for a particular profile. Which method do I need to use?

Thanks in advance.

SOAPの応答の`Scopes`に属性が指定されていた場合エラーとなる。

SOAPの応答のXML内で、Scopesに属性が指定されていることがある。

<SOAP-ENV:Envelope (略) xmlns:wsd="http://schemas.xmlsoap.org/ws/2005/04/discovery" (略)>
(略)
<wsd:Scopes MatchBy="http://schemas.xmlsoap.org/ws/2005/04/discovery/rfc3986">(略)

この場合、
https://github.com/futomi/node-onvif/blob/42449b0e31c147d3463e8d9408489aa447effdfb/lib/node-onvif.js#L59
probe_match['Scopes']xml2jsの仕様によりオブジェクトを返すため、
scopes = probe_match['Scopes'].split(/\s+/);splitで落ちる。

Wrong error format when password or username is wrong

When password or username is wrong i get this error:

Error: Failed to initialize the device: Error: [object Object]
    at services.device.getCapabilities (/home/ano/programmering/rtp test/node_modules/node-onvif/lib/modules/device.js:396:12)
    at promise.then.catch (/home/ano/programmering/rtp test/node_modules/node-onvif/lib/modules/service-device.js:120:4)
    at process.internalTickCallback (internal/process/next_tick.js:77:7)

I would like to get more info then Error: [object Object].
The fix can be found here. Please tell me if this breaks something else! If it does not, then i think this should be fixed.

Can not start server.js, SyntaxError: Unexpected token >

node ./server.js

/home/pi/node_modules/node-onvif/sample/manager/server.js:118
onvif.startDiscovery((device) => {
^
SyntaxError: Unexpected token >
at Module._compile (module.js:439:25)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:906:3

node -v
v0.10.29

npm -v
1.4.21

Thank you,
Stefan

Image Profile Setting

Hi,
I successfuly use your fantastic project to control the PTZ of 2 cameras: RLC 423 and SD22204T GN
But my Dahua SD22204T GN hasnt got IR Led so i've got a night profile, a day profile and a normal profile.
These profile control brightness, contrasts etc.
But i can't see them with your project.
I tried all commands but nothing seems to give me these image settings.
I've found this but it isn't supported with your package
https://www.onvif.org/specs/srv/img/ONVIF-Imaging-Service-Spec-v210.pdf
Have you got an idea
Thank You.
Jules

Failed to initialize the device

Hello,

I got this:
Failed to initialize the device: Error: Networ Error: socket hang up at services.media.getProfiles (node_modules\node-onvif\lib\modules\device.js:464:12) at promise.then.catch (node_modules\node-onvif\lib\modules\service-media.js:392:4) at<anonymous>

I try to launch example of Create OnvifDevice object:

'const onvif = require('node-onvif');
// Create an OnvifDevice object
let device = new onvif.OnvifDevice({
xaddr: 'http://IP:PORT/onvif/device_service',
user : 'xxxx',
pass : 'xxxx'
});

// Initialize the OnvifDevice object
device.init().then((info) => {
// Show the detailed information of the device.
console.log(JSON.stringify(info, null, ' '));
}).catch((error) => {
console.error(error);
});'

It gives me this error when I try to launch it on Windows Server 2012, but when I launch it on my pc (Win 10), it works fine. I tried to turn off firewall, make in and outbound rules, with no success. The camera has public is behind router and has forwarded ports.
Any help is appreciated.

EDIT So it turned out, that it doesn't work on my local pc either. It was connecting to my LAN IP cam, even though I typed IP address of public IP camera.
EDIT2 It is getting stranger, and stranger. When I my local IP cam connected to router, the app can connect both to local, and public IP cam (I can tell by Hardware ID), but when I disconnect local IP camera, it suddenly can't connect to public camera. When I try snapshot app and type public IP it gets snapshot...from local IP camera.

RTSP backchannel for two way audio

Hi, y'all!

I'm doing some preliminary research into building out a CCTV system for my home using ONVIF capable cameras. I'm looking at adding a few cameras that support 2-way audio, like an intercom.

I'm new to this, but it seems that the cameras that support ONVIF and two way audio (like an intercom) do so using a RTSP backchannel.

It's my understanding correct?

Is this possible with the current library? If not, is it something you'd be interested in seeing in a PR?

Sample doesn't support two cameras

I have two IP cameras and can have them both running at the same time through their own GUIs. However, I cannot connect to both from the sample app in this repo. If I'm connected to A, and then open up a new tab and connect to B, the connection to B now works, but A is frozen. Likewise if I reconnect A. Any ideas on what might cause this? (Websockets?) Is it designed to support multiple, or only one?

[Question] Exception catching

Hi. I'm building a nodeJS application using node-onvif to track some cameras. I have a situation where I'm looping over a couple of times over device.fetchSnapshot() in order to parse the results for my scenario.

From time to time, I'm getting an error that I cannot track down.

ERROR Error: Uncaught (in promise): 11552024 - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.

My code is written Promise style:

this.device.fetchSnapshot() .then(async (res) => { // my code });

I tried adding a catch statement, but the scenario is the same. I tried using try {} catch, but it seems to just hang if this error is thrown.

Unfortunately it doesn't happen all the time (I reckon from time to time, due to the looping over fetchSnapshot() the camera doesn't return a response or something breaks, thus the error.)

Any ideas ?

Multiple ethernet/wifi cards prevent device discovery

Hello, my laptop has three ethernet connections: 1 wired, 1 wifi, and 1 wifi direct to a miracast display. If the miracast connection is active, device discovery fails: it reports 0 devices found. However, if I disable the miracast display, which removes the wifi direct connection, discovery works properly and reports the ONVIF devices present on the network.

Is there a way to list the ethernet connections which are present, and then to specify which connection to use for sending the multicast/discovery packets?

`startDiscovery`と`stopDiscovery`を定期的に実行するとErrorが発生する

setInterval(function() {
  var onvif = require('node-onvif');
  onvif.startDiscovery(function(info) {
    var xaddr = info.xaddrs[0];
    var device = new onvif.OnvifDevice({
      xaddr: xaddr
    });
    device.init(function(error) {
      if(error) {
        console.log('[ERROR] ' + error.message);
      } else {
        console.log(device.address);
      }
    });
    setTimeout(function() {onvif.stopDiscovery();}, 3000);
  });
},5000);

上記コードを実行すると、数回はアドレスを取得するのですが、
2~3回繰り返すと以下のようなエラーで異常終了します。

dgram.js:520
    throw new Error('Not running'); // error message from dgram_legacy.js
    ^

Error: Not running
    at Socket._healthCheck (dgram.js:520:11)
    at Socket.close (dgram.js:414:8)
    at Onvif.stopDiscovery ([proj dir]/node_modules/node-onvif/lib/node-onvif.js:160:12)
    at Timeout._onTimeout ([proj dir]/index.js:15:34)
    at tryOnTimeout (timers.js:228:11)
    at Timer.listOnTimeout (timers.js:202:5)

404 not found on fetchSnapshot

Hi,

When I request a snapshot I get 404 Not found error as below (I'm using only example provided in the doc) :

fetching the data of the snapshot...
Error: 404 Not Found
    at IncomingMessage.res.on (/home/zombitch/Developpement/thor/node_modules/node-onvif/lib/modules/device.js:207:13)
    at emitNone (events.js:110:20)
    at IncomingMessage.emit (events.js:207:7)
    at endReadableNT (_stream_readable.js:1047:12)
    at _combinedTickCallback (internal/process/next_tick.js:102:11)
    at process._tickCallback (internal/process/next_tick.js:161:9)

Regard,
Zombitch

Error: Cannot find module 'node-onvif'

Hi,
when i execute node, i get the following issue:

server01 ~ # node /tmp/node-onvif/sample/manager/server.js
module.js:550
    throw err;
    ^

Error: Cannot find module 'node-onvif'
    at Function.Module._resolveFilename (module.js:548:15)
    at Function.Module._load (module.js:475:25)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/tmp/node-onvif/sample/manager/server.js:8:10)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
server01 ~ # 

node-onfiv is installed:

server01 ~ # npm list
[email protected] /root
├─┬ [email protected]
│ └─┬ [email protected]
│   ├── [email protected]
│   ├── [email protected]
│   ├─┬ [email protected]
│   │ ├── [email protected]
│   │ ├── [email protected] deduped
│   │ ├── [email protected]
│   │ ├── [email protected]
│   │ ├── [email protected]
│   │ ├─┬ [email protected]
│   │ │ └── [email protected] deduped
│   │ └── [email protected]
│   └── [email protected]
└─┬ [email protected]
  ├── [email protected]
  └── [email protected]

server01 ~ #

Where is my fail?

Multiple Network Interfaces

I have a machine with multiple network interfaces.

For UDP Datagrams the Node Documentation states for socket.bind([port][, address][, callback]):
"If address is not specified, the operating system will attempt to listen on all addresses. "

Notices the word "attempt." They may "attempt" to do that in the case of your software implementation, but it appears their "attempt" failed.

If I modify the code in Onvif.prototype.startProbe = function(callback) {

To make it look like this:

this._udp.bind(null, "10.1.254.55", () => {
			this._udp.removeAllListeners('error');

Where the desired interface is at "10.1.254.55", the software can find cameras, etc.

We could plagiarize the "onvif" package (their _udp socket is called socket) to provide options for discovery/probe (note that Array.prototype.some probably only calls bind once, but the end result is that the socket is indeed bound to an interface that seems to work):

if (options.device) {
	var interfaces = os.networkInterfaces();
	// Try to find the interface based on the device name
	if (options.device in interfaces) {
		interfaces[options.device].some(function(address) {
			// Only use IPv4 addresses
			if (address.family === 'IPv4') {
				socket.bind(null, address.address);
				return true;
			}
		});
	}
}

Note that the "10.1.254.55" above is the value of address.address from the other onvif package.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.