SparkFun Inventor's Kit for Edison Experiment Guide

Pages
Contributors: Shawn Hymel
Favorited Favorite 4

Experiment 6: RGB LED Phone App

Introduction

In the previous experiment, we used WebSockets to create a connection from a client (browser) to the server (Edison). With them, we can send data back and forth to control a simple LED.

In this experiment, we introduce the concept of Web Apps, which are applications designed to run in a browser. Specifically, we will create an HTML application intended for a smartphone. Because the application is written in HTML, it should be capable of running on most phone operating systems, including iOS, Android, and Windows Phone/Mobile.

NOTE: The examples in this part require a smartphone or tablet capable of running HTML5. Feel free to skip this exercise if you do not have access to a phone or do not wish to run applications on one.

Parts Needed

In addition to the Edison and Block Stack, you will need the following parts:

  • 1x Breadboard
  • 1x RGB LED
  • 3x NPN Transistor
  • 3x 1kΩ Resistor
  • 3x 100Ω Resistor
  • 12x Jumper Wires
Using the Edison by itself or don't have the kit? No worries! You can still have fun and follow along with this experiment. We suggest using the parts below:
Resistor Kit - 1/4W (500 total)

Resistor Kit - 1/4W (500 total)

COM-10969
$8.95
189
Breadboard - Self-Adhesive (White)

Breadboard - Self-Adhesive (White)

PRT-12002
$5.50
48
Female Headers

Female Headers

PRT-00115
$1.75
8
Break Away Headers - Straight

Break Away Headers - Straight

PRT-00116
$1.75
20
LED - RGB Diffused Common Cathode

LED - RGB Diffused Common Cathode

COM-09264
$2.25
2
Jumper Wires Standard 7" M/M - 30 AWG (30 Pack)

Jumper Wires Standard 7" M/M - 30 AWG (30 Pack)

PRT-11026
$2.45
20
Transistor - NPN, 60V 200mA (2N3904)

Transistor - NPN, 60V 200mA (2N3904)

COM-00521
$0.55

Intel® Edison

DEV-13024
25 Retired

SparkFun Block for Intel® Edison - GPIO

DEV-13038
4 Retired

SparkFun Block for Intel® Edison - Base

DEV-13045
16 Retired

Suggested Reading

Concepts

Web App

XDK Web App Emulator

A web application (or web app for short) is a program that runs on a client's browser (although, some of the computing may be shared by the server). With the rise of HTML5 and JavaScript, most browsers are capable of running simple (or even complex) programs with these now ubiquitous languages.

Many smartphones have built-in or third-party browsers capable of running HTML5 and JavaScript. As a result, we can write software in the XDK that runs inside a phone's browser. This allow us to make programs that run across a variety of operating systems and can make network connections (e.g. to the Internet or the Edison). The down side is that some of the phone's native capabilities (e.g. accelerometer, GPS, camera) are not available to web apps. If we want native functionality, we either need to create a native app, designed specifically for a particular phone or operating system, or we need to make a hybrid app, which combined native functionality and web app portability.

We will cover hybrid apps (with Cordova) in a future exercise.

Web App Libraries

In previous examples, we included libraries by adding the appropriate name and version (usually found from npmjs.com) into the package.json file. This told the XDK to download the Node library, build it (if needed), and transfer it to the Edison along with the other necessary program files.

When building a web app, it is often necessary to include other pieces of code as a library, much like we did with Node modules. However, the XDK does not have a good way of automatically knowing which libraries to find when it comes to web apps. As a result, we will need to manually download the library (often packaged as a .js file) and include it with the project files.

Basic file organization of a web app

The suggested file structure of a web app looks slightly different from the file structure of the Node.js IoT application. In fact, it looks very much like the suggested file structure for web pages. We will keep HTML (user interface) in index.html, JavaScript in js/app.js, and libraries (usually, third-party .js files) in the js directory.

LED Current

The brightness of an LED is controlled by the amount of current flowing through it. LEDs, generally, have a fixed voltage drop across their anode and cathode. In order to fix the amount of current, we usually need to choose the right resistor for the LED.

In our previous circuit, we used just the red channel of the RGB LED, which we will assume is 1 LED. We found that the red LED has a voltage drop of about 2.0V, and by using a 100Ω resistor and a 3.3V rail, we could get 11mA to pass through the resistor (well below its maximum current rating of 20mA.

Now, we want to add 2 more LEDs into the mix. The green and blue LEDs (all packaged within the same RGB LED housing) have a voltage drop of about 3.2V (according to the RGB LED datasheet). If we connect a 100Ω resistor to each of the green and blue LEDs and connect that to the 3.3V rail through a transistor (like we did for red), we would end up with almost no current flowing through them. They probably wouldn't turn on!

Voltage drop for green and blue channels on 3.3V

That can't happen! So, we need to increase the rail voltage that we are using for the green and blue LEDs (and not for the red channel). We will connect the collector of the transistors for green and blue to the VSYS rail, which is nominally 4.2V.

RGB LED schematic

Now, we should have some current flowing through our green and blue LEDs. We can calculate that voltage drop across the 100Ω resistor:

Voltage drop across limiting resistor

With that, we can calculate the current flowing through the resistor (and, as a result, the LED):

Calculating current through resistor

Current through resistor and LED

8mA is not exaclty the same as the current flowing through the red LED (11mA), so the brightnesses will be different. For our purposes, it will be good enough to demonstrate how to mix red, green, and blue into different colors.

Pulse Width Modulation

In addition to controlling the current, we can also rapidly turn the LED off and on to give the appearance of a dimmer LED. This is known as "Pulse-Width Modulation" (PWM). Note that we are flipping the LED off and on so fast that generally our eyes cannot see the flickering.

We adjust the "duty cycle" of this flipping process in order to control the brightness. Duty cycle just refers to how long our LED stays on in relation to how long it stays off.

Duty cycle example

The higher the duty cycle (e.g. 75% in the image above), the brighter the LED will appear to be. At lower duty cycles (e.g. 25%) the LED will hardly appear to be on. For a full tutorial on PWM, see Pulse-width Modulation.

In our program, we will rely on the Edison's built-in PWM functionality (using MRAA's PWM class) to control the duty cycle of the individual red, green, and blue channels of the LED.

Hardware Hookup

Fritzing Diagram

We build upon the previous, single LED example and add another set of transistors and resistors.

RGB LED with Edison Fritzing

Having a hard time seeing the circuit? Click on the Fritzing diagram to see a bigger image.

Part 1: Simple Web App

Create a Web App

In the XDK, create a new project, and under HTML5 Companion Hybrid or Web App select Templates and Blank. Select Standard HTML5, and click Continue.

Creating a web app in the Intel XDK

Give your new app a name (e.g. "XDK_MyApp"), and click Create. You will notice that the files and folders in the web app template are different from the ones in IoT project templates.

XDK Web App files

Our code will live in www/index.html and www/js/app.js

Libraries

Similar to loading Node.js modules for code that runs on the Edison, we will rely on JavaScript libraries in our web app. In the first part, we will include jQuery, which makes it easier to select HTML elements (from the index.html page) in our JavaScript (app.js) code and handle events like text entry or button clicks.

Navigate to http://jquery.com/download/ and download the latest, uncompressed version (e.g. "Download the uncompressed, development jQuery 2.1.4"). That will download a .js JavaScript file, which we need to copy into our project.

Navigate to your Downloads directory, and copy the newly downloaded .js file. Then, navigate to your project directory. In the www directory (e.g. \/www), create a directory named lib.

Create lib directory in project

In that directory, create another directory named jquery.

jquery directory in project

Finally, paste the jQuery JavaScript (.js) file in the jquery directory.

Copying in the jQuery file

The XDK should now show the jQuery file in the file browser pane (if not, switch to another project and then back to the web app project to reload the file browser).

XDK file browser with jQuery

HTML

Open the index.html file (found in the www directory in the project), and copy in the code below. Don't forget to save the file (File → Save) when you are done!

<!DOCTYPE html>



<html>
    
<head>
  <title>Simple Web App</title>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
    <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=no">
    <style>
        @-ms-viewport { width: 100vw ; min-zoom: 100% ; zoom: 100% ; }  @viewport { width: 100vw ; min-zoom: 100% zoom: 100% ; }
        @-ms-viewport { user-zoom: fixed ; min-zoom: 100% ; }           @viewport { user-zoom: fixed ; min-zoom: 100% ; }
    </style>
</head>

<body>

    
    <div>
        <h2>The Button</h2>
        <p><button id="toggle_button">Push Me!</button></p>
    </div>
    
    
    <div id="toggle_text" style="display: none;">
        <p>Boo!</p>
    </div>
    
    
    <script type="text/javascript" src="lib/jquery/jquery-2.1.4.js"></script>
    <script type="text/javascript" src="js/app.js"></script>
</body>

</html>

JavaScript

Open the app.js file (found in the www/js directory), and copy in the following code. Don't forget to save the file (File → Save) when you are done!

language:javascript
/*jslint unparam: true */
/*jshint strict: true, -W097, unused:false,  undef:true, devel:true */
/*global window, document, d3, $, io, navigator, setTimeout */

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 6 - Part 1: Simple Web App
 * This sketch was written by SparkFun Electronics
 * November 10, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 * 
 * Create a some dynamic text that appears when a button is pushed.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Make the toggle text div appear and disappear
function toggleText() {

    // Put in strict mode to restrict some JavaScript "features"
    "use strict";

    // Declare our variables at the beginning of the scope
    var toggleTextEl = $('#toggle_text');

    // Toggle the visibility of the text
    toggleTextEl.fadeToggle();

    // Print the visibility to the console
    console.log("Visibility: " + toggleTextEl.css('visibility'));
}

// Short for jQuery(document).ready() method, which is called after the page
// has loaded. We can use this to assign callbacks to elements on the page.
$(function() {
    "use strict";

    // Assign a callback to the "Push Me" button
    $('#toggle_button').on('click', function(){
        toggleText();
    });
});

What You Should See

To test the program in the XDK's phone emulator, click on Run My App in the right-side pane. Click on the "Play" symbol (triangle) next to Run in Emulator. The XDK Emulator should boot up and give you a phone-like interface running our web app. Click the "Push Me!" button for a (very insignificant) surprise.

XDK Phone Emulator

In the top-left pane, you can also select the model of phone you wish to test. It may not be as good as the real thing, but it's a start!

To test the program on a real phone, we will first need to download and install the Intel App Preview from the appropriate app store. App Preview can be found here for iOS, here for Android, or here for Windows.

For the next steps, you must be logged into the Intel® Developer Zone in the XDK.

In the XDK, go to the TEST tab, and click on the Push Files button. This will upload the project to Intel's servers, where you will be able to download it on your phone.

Pushing files to Intel's test servers with the XDK

On your phone, open the Intel® App Preview app (don't think about the redundancy too hard). Press the Login button, and enter your Intel® Developer Zone username and password. Press the Server Apps tab on the bottom of the screen to view your uploaded projects (at this point, you should only see one).

App Preview server apps

Press on your project's name, and you will be presented with a launch screen.

App Preview launch screen

Press the rather large Play button to start your app.

App running

And that's it! Your web app is now running on your phone. To exit, tap the screen with three fingers simultaneously.

To build and deploy your app (i.e. run without the App Preview app), navigate to the BUILD tab in the XDK. There, you will see several options on building your app. To build your program as a Web App, click the WebApp button. To learn more about building XDK apps, read this article.

Code to Note

The \<html>, \<head>, and \<body> tags should look very similar to how we created a simple web page in the previous experiment. The difference here is that the HTML is located in a separate file (index.html) than the JavaScript (app.js).

We load the JavaScript file with


at the end of the body. This allows us to make functions calls to JavaScript as well as have HTML elements be referenced by the JavaScript. For example, we create a button with <button id="toggle_button"> that has the id "toggle_button". In app.js, we assign an event handler (the function .on()) to the toggle_button element.

To make the HTML-JavaScript communication easier, we rely on the jQuery library. jQuery adds event handling, page manipulation, and animations to JavaScript in an easy-to-use fashion. The syntax might take some time to get used to, but for starters, know that $ is short for the class jQuery. That means $('#toggle_button') is really jQuery('#toggle_button') (i.e. it's just a shortcut).

The piece of code

language:javascript
$('#toggle_button').on('click', function(){
    toggleText();
});

assigned the function toggleText() to the on click action for the toggle_button HTML element, which we created in index.html.

Finally, "use strict"; is an odd piece of code that sits in the beginning of functions. This line puts JavaScript into "strict mode" running in browsers, which restricts certain functions and is generally considered more "safe."

Part 2: RGB Color Picker

The Web App

In the previous part, we created a simple web app to demonstrate how web apps work. You might have noticed that we did not use the Edison at all. In this part, we will need to create 2 programs: one that runs on the Edison as a server and one that runs as a client on a smartphone.

Create a new Standard HTML5 app using the Blank Template (just like we did in part 1). Then, we need to add some libraries.

First, download the uncompressed, latest version of jQuery from http://jquery.com/download/. Copy that file (e.g. jquery-2.x.x.js) to \/www/lib/jquery (just like we did in part 1). Create any directories that do not exist.

Second, download the socket.io client library from https://github.com/socketio/socket.io-client (click Download ZIP). Unzip the .zip file, and copy socket.io.js to \/www/lib/socketio.

Third, download the JavaScript tinyColorPicker from https://github.com/PitPik/tinyColorPicker. Unzip the .zip file, and copy jqColorPicker.min.js to \/www/lib/jqColorPicker. Note that we are using the minified version of the tinyColorPicker library.

You might have to refresh the project in the XDK (i.e. right-click in the file explorer pane and select Refresh File Tree).

Refresh file tree in XDK

In www/index.html, paste in the following code:

<!DOCTYPE html>



<html>
    
<head>
  <title>Set RGB of Edison</title>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
    <meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1, user-scalable=no">
    <style>
        @-ms-viewport { width: 100vw ; min-zoom: 100% ; zoom: 100% ; }  @viewport { width: 100vw ; min-zoom: 100% zoom: 100% ; }
        @-ms-viewport { user-zoom: fixed ; min-zoom: 100% ; }           @viewport { user-zoom: fixed ; min-zoom: 100% ; }
    </style>
</head>

<body>

    
    <div id="connection">
        <h2>Edison Address</h2>
        <p>Please provide the IP address & port to the Edison</p>
        <p>
            <input id="ip_address" type="text" placeholder="IP Address">
            <input id="port" type="text" placeholder="Port">
        </p>
        <p><button id="send_ip_port">Connect</button></p>
    </div>
    
    
    <div id="rgb" style="display: none;">
        <h2>Color Selector</h2>
        <input id="colorSelector" class="color">
    </div>
    
    
    <script type="text/javascript" src="lib/jquery/jquery-2.1.4.js"></script>
    <script type="text/javascript" src="lib/jqColorPicker/jqColorPicker.min.js"></script>
    <script type="text/javascript" src="lib/socketio/socket.io.js"></script>
    <script type="text/javascript" src="js/app.js"></script>
</body>

</html>

Save the file, and in www/js/app.js, paste in the following code:

language:javascript
/*jslint unparam: true */
/*jshint strict: true, -W097, unused:false,  undef:true, devel:true */
/*global window, document, d3, $, io, navigator, setTimeout */

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 6 - Part 2: Phone RGB LED
 * This sketch was written by SparkFun Electronics
 * November 9, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Runs as a web app on a smartphone. Creates a socket.io connection to the
 * Edison and sends RGB values.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Connect to Edison server with socket.io
function connectIP() {

    // Put in strict mode to restrict some JavaScript "features"
    "use strict" ;

    // Declare our variables at the beginning of the scope
    var scoket;
    var ipEl = $('#ip_address');
    var portEl = $('#port');
    var connectionEl = $('#connection');
    var rgbEl = $('#rgb');
    var colorSelectorEl = $('#colorSelector');

    // Attach a socket.io object tot he main window object. We do this to avoid
    // a global socket variable, as we will need it in the colorPicker callback.
    window.socket = null;

    // Connect to Edison
    console.log("Connecting to: " + ipEl.val() + ":" + portEl.val());
    window.socket = io.connect("http://" + ipEl.val() + ":" + portEl.val());

    // If we don't have a connection, disconnect and hide the RGB selector
    window.socket.on('connect_error', function() {
        window.socket.disconnect();
        alert("Could not connect");
        rgbEl.fadeOut();
    });

    // If we do have a connection, make the RGB selector appear
    window.socket.on('connect', function() {
        rgbEl.fadeIn();
        colorSelectorEl.trigger('click');
    });
}

// Short for jQuery(document).ready() method, which is called after the page
// has loaded. We can use this to assign callbacks to elements on the page.
$(function() {
    "use strict" ;

    // Assign a callback to the "Connect" port
    $('#send_ip_port').on('click', function(){
        connectIP();
    });

    // Assign initial properties to the color picker element
    $('.color').colorPicker({
        opacity: false,
        preventFocus: true,
        color: 'rgb(0, 0, 0)',

        // This is called every time a new color is selected
        convertCallback: function(colors, type) {
            if (window.socket && window.socket.connected) {
                window.socket.emit('color', colors.RND.rgb);
            }
        }
    });
});

Don't forget to save!

Edison Code

Create a new project (Blank template under Internet of Things Embedded Application). This code will run on the Edison. Copy in the following code into main.js:

language:javascript
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
// Leave the above lines for propper jshinting

/**
 * SparkFun Inventor's Kit for Edison
 * Experiment 6 - Part 2: Edison RGB LED
 * This sketch was written by SparkFun Electronics
 * November 9, 2015
 * https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments
 *
 * Waits for socket.io connections and received messages to change RGB LED.
 *
 * Released under the MIT License(http://opensource.org/licenses/MIT)
 */

// Import the MRAA and HTTP modules
var mraa = require('mraa');
var server = require('http').createServer();
var io = require('socket.io').listen(server);

// Port
var port = 4242;

// Set up PWM pins
var rPin = new mraa.Pwm(20);
var gPin = new mraa.Pwm(14);
var bPin = new mraa.Pwm(0);

// Enable PWM
rPin.enable(true);
gPin.enable(true);
bPin.enable(true);

// Set 1000 Hz period
rPin.period(0.001);
gPin.period(0.001);
bPin.period(0.001);

// Turn off LEDs initially
pwm(rPin, 0.0);
pwm(gPin, 0.0);
pwm(bPin, 0.0);

// Wait for a client to connect
io.on('connection', function(socket) {
    console.log("A client is connected!");

    // Look for the "color" message from the client and set the LED
    socket.on('color', function(rgb) {
        console.log("RGB(" + rgb.r + ", " + rgb.g + ", " + rgb.b + ")");
        pwm(rPin, rgb.r / 255);
        pwm(gPin, rgb.g / 255);
        pwm(bPin, rgb.b / 255);
    });
});

// PWM needs a "fix" that turns off the LED on a value of 0.0
function pwm(pin, val) {
    if (val === 0.0) {
        pin.write(0.0);
        pin.enable(false);
    } else {
        pin.enable(true);
        pin.write(val);
    }
}

// Run the server on a particular port
server.listen(port, function() {
    console.log("Server listening on port " + port);
});

What You Should See

Upload the Edison code to the Edison and run it. You should see a note in the console, "Server listening on port 4242". Take note of the Edison's IP address.

Open the web app project back up and run it in an emulator or your smartphone. You will be presented with a couple of fields for IP address and port number. Enter the IP address of the Edison and 4242 for the port.

Connecting to the Edison with a web app

Click Connect and the web app should make a connection with the Edison (assuming your phone/emulator and Edison are on the same network). If it was successful, you should see an RGB color selector appear.

RGB color picker as a web app

Try selecting different colors, and see how the LED connected to the Edison responds!

RGB LED on Edison

Code to Note

In the web app, we are using jQuery again to control elements, like in part 1. We rely on fadeIn() and fadeOut() to make the RGB selector appear and disappear. Additionally, we use the alert() function to make a pop-up appear letting the user that the connection failed.

You might have noticed that we used window.socket in connectIP(). The window object is pre-defined as the open window in a browser. It contains all the displayed HTML. As it turns out, we need to access a socket object in the function connectIP() as well as the callback for the RGB color picker. However, socket was never declared as a global variable, and as a result, the color picker callback (convertCallback) does not know about the existence of socket, as it was declared in connectIP(). This is a problem of "scope."

To solve this issue (and without creating unnecessary global variables), we create a socket object inside the window object (we say that window owns a socket object) with window.socket. Because window is global, we can then access window.socket anywhere in our code! To make sure that the window.socket object exists and has a connection before we use it to send data, we rely on the conditional

language:javascript
if (window.socket && window.socket.connected) {
    ...
}

in convertCallback. That way, we don't throw any undefined errors when we try to use the socket.

In the Edison code, we use the MRAA Pwm object to control the brightness of the RGB LED, which is created with an MRAA pin number. To find the MRAA pin number, first find the pin number as it is listed on the GPIO Block, and find the associated MRAA pin number in Appendix E: MRAA Pin Table. For example, GP12 is MRAA pin 20.

Troubleshooting

  • The web app does not start -- Try it in the XDK emulator first. In the emulator, click on the "debug" button (bug icon with an 'X' in the upper-left corner), and click on the Console tab to view error messages.
  • The web app won't run on my phone -- Your phone might not be supported. If it is an older phone, read about legacy phone support for the XDK.
  • The web app won't connect to the Edison -- Make sure the Edison and phone are on the same network (e.g. the phone must be connected to WiFi and on the same subnet as the Edison).

Going Further

Challenges

  1. Make a modified email notifier that changes the color of the LED depending on different parameters of your inbox. For example, you could have the LED be green for 1-10 new emails and red for 11+ emails.
  2. Add an image to the web app that turns the LED off and back on when you press it (hint).

Digging Deeper