DIY Remote Camera using Raspberry Pi, Pi Camera, and Socket.IO

There may be situations where you may have to take pictures remotely and view them. With a Raspberry Pi single-board computer, Pi Camera and Socket.IO server, creating a DIY remote camera has never been easier.

To create this remote camera system, you need the following:

  1. A Raspberry Pi device running Raspbian
  2. A Pi Camera
  3. A cloud platform such as Heroku

The Architecture

The diagram below shows you the architecture of the system.

The Pi Camera would be connected to the Raspberry Pi device. The Raspberry Pi will be running a node app that would be listening to a socket.IO server. A client who wants to take a picture would simply request the Socket.IO server for a picture. The server will then forward the request to the Raspberry Pi device. The Raspberry Pi device would then take a picture, and send it to the server. The server would send the picture to the client.

Why can’t I request a picture directly from the Raspberry Pi?

To be able to request a Raspberry Pi device directly for a picture, the device should be running a server. Even though this is very much possible with a Raspberry Pi device, the problem arises with communication. To send a request to the Raspberry Pi device, we should be able to uniquely identify the device. If you are only planning to deploy this setup within your home, then this would be as simple as connecting your Raspberry Pi device to the local network and assigning it a static IP address.

But what if you want to take pictures through the internet? You will have to purchase a static IP address from your ISP to assign it to the Raspberry Pi, and as you may have already known, this is extremely costly. By using a server that runs on a cloud platform, we will have an endpoint that is uniquely identifiable even on the internet. Since our server runs a simple app, we can make use of free cloud platforms like Heroku to host our app.

Why Socket.IO and not http requests?

You can request the server for a picture by making an http call. But how will the server request the Raspberry Pi device for a picture through an http call? If the Raspberry Pi device is to service http requests, it should run an http server, but we already know running a server on a remote device is not feasible. Of course, we can have the Raspberry Pi device poll the server through http calls to see if there are new requests so that it can take pictures and send them through http calls but this won’t be real time and may cause unnecessary server load.

What Socket.IO does is to create a tunnel over http in a manner similar to TCP/IP sockets on the transportation layer. This helps clients establish connections with a server and keep the connection active so that both the clients and the server can request information from one another.

The Server

Let’s get started with coding our server application. This is a node.js app and does two things.

  1. Creates a Socket Server and listens to and services requests from clients
  2. Requests pictures from the Raspberry Pi device and forwards the picture to the relevant client

To build this app, we need to install two modules viz., express and socket.io

npm install --save express

npm install --save socket.io

Now, let’s initialize both modules.

const PORT = process.env.PORT || 5000
var app=require('express')();
var socket=require('socket.io')(
    app.listen(PORT,()=>{
        console.log("Server is listening on ",PORT);
    })
);

We are instantiating the express module and passing the listen method of it into the socket.io function to create a socket. We have a socket now, with which we would listen to connections.

Socket.IO is event-driven. You emit an event and have a listener listen to that event. When a client connects to the server, a connection event is emitted to both the client and the server. Our server needs to listen to the connection event.

We can create namespaces and have sockets connect to a particular namespace. This helps us separate the concerns within our app.

In our app, we create a namespace called camera and have the clients connect to that namespace.

socket.of('camera').on("connection", io=>{
    console.log("Client connected!",io.id);
})

We use the of method to specify the namespace on which we need to listen to new connections. The on method creates a listener. The first argument refers to the event and the next one is a callback function—which accepts the connecting socket as an argument—that would be called every time an event is received. Now, each time a socket connects to our server, our console will print a message along with the id of the socket.

Leave a Reply

placeholder="comment">