Introduction: Intel IoT Edison Web Controlled LED

This instructable demonstrates how to combine the Arduino IDE with node.js, available by default on Edison's Yocto linux, in order to control Arduino elements remotely, through a web interface. To put it simply, you can press a button from any browser to switch a LED on/off on your Intel® Edison Arduino Board. As a plus, your board will display on an LCD screen the IP address from where the command came.

What you need:

  1. Intel® Edison Arduino Board

  2. Grove Starter Kit Plus V2.0 (only if you want IP information displayed on the board)

  3. Having successfully installed the Arduino IDE on your computer, updated to the latest Yocto Image and a working terminal connection to the board. For a detailed how-to, you can check my other instructable

    https://www.instructables.com/id/Touch-me-Edison-ba...

  4. The Grove RGB LCD should be connected to one of the I2C ports of the Grove shield. The LED controlled is the built-in Pin13 LED.

I am thankful to Instructables and Intel for providing me the hardware used in this project (I was one of the 250 lucky ones!)

Step 1: Inter Process Communication, Mutex Etc

If you are interested to know how Intel does it, you can check the following article

https://software.intel.com/en-us/blogs/2014/09/22/...

In it, the author explains what IPC (Inter Process Communication) is in linux, how mutex (mutually exclusive) variables work and also provides a code sample, both for the arduino part and a native C++ process.

It is a good starting point, if you want to look under Edison's hood, but, honestly, much of the information provided is not easy to digest. Apart from the digestibility thing, I don't get why somebody would want to write half the code in Arduino, a more or less easy, beginner friendly language and the other part in hard-core C++, employing mutex variables and threads and all. Why not write everything in C/C++ then?

Anyway, one thing is important to know when making arduino sketches communicate with other linux processes: Create a file in the /tmp/ directory and make both sketch and the other process read and write to this file. /tmp/ is mapped to memory so read and write operations are fast, and you don't wear out your flash memory. In Intel's example, the file created is binary (not human readable).

I have tried to simplify stuff a bit: There is still some C code involved, but one can easily tailor the arduino code part to his/her needs. What's more, the communication succeeds through a human readable file (words! not zeros and ones!): /tmp/arduino.txt The advantage is that you can easily use whatever scripting language you prefer from the linux side, be it node.js, python, perl, php etc and still be able to check (that is, read) what your programs send to each other. I've put mutex away, too: The arduino sketch reads the /tmp/arduino.txt file and ignores it if it's not complete (if it doesn't file an OK string in the end). This is more than enough for most of the use cases of an arduino sketch.

For this project, the file /tmp/arduino.txt consists of four lines:

Line 1: "true" or "false" strings. Instructs arduino to switch the LED on or off

Line 2: the IP from where the last switch command originated.

Line 3: "OK" if the arduino sketch does not encounter this OK, the file is ignored till the next loop.

Line 4: left empty

Step 2: The Arduino Part

Create the following two files in you Arduino IDE:

text_reader.c contains the function readFile(), which reads the file /tmp/arduino.txt and returns its contents. If no file has been created yet, it returns null.

/*
text_reader.c Part of "Intel IoT Edison web controlled LED demo" Copyright 2014 Pavlos Iliopoulos, techprolet.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include <stdio.h>
#include <stdlib.h> #include <string.h> #include <malloc.h> char* readFile (){ FILE *f = fopen("/tmp/arduino.txt", "rb"); if (f != NULL) { fseek(f, 0, SEEK_END); long pos = ftell(f); fseek(f, 0, SEEK_SET); char *bytes = (char*)malloc(pos); fread(bytes, pos, 1, f); fclose(f); return bytes; } else { return NULL; } }

web_button.ino is the main arduino sketch. It reads the string provided by readFile(), splits it with the line change delimiter ("\n"), parses the data and switches the LED on or off, accordingly.

/*
web_button.ino Part of "Intel IoT Edison web controlled LED demo" Copyright 2014 Pavlos Iliopoulos, techprolet.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include <Wire.h> #include "rgb_lcd.h" #include "text_reader.c" const char * delimiter = "\n"; char * str; char * pch; rgb_lcd lcd; int ledPin = 13; bool ledStatus = false; bool lastLedStatus = false; bool stringIsOk = false; String remoteIp; void setup() { //Initialize serial and wait for port to open: Serial.begin(9600); pinMode(ledPin, OUTPUT); digitalWrite(ledPin,LOW); // set up the LCD's number of columns and rows: lcd.begin(16, 2); lcd.setRGB(0,0,0); // Print a message to the LCD. lcd.print("Remote IP:"); delay (1000); } void loop() { // put your setup code here, to run once: str = readFile(); pch = strtok (str, delimiter); if (pch != NULL){ ledStatus = (String(pch) == "true"); pch = strtok (NULL, delimiter); remoteIp = String (pch); pch = strtok (NULL, delimiter); stringIsOk = String (pch) == "OK"; //read the rest of the string, you can omit this while ((pch != NULL)) { pch = strtok (NULL, delimiter); } } if (stringIsOk && (ledStatus!=lastLedStatus)){ pinMode(ledPin, OUTPUT); digitalWrite(ledPin,ledStatus); Serial.println (ledStatus); //first, empty the screen from the old address lcd.setCursor(0, 1); lcd.print(" "); lcd.setRGB(0,0,ledStatus?255:00); lcd.setCursor(0, 1); lcd.print(remoteIp); Serial.println(remoteIp); Serial.println("-------------------"); lastLedStatus = ledStatus; } delay(100); }

Step 3: The Node.js Part

Using the terminal connection, create the following node.js file:

web_button.js (please download the attached file, code was probably broken after pasting here)

Updates /tmp/arduino.txt when a user sends a command from the web interface.

/*
web_button.js Part of "Intel IoT Edison web controlled LED demo" Copyright 2014 Pavlos Iliopoulos, techprolet.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ var http = require('http'); var url = require('url'); var fs = require('fs'); var arduinoFileName = "/tmp/arduino.txt"; function sendResponse(ledOn, remoteIP, response) { if (remoteIP != null){ console.log('\nRequest to switch LED ' + (ledOn?'On':'Off')); console.log('from ' + remoteIP); var fileStream = fs.createWriteStream(arduinoFileName); fileStream.write(ledOn + "\n" + remoteIP + "\nOK\n"); fileStream.end(); response.writeHead(302, { 'Location': '/' }); response.end(); } else { response.writeHead(200, { 'Content-Type': 'text/html' }); response.write('<!DOCTYPE html><html lang="en"><head>'); response.write('<meta charset="utf-8">'); response.write('<meta http-equiv="refresh" content="30" />'); response.write('<title>LED switch</title>'); if (!ledOn) { response.write ('<style>body{background-color:black;color:white;}</style>'); } response.write('</head>'); response.write('<body><h1>LED is now '+(ledOn?'On':'Off')); response.write('</h1>'); if (ledOn){ response.write('<a href="/off">Switch off!</a>'); } else { response.write('<a href="/on">Switch on!</a>'); } response.write('</body></html>'); response.end(); } } function processRequest(request, response) { "use strict"; var pathName = url.parse(request.url).pathname; var remoteIP = request.headers['X-Forwarded-For'] == undefined?request.connection.remoteAddress:request.headers['X-Forwarded-For']; if (pathName == "/on") { sendResponse (true, remoteIP, response); } else if (pathName == "/off") { sendResponse (false, remoteIP, response); } else if (pathName == "/") { fs.exists(arduinoFileName, function (exists) { if (exists){ fs.readFile(arduinoFileName, function(err,data){ if (!err){ console.log('\nStored data:\n' + data); var storedData = data.toString().split("\n"); sendResponse ((storedData[0] == "true"), null, response); }else{ console.log(err); } }); } else { sendResponse (false, null, response); } }); } else { response.end(); } } http.createServer(processRequest).listen(8080); console.log("Server running at port 8080");

Run the script with the following command:
# node web_button.js

The web is then accessible at http://youredisonaddress:8080/

That's it! Have fun with your web controlled Edison!