agsh / onvif

ONVIF node.js implementation
http://agsh.github.io/onvif/
MIT License
699 stars 240 forks source link

Connect to multiple devices #171

Closed Motoralfa closed 4 years ago

Motoralfa commented 4 years ago

Hi! I recently install this plugin and im trying to use with express. I want to manipulate the camera from mobile app as client. The problem is that i need to connect multiple devices at the same time, depend of the client and available ip for his user. I want to know if it is possible and if there is some way to handle this situation. I recently was trying to return the cam instance as response, but later i cannot get uri.

var onvif = require('onvif');
var app = require('express')();
var bodyParser = require('body-parser')
var port = 3000

app.use(function (req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  next();
});
app.use(bodyParser.json());

app.get('/connect',(req,res)=>{
    var body = req.body;
    var camData = body['camData'];
    return new onvif.Cam({
        hostname: camData.ip,
        port:camData.port,
        username: camData.username,
        password: camData.password
      }, function(err) {
        return res.send(this);
      });
})
app.post('/getUri',(req,res)=>{
    var body = req.body;
    var cam = body['cam'];
    console.log(cam);
    cam.getStreamUri({}, function(err, stream) {
        return res.send(stream);
    })
})
app.listen(port, console.log);

Another question is, do i need to connect in every request? is the only solution? Im really noob at working with ONVIF protocol, so sorry if im not explaining well, but thank you anyway!

chriswiggins commented 4 years ago

Hi @Motoralfa,

You won't be able to return the ONVIF object as a response to your HTTP client. That object needs to stay on the server.

I suggest you connect to the camera when the user requests it, store it in a local in-memory object on your server, and then use that when you want to control it.

agsh commented 4 years ago

Agree with @chriswiggins Smth like this:

let cam;
app.get('/connect',(req,res)=>{
    var body = req.body;
    var camData = body['camData'];
    cam = new onvif.Cam({
        hostname: camData.ip,
        port:camData.port,
        username: camData.username,
        password: camData.password
    }, function(err) {
      if (err) {return res.send(err.message);}
      res.send('connected');
    });
})
app.post('/getUri',(req,res)=>{
    var body = req.body;
    console.log(cam);
    if (!cam) {
      return res.send('not connected');
    }
    cam.getStreamUri({}, function(err, stream) {
        return res.send(stream);
    });
})
Motoralfa commented 4 years ago

Hi @Motoralfa,

You won't be able to return the ONVIF object as a response to your HTTP client. That object needs to stay on the server.

I suggest you connect to the camera when the user requests it, store it in a local in-memory object on your server, and then use that when you want to control it.

@chriswiggins @agsh Thank you so much for take a time to reply! I understand the situation, i also tried to use variable before, but in this case, isnt it the cam's variable the same for all users? Let me explain, an user has access to camera x.x.x.x and execute the connect method. Inmediately after that, another user with access to camera y.y.y.y execute the connect method again. If the first user try to getUri, he will receive the uri for the y.y.y.y cam, right? Or, do i need to store camera in an json object with id? Really sorry if i cannot explain well, i dont natively talk english. And thank you again.

agsh commented 4 years ago

@Motoralfa you can use a Map in which you can store different cams and in the /getUri endpoint send also info which cam you want. Or store in the user's session this info. Or something else... I don't know your current case. Simple example with host-port info:

...
let cams = {};

app.get('/connect',(req,res)=>{
   ...
    cams[`${camData.ip}-${camData.port}`] = new onvif.Cam({
        hostname: camData.ip,
        port: camData.port,
        username: camData.username,
        password: camData.password
    }, function(err) {
      if (err) {return res.send(err.message);}
      res.send('connected');
    });
});
...
app.post('/getUri', (req,res)=>{
    var body = req.body;
    const camData = body.camData;
    const camInfo = `${camData.ip}-${camData.port}`;
    const cams = cams[camInfo]; 
    if (!cam) {
      return res.send('not connected');
    }
    cam.getStreamUri({}, function(err, stream) {
        return res.send(stream);
    });
})
Motoralfa commented 4 years ago

@Motoralfa you can use a Map in which you can store different cams and in the /getUri endpoint send also info which cam you want. Or store in the user's session this info. Or something else... I don't know your current case. Simple example with host-port info:

...
let cams = {};

app.get('/connect',(req,res)=>{
   ...
    cams[`${camData.ip}-${camData.port}`] = new onvif.Cam({
        hostname: camData.ip,
        port: camData.port,
        username: camData.username,
        password: camData.password
    }, function(err) {
      if (err) {return res.send(err.message);}
      res.send('connected');
    });
});
...
app.post('/getUri', (req,res)=>{
    var body = req.body;
    const camData = body.camData;
    const camInfo = `${camData.ip}-${camData.port}`;
    const cams = cams[camInfo]; 
    if (!cam) {
      return res.send('not connected');
    }
    cam.getStreamUri({}, function(err, stream) {
        return res.send(stream);
    });
})

Thank you so much @agsh . Seriously this help me a lot, i was thinking in implement something like that but i didnt know if it was right. Now i have an idea about how to face the situation! 👍