1-5 Build Smart Lightbulb

The Philips Hue smart lightbulb was introduced in 2012, and now several companies offer smart lightbulbs. Smart lightbulbs can be controlled remotely using a mobile app and offer features like setting automatic on-off schedules, dimming lights, changing the light color, syncing lights to music, etc.

VIDEO: Philips Hue Smart Lighting

YOUR TASK

As an introduction to building and programming IoT devices using your Photon kit, your team will create a prototype of a smart lightbulb that can be controlled by a web app.

Your team will build its prototype of a smart lightbulb in four versions (or iterations) that keep getting closer to the end result. Each time you will modify your existing Photon device and your existing Photon code.

  1. Prototype Version 1: Connect LED light to Photon device, and have Photon code turn light on and off in repeating cycle.

  2. Prototype Version 2: Add push button to Photon device, and have Photon code turn on light when button is pressed.

  3. Prototype Version 3: Modify Photon code so button switches light on or off with each push, like a regular light switch.

  4. Prototype Version 4: Modify Photon code so it interacts with a web app by sending and receiving data through Internet. Create web app that shows current status of light and allows user to switch light on or off remotely.

Since this is practice, the instructions provided below will tell you which parts are needed, show you how to connect them, and even provide the code needed.

Your focus should be on:

  • understanding how to connect the parts to form circuits that power the parts and transfer data

  • understanding how the Photon code controls the parts and processes data

  • understanding how the Photon code and a web app can interact by sending and receiving data through the Internet

BACKGROUND

Each part (such as LED, etc.) that you connect to your Photon device must have a complete electrical circuit. The jumper wires and breadboard are used to help make a circuit for each part.

If this is your first time using an electronics kit, then read this helpful background about circuits and the breadboard.

PROTOTYPE VERSION 1

GOAL: Connect LED light to Photon device, and have Photon code turn light on and off in repeating cycle.

Complete Experiment 1 of the online SparkFun Photon Experiment Guide. Only complete the first part – skip Part 2.

For the Photon code, just modify (or copy) your existing Hello World app. That code is identical to the code for Experiment 1, except for the pin being used for the LED. In Hello World, you used pin D7 (built-in LED). In Experiment 1, you are instructed to connect an LED light bulb to pin D0. So just change this one line of code as shown below:

// global variables
int led = D0;

NOTE: LED lights need to be connected correctly. They are polarized (meaning they have a positive end and a negative end), and they need to be connected through a resistor (to limit the current that flows through the bulb). Pay attention to the diagrams and instructions in the experiment.

PROTOTYPE VERSION 2

GOAL: Add push button to Photon device, and have Photon code turn light on when button is pressed.

Complete Experiment 2 of the online SparkFun Photon Experiment Guide. Only complete the first part – skip Part 2.

For the Photon code, modify your existing code from the previous step. The complete code for Experiment 2 is shown below.

// global variables
int led = D0;
int pushButton = D2;

void setup() {
    pinMode(pushButton, INPUT_PULLUP);
    pinMode(led, OUTPUT);
}

void loop() {
    int pushButtonState = digitalRead(pushButton);

    // LOW means button is being pushed
    if(pushButtonState == LOW) {
        digitalWrite(led, HIGH);
    } else {
        digitalWrite(led, LOW);
    }
}

The push buttons included in your kit are classified as momentary switches, meaning they are only active ("on") when they are being pushed. Everyday examples of momentary switches are doorbell switches and the keys on a computer keyboard.

PROTOTYPE VERSION 3

GOAL: Modify Photon code so button switches light on or off with each push.

You will modify your existing Photon code to make the push button act similar to a maintained switch, which maintain their current state (on or off) until pushed again. This is how most light switches operate.

To do this, you need to create a global variable in the Photon code to keep track of the light's current state (on or off), so the light can be switched to the opposite state when the button is pushed again. Let's name this variable as: ledStatus

There are several possible data types that could be used for this variable, but we have to select only one to use:

// DON'T copy and paste this

// possible data types for variable - can only use one
int ledStatus = 0; // 0 represents off, 1 represents on
boolean ledStatus = false; // false represents off, true represents on
String ledStatus = "off"; // use "off" or "on"

Although any of those data types above would work, the code might be easier to understand if we use a String variable to track ledStatus as "off" or "on" by changing the variable's value whenever the button is pushed.

Since we still need global variables for the LED pin and the push button pin, our final list of global variables will be:

// global variables
int led = D0;
int pushButton = D2;
String ledStatus = "off";

Let's make sure the light is actually off when the device first starts (so it matches the initial ledStatus assigned in the global variables). To do this, add a statement within the setup() function.

void setup() {
    pinMode(pushButton, INPUT_PULLUP);
    pinMode(led, OUTPUT);

    // make sure light is off at start
    digitalWrite(led, LOW);
}

Let's add a custom function at the end of the Photon code that will toggle the light on or off based on the current ledStatus. Let's name this function as: ledToggle()

void ledToggle(){
    if (ledStatus == "off") {
        digitalWrite(led, HIGH);
        ledStatus = "on";
    } else {
        digitalWrite(led, LOW);
        ledStatus = "off";
    }
}

Now you can "call" (run) this custom function within the loop() whenever the button is pushed:

void loop() {
    int pushButtonState = digitalRead(pushButton);

    if(pushButtonState == LOW) {
        ledToggle();
    }

    // wait before reading button again
    delay(200);
}

Notice that a slight delay was included before reading the button again. (The delay command uses milliseconds, so 1000 milliseconds = 1 second.)

Without a delay (or if the delay is too short), the code loops so fast that it toggles the light on and off multiple times with each button press, making the device seem unpredictable. If the delay is too long, the device feels unresponsive because you have to hold down the button longer to have the code detect the press.

Remember to flash the modified app to your Photon device to test it out.

PROTOTYPE VERSION 4

GOAL: Modify Photon code so it interacts with a web app by sending and receiving data through Internet. Create a web app that shows current status of light and allows user to switch light on or off remotely.

You will modify your existing Photon code to send and receive data through the Particle Cloud service. Then you will create a web app that uses the Particle JavaScript library to send and receive data through the Particle Cloud.

Particle has built-in functions to share data through the Particle Cloud service. This is how your Photon device can interact with other apps (or even with other Photon devices).

Modify Photon Code

We want to share the ledStatus variable with our web app, so we can display the current status of the light. We can share the current value of a variable by adding one line of code to the setup() function:

Particle.variable("ledStatus", ledStatus);

We need to first tell it what name to call the variable in Particle Cloud (name can be up to 12 characters) and then identify the name of the variable in the Photon code. Usually, these two will have the same name (but they don't have to).

Next, we want to be able to receive data from our web app, so we can run the function to toggle the light on or off when the user clicks a button in the web app. Again, we can do this by adding one line of code to the the setup() function:

Particle.function("led", ledToggle);

We need to first tell it what name to call the function in Particle Cloud (name can be up to 12 characters) and then identify the name of the function in the Photon code to run. These can have the same name or be different.

We will also need to modify our ledToggle() function. If we want to use the Particle Cloud to call a function in our Photon code, then the function in the Photon code must return a int value (instead of void or some other data type) – and the function must accept a String value from the Particle Cloud (the string is the data that our web app sends to the Photon device).

However, you do not necessarily have to do any with the function's return value or even with the String value – they just need to be present in the code for it to communicate properly with Particle Cloud.

The modified ledToggle() function is as follows:

int ledToggle(String data){
    if (ledStatus == "off") {
        digitalWrite(led, HIGH);
        ledStatus = "on";
        return 1;
    } else {
        digitalWrite(led, LOW);
        ledStatus = "off";
        return 0;
    }
}

Now we have to also modify the line of Photon code in the loop that calls this function when the user pushes the button on the device. We must pass a string value to the function (even though we decided to not actually use this string for anything inside the function).

The modified loop() function is as follows (only change is adding "toggle"):

void loop() {
    int pushButtonState = digitalRead(pushButton);

    if(pushButtonState == LOW) {
        ledToggle("toggle");
    }

    // wait before reading button again
    delay(200);
}

That takes care of the changes in the Photon code. Remember to flash the modified app to your Photon device.

Create Web App

Create a new HTML file (index.html), CSS file (style.css), and JavaScript file (code.js) using a code editor (such as Editey in Google Drive, etc.). Make sure the files are blank.

Copy and paste the HTML code below into index.html

HTML for index.html

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smart Lightbulb</title>
        <script src="//cdn.jsdelivr.net/jquery/3.1.1/jquery.min.js" type="text/javascript"></script>
        <script src="//cdn.jsdelivr.net/particle-api-js/6.4.2/particle.min.js" type="text/javascript"></script>
        <script src="code.js" type="text/javascript"></script>        
        <link href="style.css" rel="stylesheet" type="text/css">
    </head>
    <body>
        <h1>My Smart Light</h1>
        <div id="light" class="card">
            <h2 id="light-name" contenteditable="true">Light 1</h2>
            <h2 id="light-status">Connecting...</h2>
            <button id="light-button" onclick="toggleLight();">Wait</button>
        </div>
    </body>
</html>

Notice that the HTML <head> section loads 3 JavaScript files:

  1. jQuery which is a JavaScript library that makes it easier to do things like change HTML or CSS in your web app

  2. Particle API JS which is a JavaScript library that contains functions that allows your web app do things like share data through Particle Cloud

  3. code.js which is your own JavaScript file that will get data from your Photon device, send data to your Photon device, and update your web app to show the current status of your Photon device.

Notice that we've assigned unique id names to several elements within the <body> section. This will allow us to use jQuery functions to change these elements.

Finally, notice that we added an onclick event to the <button> that will run a JavaScript function called toggleLight() which will be in your code.js file.

Next, copy and paste the CSS code below into style.css

CSS for style.css

body {
    font-family:  Helvetica, Arial, sans-serif;
    font-size: 1em;
    text-align: center;
}
h1 {
    color: red;
}
.card {
    width: 250px;
    height: 200px;
    padding: 10px;
    margin: 0 auto 20px;
    border: 1px solid #888;
    border-radius: 5px;
    box-shadow: 2px 2px 2px #ccc;
    background-color: #bbb;
    text-align: center;
}
.light-on {
    background-color: #ffff99; /* yellow */
}
button {
    padding: 10px;
    width: 100px;
    border-radius: 10px;
    font-size: 1em;
    color: #444;
    background-color: white;
}

The CSS will make our web app look nicer. The <div> in the HTML is styled to look like a card. The background color will be gray when the light is off but will be changed to yellow when the light is on.

We will change this background color by using jQuery to add the class of .light-on to the <div> if the data from the Particle Cloud tells us the light is on. When the light is turned off, we will use jQuery to remove that class (making the card gray again).

Finally, copy and paste the JavaScript code below into code.js

JavaScript for code.js

var myDevice = "000000000000000000000000"; // insert your Photon device ID
var myToken = "abcdefghijklmnopqrstuvwxyz1234567890"; // insert your Photon access token
var particle = new Particle();

window.setInterval(checkLight, 200);

function checkLight(){
    particle.getVariable({ deviceId: myDevice, name: "ledStatus", auth: myToken }).then(function(data) {
            if (data.body.result == "on") {
                $("#light").addClass("light-on");
                $("#light-status").html("ON");
                $("#light-button").html("Turn Off")
            } else if (data.body.result == "off") {
                $("#light").removeClass("light-on");
                $("#light-status").html("OFF");
                $("#light-button").html("Turn On")
            }
    }, function(err) {
            console.log("An error occurred retrieving data:", err);
    });
}

function toggleLight() {
    particle.callFunction({ deviceId: myDevice, name: "led", argument: "toggle", auth: myToken });
}

Notice that the first two lines of JavaScript are supposed to list your Photon device ID and your Photon access token, which must be copied and pasted from your Particle Build account.

IMPORTANT: If you don't update these first two lines of JS code, your web app will not work properly.

  • Your Photon device ID is listed in the "Devices" section of your Particle Build account. Click the arrow to the right of your Photon device name to reveal the device ID. This device ID acts like a username to access your device's data in the Particle Cloud service.

  • Your Photon access token is listed in the "Settings" section of your Particle Build account. This access token acts as a password to access your device's data in the Particle Cloud service. (If you reset your access token at some future point, you would have to update your web app to use the new token.)

Next notice that we include a JavaScript statement that tells the webpage (window) to run the checkLight function at an interval of once every 200 milliseconds. This lets the web app stay updated on the current status of the light.

Next, we list our checkLight() function that we already told the web app to run every 200 milliseconds. Inside this function, it checks the current value of the ledStatus variable that is being shared to the Particle Cloud by your Photon device.

Here's how particle.getVariable in the web app matches up with Particle.variable in the Photon code. Notice that what links them is the name "ledStatus" – this is the variable in the Photon code that is being sharing through Particle Cloud.

// Just a comparison - DON'T copy and paste these again

// WEB APP 
function checkLight(){
    particle.getVariable({ deviceId: myDevice, name: "ledStatus", auth: myToken }).then(function(data) {
            if (data.body.result == "on") {
                $("#light").addClass("light-on");
                $("#light-status").html("ON");
                $("#light-button").html("Turn Off")
            } else if (data.body.result == "off") {
                $("#light").removeClass("light-on");
                $("#light-status").html("OFF");
                $("#light-button").html("Turn On")
            }
    }, function(err) {
            console.log("An error occurred retrieving data:", err);
    });
}


// PHOTON CODE
Particle.variable("ledStatus", ledStatus);

Once we get the data result for the "ledStatus" variable, we use jQuery statements to add or remove the class light-on to switch the card background to yellow or gray and to update the text in two HTML elements.

Finally, the last thing in our JavaScript is the toggleLight() function that will run whenever the user clicks the on-screen button. Inside this function, it calls the "led" function through Particle Cloud and sends it data (the String argument, which we assigned a value of "toggle").

Here's how particle.callFunction in the web app matches up with Particle.function in the Photon code. Notice that what links them is the name "led" – this is the function that the web app calls through Particle Cloud. When the Photon code receives this call, the Photon code runs the custom function called ledToggle and passes it the String data sent by the the web app.

// Just a comparison - DON'T copy and paste these again

// WEB APP 
function toggleLight() {
    particle.callFunction({ deviceId: myDevice, name: "led", argument: "toggle", auth: myToken });
}

// PHOTON CODE
Particle.function("led", ledToggle);

int ledToggle(String data){
    if (ledStatus == "off") {
        digitalWrite(led1, HIGH);
        ledStatus = "on";
        return 1;
    } else {
        digitalWrite(led1, LOW);
        ledStatus = "off";
        return 0;
    }
}

Be sure to refresh your web app, and it should now be able to interact with your Photon device. You should be able to push the physical button on the Photon device to switch the light on or off – and see that your web app shows the updated light status relatively quickly.

You should also be able to do the reverse: click the on-screen button in your web app to see that it toggles the light on your Photon device and then updates the light status on the web app.

NOTE: There may be a slight delay of about 0.5 second for the device and web app to sync up. Keep in mind that the web app was told to only run checkLight() once every 0.2 seconds. We also told the Photon code to add its own delay of 0.2 seconds because of the push button. Also, the data is traveling from an app on one device through the Internet to Particle Cloud and then back again through the Internet to the other app on a different device. (Remember data is not being transferred through the USB cable – it only provides power.)

You've just created your first IoT device!

GOING FURTHER

If you have time, you could think about ways to modify the smart lightbulb and its apps. Can you further customize the appearance of the web app? Can you add a second LED light and second button to your Photon device – and then modify your Photon app and web app to control each light separately? What are some other features that you could try to add to the smart lightbulb web app (dimming lights, setting on-off schedule, etc.)?

Last updated