
Remote smartphone control with Node.js and Socket.io
- Transfer
- Tutorial
It would be fun to use your smartphone as a control panel, right? In fact, it does not look very difficult. You do not even need to be able to write large applications, as there is a browser that supports opening sockets. In this short lesson, we will use Node.js and Socket.io to control the presentation that is running on a computer using a phone.
There are many cool HTML5 libraries for creating presentations, but not one of them is provided for our idea. In this regard, we will use Reveal.js - the library will work with animation and respond to pressing a keyboard or touching the screen of a smartphone.
We will not develop a separate management interface. Instead, let's synchronize the open presentation on both devices. This will allow you not only to see the mobile version of the presentation, but also to understand which of the slides is currently active.
Our idea is simple - Reveal.js will pass the number of the current slide through a URL in the form of a hash (for example, example.com/#/1 ). Then we will send this hash to all other connected devices, which will scroll through the presentations automatically. In this regard, anyone can ruin everything by the elementary opening of an arbitrary slide, which will lead to turning over on all devices. In order to avoid this, we will set a password and will require its input to connect.
It’s worth mentioning that Reveal.js already has an API, and we can use it for synchronization, but the technique of changing and sending a hash is simpler, so let's use it.

Our presentation
You can run the example on your computer or deploy it with a provider like Heroku. The first option is simpler, but you need to install node.js and npm. The second involves installing the heroku toolbelt and registering with the system.
Read more about this process here . If you use a different provider, the last steps may vary.
Stop talking, let's take a look at the code! We have only two JavaScript files - app.js for the back-end and script.js for the browser. You can run the application in Node.js 0.10+ or in io.js.
In the server side, we use express and socket.io . Its task is to listen for socket.io events and send responses to them. With express.static, we display files from public folders. The file public / index.html contains the presentation itself. It is processed automatically through express.static, so there is no need to specify “/” in the address.
app.js
And here is the JavaScript for the front-end, which listens for the hashchange event and sends a socket.io message to the server.
public / assets / js / script.js
Our smartphone remote is ready! I hope you find this useful and enjoyable.
Download Demo Code
There are many cool HTML5 libraries for creating presentations, but not one of them is provided for our idea. In this regard, we will use Reveal.js - the library will work with animation and respond to pressing a keyboard or touching the screen of a smartphone.
We will not develop a separate management interface. Instead, let's synchronize the open presentation on both devices. This will allow you not only to see the mobile version of the presentation, but also to understand which of the slides is currently active.
Idea
Our idea is simple - Reveal.js will pass the number of the current slide through a URL in the form of a hash (for example, example.com/#/1 ). Then we will send this hash to all other connected devices, which will scroll through the presentations automatically. In this regard, anyone can ruin everything by the elementary opening of an arbitrary slide, which will lead to turning over on all devices. In order to avoid this, we will set a password and will require its input to connect.
It’s worth mentioning that Reveal.js already has an API, and we can use it for synchronization, but the technique of changing and sending a hash is simpler, so let's use it.

Our presentation
Running example
You can run the example on your computer or deploy it with a provider like Heroku. The first option is simpler, but you need to install node.js and npm. The second involves installing the heroku toolbelt and registering with the system.
To run locally:
- Download the archive with the code;
- Make sure node.js is installed ;.
- Unzip the downloaded file;
- Open a terminal and go to the folder with the extracted files;
- Run
npm install
to install the libraries; - Launch the application with the command
node app.js
; - Open http: // localhost: 8080 and enter the password (“ kittens “ by default);
- Open http: // <local computer address> on the phone and enter the same phrase;
- Rejoice!
To run in Heroku:
- Download the archive with the code;
- Unzip it;
- Open a terminal and go to the folder;
- Create a repository and first commit;
- Create an application in Heroku;
- Run
git push heroku master
; - Open the application at its address and enter the password “ kittens ” (default).
Read more about this process here . If you use a different provider, the last steps may vary.
The code
Stop talking, let's take a look at the code! We have only two JavaScript files - app.js for the back-end and script.js for the browser. You can run the application in Node.js 0.10+ or in io.js.
In the server side, we use express and socket.io . Its task is to listen for socket.io events and send responses to them. With express.static, we display files from public folders. The file public / index.html contains the presentation itself. It is processed automatically through express.static, so there is no need to specify “/” in the address.
app.js
// This is the server-side file of our mobile remote controller app.
// It initializes socket.io and a new express instance.
// Start it by running 'node app.js' from your terminal.
// Creating an express server
var express = require('express'),
app = express();
// This is needed if the app is run on heroku and other cloud providers:
var port = process.env.PORT || 8080;
// Initialize a new socket.io object. It is bound to
// the express app, which allows them to coexist.
var io = require('socket.io').listen(app.listen(port));
// App Configuration
// Make the files in the public folder available to the world
app.use(express.static(__dirname + '/public'));
// This is a secret key that prevents others from opening your presentation
// and controlling it. Change it to something that only you know.
var secret = 'kittens';
// Initialize a new socket.io application
var presentation = io.on('connection', function (socket) {
// A new client has come online. Check the secret key and
// emit a "granted" or "denied" message.
socket.on('load', function(data){
socket.emit('access', {
access: (data.key === secret ? "granted" : "denied")
});
});
// Clients send the 'slide-changed' message whenever they navigate to a new slide.
socket.on('slide-changed', function(data){
// Check the secret key again
if(data.key === secret) {
// Tell all connected clients to navigate to the new slide
presentation.emit('navigate', {
hash: data.hash
});
}
});
});
console.log('Your presentation is running on http://localhost:' + port);
And here is the JavaScript for the front-end, which listens for the hashchange event and sends a socket.io message to the server.
public / assets / js / script.js
$(function() {
// Apply a CSS filter with our blur class (see our assets/css/styles.css)
var blurredElements = $('.homebanner, div.reveal').addClass('blur');
// Initialize the Reveal.js library with the default config options
// See more here https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
history: true // Every slide will change the URL
});
// Connect to the socket
var socket = io();
// Variable initialization
var form = $('form.login'),
secretTextBox = form.find('input[type=text]');
var key = "", animationTimeout;
// When the page is loaded it asks you for a key and sends it to the server
form.submit(function(e){
e.preventDefault();
key = secretTextBox.val().trim();
// If there is a key, send it to the server-side
// through the socket.io channel with a 'load' event.
if(key.length) {
socket.emit('load', {
key: key
});
}
});
// The server will either grant or deny access, depending on the secret key
socket.on('access', function(data){
// Check if we have "granted" access.
// If we do, we can continue with the presentation.
if(data.access === "granted") {
// Unblur everything
blurredElements.removeClass('blurred');
form.hide();
var ignore = false;
$(window).on('hashchange', function(){
// Notify other clients that we have navigated to a new slide
// by sending the "slide-changed" message to socket.io
if(ignore){
// You will learn more about "ignore" in a bit
return;
}
var hash = window.location.hash;
socket.emit('slide-changed', {
hash: hash,
key: key
});
});
socket.on('navigate', function(data){
// Another device has changed its slide. Change it in this browser, too:
window.location.hash = data.hash;
// The "ignore" variable stops the hash change from
// triggering our hashchange handler above and sending
// us into a never-ending cycle.
ignore = true;
setInterval(function () {
ignore = false;
},100);
});
}
else {
// Wrong secret key
clearTimeout(animationTimeout);
// Addding the "animation" class triggers the CSS keyframe
// animation that shakes the text input.
secretTextBox.addClass('denied animation');
animationTimeout = setTimeout(function(){
secretTextBox.removeClass('animation');
}, 1000);
form.show();
}
});
});
It's Slideshow Time!
Our smartphone remote is ready! I hope you find this useful and enjoyable.
Download Demo Code