Foscam control via bootstrap

I just got a Foscam FI9821W V2 with pan/tilt control for cheap. Thought I’d try it out at the office. It’s was intriguing for a few reasons:

  • HD (whatever that means)
  • Pan Tilt controls.
  • “Night Vision Mode”

So okay.. I got it in the mail and fired it up. Seemed to work, but right away I noticed that their software totally sucks. You can do basic configuration via the browser, but you need IE to do pan/tilt control, and even in IE the picture is screwed up. I managed to get a good video stream over RTSP using VLC but since I run linux, I have to fire up a virtual machine running windows every time I want to control the camera.

There are a couple very basic Android apps that almost worked, but they were flaky – so I started looking around and found out the camera has an HTTP API you can use to control it. Here’s the docs:

Foscam HD Camera API

This is great, I can just bootstrap/jquery up my own interface.. so I did.. a single HTML file that I can basically control and call a couple preset positions I set with the POS IE interface.

This is my layout. You could make it much more complex and functional if you wanted.
This is my layout. You could make it much more complex and functional if you wanted.

First off, call a couple libs so I can build this out quickly:

<!DOCTYPE html>
<html>
 <head>
<title>Webcam</title>  
<style type="text/css">
 body { 
    text-align:center;
    background-color:#000000;
    color: #fff;
 }
 </style>
 <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
 <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet">
 <link rel="stylesheet" href="https://cdn.jsdelivr.net/bootstrap/3.3.0/css/bootstrap-theme.min.css">

All API commands require a user/pass, so I build an ‘operator’ user in the camera’s setup, and then set the user/pw in javascript along with the camera’s URL. I opened a port in my router, and I use Noip.com’s DDNS service so I can refer to the camera by URL.  You’ll need to get this working your own way, or by IP if you’re just going to use the local network.  Notice the ‘?callback=?’ at the end of the URL. This tells jQuery that it should do a JSONP request, and not normal AJAX. This is because for me at least, the camera is on a seperate URL than my web page, and AJAX won’t work normally without setting up some extra security stuff. JSONP will make a call to any URL, so I had to go this route. For details check this page out.

var url="https://<camera url/ip>/CGIProxy.fcgi?callback=?";
var user="user";
var pw = "pass";

Then I know I’m going to be making a lot of the same calls using jQuery, so I setup a quick function for sending commands:

function command(settings)
{
	settings['usr'] = user;
	settings['pwd'] = pw;
	jQuery.getJSON(url, settings).done(function(data) {
		console.log(jQuery.parseXML(data));
	});
}

One thing to note, is that getJSON never calls the ‘done’ code. I think this is because it’s expecting a JSONP style response, and the camera doesn’t give it. Doesn’t really matter though since I’m not reading from the camera, just telling it stuff to do.  But basically I can call this, and it automatically adds my user/pw to whatever command I need, and away I go.

Since the ptzGotoPresetPoint command was used a lot, I made a function for this too:

function moveTo(pos) {
	command({
		cmd: 'ptzGotoPresetPoint',
		name: pos
	});
}

// So now I can just do:
moveTo('myLocation');

Another thing I noticed, was that the move commands will start the camera moving, but not in increments. For example, if I issue ‘MoveUp’ to the camera, it’ll just start panning up, until it hits the limit of the axis. I wanted to be able to do this in small increments, so I made a function to move a bit, wait then stop.

function stopMov() {
	setTimeout(function() {
	command({
		cmd: 'ptzStopRun'
	});
	}, 150); // stop after 150 miliseconds. This seemed about right. You can change this. 
}

So my actual events from the buttons look like this example for move up:

jQuery('#up').on('click', function() {
	command({
		cmd: 'ptzMoveUp'
	});
	stopMov();
});

The actual video is RTSP which isn’t supported well by browsers, so I just used the snapshot command in an image tag. I use a bit of Javascript to refresh this periodically:

function qrefresh() {
	refresh(); // do the actual refresh
	// now schedule another refresh based on the value from our textfield. 
	setTimeout(function () { 
		qrefresh();
	}, jQuery('#refresh').val() * 1000); 
}
// start it going
setTimeout(function () { 
	qrefresh();
}, 5000);
// update the image based on a timestamp. 
function refresh() {
	d = new Date();
	jQuery("#image1").attr("src", url+"cmd=snapPicture2&usr="+user+"&pwd="+pw+"&t="+d.getTime());
}

Then I just built out a quick layout using bootstrap. This means it’ll still work on my phone if I need it to. You could do this pretty easily in regular HTML too.  Here’s the whole page in a Gist.

Let me know if anyone does something cool with this.

 

UPDATE: Here’s the format for the RTSP stream if anyone wants it:

rtsp://<hostname/IP address>:<port>/videoMain

Like or share:

10 comments on “Foscam control via bootstrapAdd yours →

  1. Great article,I recently created a hybrid web app in AngularJS/HTML to connect to FOSCAMs and control them. But one problem i’ve run into is using javascript to search for devices on my network and connect with the device using P2P or by setting a static IP and DDNS. In your example you just manually enter the ip address and port, but i’m trying to make it simpler for users to connect locally and then remain connected on an outside network without having to set up DDNS and possibly port forwarding on their router. I would like the user to just scan the QR code for the P2P id and have the javascript search the network for the device. FOSCAM provides an SDK for iOS and has a searchDev() and getDevList() to obtain and add device information
    before accessing devices, but i need those methods in javascript so i dont have to write in native ios.Any ideas on javascript to search for devices on a network based on a P2P id and connect on submit?

    1. You can launch a series of ajax requests across the subnet and wait until you get an expected reply. I believe (I’d have to check) that you get a 401 unauthorized, most other addresses will give you 500, 404 or just not reply.

      Just loop through and create a decent callback function to deal with the responses properly, and register all proper responses on the network. I have no idea how fast this would be but since ajax calls are asynchronous, you could do several in parallel, so it might not be bad.

      Thanks for the response! If you get your AngularJS app running and want to share, please post a github link here! I’d love to check it out.

  2. Hi! I am working with a Foscam FI9826P and I have seen your article. It has been very helpful to me. I wanted to comment you something, I have used your code to refresh snapshots, but in my case it just loads only one snapshot. It seems as if the cam is blocked, because I send some other URL commands and it does not responds. Do you have any hint of what could be wrong? thank you in advance, great article!

  3. No. I have seen that it works only with refreshing times higher tan 1,3s. If I ask it to refresh every 1.3s or less I have the issue that I told you.

    1. I’ve seen it fail after a while when I have the page open for long periods of time. If you’re doing a lot of refreshes, it might kill their little webserver.

      I usually have good luck with a 1 second refresh time though. It works for an hour or more, I usually don’t run it for more than that.

      Too bad we can’t embed rtsp streams in the web page.

      The other alternative is if you have a linux box, you can set up motion, and it can then provide you a mjpeg stream. Supposedly the Foscam will do this, but I could never get it to work.

      http://www.lavrsen.dk/foswiki/bin/view/Motion/WebHome

  4. I have observed that the Time To First Byte is about 1,22-1,28s, I think that it is the problem, but then I don’t understand why it loads the first image 

  5. I also use the MJPEG streams as an alternative, but it spends about 10-15Mbps and it is a big handicap, and we can not configure the parameters of this stream, that is fixed to VGA, and 15fps. I am trying to find an alternative and thought that a snapshots loop could be one. I think I’ll keep researching some way to embed a rtsp stream in the browser, but Chrome now does not allow NPAPI plugins anymore.

  6. I’m having very mixed results with this.Despite the URLs working perfectly if you place it directly into the browser, when I use the script to assign them to the image via this script.- If I’m on the LAN, only 1 type of camera is showing up. The others show broken images- If I’m on the WAN, nothing shows upAgain, If I plug the URL directly into the browser, all works just fine. The script seems to be problematic.

Leave a Reply

Your email address will not be published. Required fields are marked *