Introduction: Easy Node.JS + WebSockets LED Controller for Raspberry Pi
Hi,
in this instructable, I'll show you how to create a lightweight and incredibly responsive web server with WebSockets.
I'll use it to control a LED using an Arduino but the concept can be applied to many other projects.
Since this project does not use any on-board peripherals, it will work with just about any computer, but running it on a low power machine like the Raspberry PI makes sense for continuous operation.
Why use Node.Js or WebSockets?
There are a few tutorials on the web that show how to use a Raspberry Pi for home automation, but many use php and simple http requests to send data back to the server. This is fine for simply switching on and off some lights but quickly reaches it's limitations when you want to run code server-side or if you want bidirectional communication.
Node.Js allows you to write programs in JavaScript and the vast amount of community-made libraries enables you to write very intricate programs in just a few lines of code.
Websockets have a few advantages over simple http requests:
- Speed: A normal http request has to establish a connection before any transactions can happen which takes a lot of time. A websocket is always open and ready to send or receive data.
This means that the lag can be as low as your ping, so just a millisecond or two in most cases - Bidirectional: Websockets allow data to be sent in both directions, this also means that the server can trigger events in the client.
Step 1: Setting Up the Environment
Installing Node.JS
Node recently released the new version 4.0.0 which comes with a ARM build (http://blog.wia.io/installing-node-js-v4-0-0-on-a-...):
wget https://nodejs.org/dist/v4.0.0/node-v4.0.0-linux-armv7l.tar.gz
tar -xvf node-v4.0.0-linux-armv7l.tar.gz cd node-v4.0.0-linux-armv7l sudo cp -R * /usr/local
Creating your project
mkdir ~/node_led cd ~/node_led mkdir public
create your project folder and a folder that contains static webpages
Installing libraries
npm install express npm install socket.io npm install serialport
Be sure to do this is the node_led folder or use the '-g' flag to install the libraries globally.
express: http server wrapper
socket.io: WebSockets library
serialport: Serial port wrapper
Step 2: Prepare the Arduino
Upload this code to your Arduino:
void setup()
{
Serial.begin(115200); }
void loop()
{ while(!Serial.available()); //wait until a byte was received analogWrite(3, Serial.read());//output received byte }
and connect an LED with a current-limiting resistor to D3 (image shows D10, there is no difference if you use the correct pin in your code).
The code just waits for a byte from the serial stream and sets the PWM level of D3 accordingly.
Now you can connect the Arduino to the Pi via USB and correct the serial port name in main.js.
To find the assigned serial port you can use this command:
ls /dev | grep ttyACM
Instead of a single LED you can connect any peripheral you can imagine to the Arduino. Just to name a few ideas:
-LED stips (maybe RGB, the code can easily be adjusted for 3 sliders)
-Motors / fans
Naturally, both require a transitor to handle the higher current and voltage as shown in the third image. The flyback diode is only necessary for inductive loads such as motors, solenoids or relays.
Step 3: Writing the Server Script
Create a new file called 'main.js' in the node_led folder, it will contain all the code that is necessary for running the server. Use your favorite text editor (I prefer Notepad++ with the NppFTP plugin).
Set up the webserver and websocket server
express = require('express'); //web server
app = express();
server = require('http').createServer(app);
io = require('socket.io').listen(server); //web socket server server.listen(8080); //start the webserver on port 8080
app.use(express.static('public')); //tell the server that ./public/ contains the static webpages
Open the serial port
var SerialPort = require("serialport").SerialPort
var serialPort = new SerialPort("/dev/ttyACM0", { baudrate: 115200 });
Define the WebSocket behavior
var brightness = 0; //static variable to hold the current brightness
io.sockets.on('connection', function (socket) { //gets called whenever a client connects
socket.emit('led', {value: brightness}); //send the new client the current brightness
socket.on('led', function (data) { //makes the socket react to 'led' packets by calling this function
brightness = data.value; //updates brightness from the data object
var buf = new Buffer(1); //creates a new 1-byte buffer
buf.writeUInt8(brightness, 0); //writes the pwm value to the buffer
serialPort.write(buf); //transmits the buffer to the arduino
io.sockets.emit('led', {value: brightness}); //sends the updated brightness to all connected clients
}); });
this is all the required code to run the web- and websocket-server, you can add the line 'console.log("running");' to indicate that the startup procedure has finished.
Step 4: Add the Static Html Content
in the 'public' folder, add following files:
index.html
when I paste html code into instructables, it automatically renders it as part of the page, so I made the file available on pastebin: http://pastebin.com/jJ9L0RF8
style.css
body { text-align: center; margin-top: 50px; background: #50D0A0; } input[type=range]{ -webkit-appearance: none; width: 80%; } input[type=range]::-webkit-slider-runnable-track { height: 10px; background: #ddd; border: none; border-radius: 3px; } input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; border: none; height: 32px; width: 32px; border-radius: 50%; background: goldenrod; margin-top: -12px; } input[type=range]:focus { outline: none; } input[type=range]:focus::-webkit-slider-runnable-track { background: #ccc; }
this stylesheet is optimized for webkit browsers such as Google Chrome or the chromium browser.
The website will work just fine without it, but it looks much nicer with.
The website should also render and work fine on most smartphones and tablets (tested with Chrome).
Step 5: Run the Server
go back into 'node_led' folder and run this command:
nodejs main.js
Now you can visit the website under [raspberry pi IP]:8080
If you visit the site with multiple clients simultaneously, the sliders will move synchronized on all clients.
The LED's brightness should follow the slider with little to no lag at all
Step 6: Conclusion
With Node.Js you can create websites and services with very little code or background knowledge.
Until three days ago, I despised JavaScript as a language and had never used it before. I'm just blown away by the simplicity and the possibilities of Node.Js.
If you want to learn more, here are some websites that might help you:
If you liked this instructable, please consider giving me a vote in one of the contests I participated in, thank you!

Participated in the
First Time Author Contest

Participated in the
Raspberry Pi Contest
57 Comments
Question 3 years ago
Do you have an example where you are controlling 3 leds with 3 different sliders? I can't seem to get the code going for all 3 leds
6 years ago
hi,i am using intel galileo gen 2 and using intel xdk as IDE but i am not able to run the code since socket.io is not installed in the board.the command
npm install socket.io
gives error- npm command not found.
pls tell me how do i install npm.
7 years ago
Awesome tutorial! I'd like to be able to control multiple pins on the Arduino with multiple sliders on the Pi. I've tried tweaking the code but I'm not quite sure how to get it working. Anyone have an example using multiple pins?
Thanks
Rich
Reply 6 years ago
Johnny 5 and firmata will allow you to use multiple pins, or you could create different sliders and have each slider transmit a character to indicate which pin to use then you could use case and switch statements or if/else statements based on the transmitted character.
http://blog.ricardofilipe.com/post/getting-started-arduino-johhny-five
6 years ago
Is it possible to do the same with a jquery slider.ui instead of html slider?
I mean this great feature to change the slider value on smartphone and for example see changes on PC.
7 years ago
Having trouble installing npm serialport on RaspberryPi 3 (raspian pixel). Error says failed at serialport@4.0.1 install script node-pre-gyp install --fallback-to-build.
This is most likely serialport package....
How do I fix this?
Reply 7 years ago
Have you had any luck getting it to work? I am having the same issue...
Reply 7 years ago
you should ask this question over at their github:
https://github.com/EmergingTechnologyAdvisors/node...
7 years ago
Hi,
When I run npm -v, node -v, nüm install express or anything else relating to this I got a "Segmentation fault"
Any idea why?
Reply 7 years ago
Hi,
I don't know what could cause this, your guess is as good as mine.
https://github.com/nodesource/distributions/issues... looks like you're not the only one with this error.
If you do get it to work, let us know in case someone else has the same issue
Reply 7 years ago
that has to do with the wheezy version of raspbian.
I manage to get nodejs through this link
http://blog.blakesimpson.co.uk/read/41-install-nod...
and for npm just a simple apt-get install npm
(and I had to remove the stuff unpacked before)
I still have to see if everything work fine, but at least I have nodejs and npm working. I will get a try tomorrow....
Reply 7 years ago
I still had some issues running npm install express, but I managed to solver it:
I had to execute the command below:
However, that will make npm install packages over an insecure HTTP connection. If you can, you should stick with
instead to install over HTTPS.
Reply 7 years ago
thanks!
7 years ago
hi there thank you very much for the tutorial :D, i waned to ask if this be done with out an arduino direct from the GPIO pins?
Reply 7 years ago
Glad you like it! You can absolutely use a rpi-gpio library and do away with the arduino. I used the arduino as an additional abstraction layer because I'm using an odroid C1 (great board, but lacks the good library support that the raspberry pi offers)
Reply 7 years ago
hi martin thanks for the replay how will i add rpi-gpio to the java code what part of your code should i change with the gpio code ?
Reply 7 years ago
you only need to replace the serial write function with the set pwm (probably not the actual name) function
7 years ago
Dear,
Great project, but I'd like to expand this to an 8 channel ac dimmer. The hardware is no problem. I saw in one of your solutions something like:
but i can't make anything out of it. Could you be more specific. I'm not that familiar with java nor html.
Grz
Bart
7 years ago on Introduction
OK, its spring break so now I have time to work out this project. Now when I create the node_led folder, do I create it inside the /usr/local/ nodejs folder or just create it in the home folder then npm install everything inside node_led <- I would rather install everything -g globally...
Reply 7 years ago
you can put the node_led folder whereeveryou want (and where you have write permissions :D)
if you want you can install all modules globally, it should run just as well.