Raspberry Pi, Camera and Node.js – Live Streaming with Websockets #IoT5 min read

A few days ago Bala Kolluru has reached out to me asking if we can control a Raspberry Pi camera module using Web browser, so he can view a live stream from any HTML5 powered device. I was intrigued by this idea and wanted to give it a try.

In this post, we will see how we can implement a system that can “stream” a video from our pi to a browser. The completed system would look like

Pretty sweet right! I am able to see my aquarium from any where and check on my only gold fish. This can be extended to do anything.

For instance, you can hook the camera up pointing at the front door, as soon as someone rings the bell, you can see who is at the door by opening the video stream URL in your mobile/tablet/computer and confirm if you need to wear pants to open the door.

So let us see how we can build such an awesome multi-purpose system.

You can find the complete code for this system here.

Prerequisites

If you are new to Raspberry pi and have not yet installed Node.js on it, I would recommend going through Getting Started with Raspberry pi and Node.js.

If you are new to electronics devices and circuits, I would recommend going through the video lectures from All About Circuits.

Components needed

  1. 1 – Raspberry pi B+
  2. 1 – Raspberry pi camera

If you have not already set up the camera module, please follow this.

Understanding MJPEG

Based on what I have googled and understood, there is no straight forward way of streaming the live video from the camera module to a web browser.

After going through a few similar solutions, I kind of sort of decided that MJPEGs are the way to go when dealing with Live streaming from the Pi.

MJPEG is Motion JPEG. You can know more about MJPEG in the below video

In this post we are not really using MJPEG from a technology standpoint, but we are using a similar principle.

The idea is that we keep clicking pictures using the camera say for every 100ms and then save it to the same file. And then we keep sending the same image to the client as it changes every time.

This is really not the best of solutions, but it kind of gets the job done. I am looking for other alternatives too and will update this post as it goes.

Building the system

So, the idea is very simple, we will have a web server setup on the Pi. When we get a request to start the stream, we will trigger a child process in node that will start capturing the picture, once for every 100ms.

Then we have a file watcher on that image file and whenever the file changes, we trigger the client to load the new image.

We are using Web Sockets to emit and act on the events accordingly.

Now, login to your pi via ssh – terminal/putty. As soon as you ssh into pi, you will be landing inside the /home/pi folder. We will create a new folder here named node_programs. And inside this folder, we will be maintaining all our programs. Run

mkdir node_programs

To step inside that folder, run

cd node_programs

For this post, we will create a new folder named liveStreaming and will step inside this folder. Run

mkdir liveStreaming && cd liveStreaming

Note : You can run multiple commands separated by a &&.

First we will initialize a new node project here. Run

npm init

Fill it up as applicable.

Now, we will install express and socket.io modules on our pi. Run

npm install express socket.io --save

Once they are installed, create a new file named index.js. And we will open the same in the nano editor. Run

nano index.js

Paste the below code into the nano editor

Things to notice

Line 1 – 6 : Essential requires

Line 8 : Cache spawn method on child_process

Line 9 : Global proc variable that we store the spawned process

Line 11 : Make the stream folder as a static folder

Line 14 : Default route that will dispatch the index.html

Line 18 : Global sockets object. This will store all the connected sockets

Line 22 : When a client connects to the server, a new socket will be created. This is store in the global variable.

Line 25 : We delete the disconnected client from the global object and if there are no more clients we will stop the streaming (power saving)

Line 36 : We start the streaming on start-stream event.

Line 42 : We start the server

Line 56 : If the capturing is already started, we will not re-init the same. And then emit the last saved image to the client

Line 62 : If the capturing is not started, we will start a new child process and then spawn it with raspistill command. And then register a watch on the file which changes. And whenever the file changes we emit a URL to all the connected clients.

Note : The _t param on the image is to avoid caching

Argument to the raspistill command

  • -w : width 640px
  • -h : height 480px
  • -o : output file ./stream/image_stream.jpg
  • -t : Timeout before the camera stops capturing
  • -tl – Time Limit between captures 100ms

A simple Express/Socket IO server

Let us save the file now. To save the program, press (ctrl+x). This will ask you to save the file. Press Y and press enter key to complete the operation.

Now we will create a new folder named stream at the root of the liveStreaming folder. This is where our image will be saved.

Finally the Websocket client

Things to notice

Line 28 : Init sockets

Line 29 : When there is new image saved, liveStream event will be broadcasted. And then we will fetch the image.

Line 34 : We start streaming when a user clicks on the Start button. If the video has already started by another user, we simply hide the button and show the last saved image.

Line 51 : The Image tag

That is it! save the file as we did above and then we will start the node server. Run

node index.js

And then access the port 3000 on your Raspberry pi port. My pi runs on 192.168.2.2, so my URL would be

http://192.168.2.2:3000

Click on start camera and Bam!! You should see the live feed.

As mentioned earlier it is a big laggy and buggy. You can tweak  -tl – Time Limit between captures to < 50ms and see how it works for you.

Hope this post gave you an ideas as how to “stream” a video from your pi camera to the browser.


Thanks for reading! Do comment.
@arvindr21