Only this pageAll pages
Powered by GitBook
1 of 62

Code: Internet of Things 2.0

Loading...

Loading...

Tutorials

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

References

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Links

Prerequisite Knowledge

Electric Circuits

Having a basic conceptual understanding of electric circuits is very helpful, so students can better understand how to correctly connect the parts in their IoT electronics kit (and how to troubleshoot connection issues) – however, it is NOT required:

  • Atoms and Electrons

  • Static Electricity vs. Current Electricity

  • Conductors vs. Insulators

  • Closed Circuit vs. Open Circuit

  • Voltage, Current, and Resistance

  • Series Circuit vs. Parallel Circuit

Being able to solve quantitative equations involving circuits (Ohm's Law, etc.) is NOT required.

The IoT tutorials will provide a limited explanation of circuits, which should be sufficient for using the IoT kit to create devices.

Physical Computing

Previous experience building and programming devices using an Arduino electronics kit – such as a robotics kit, etc. – is very helpful. However, it is NOT required. The IoT tutorials will assume that students have no prior experience in building or programming physical computing devices.

Arduino

Previous experience and familiarity with the following Arduino development concepts is very helpful before programming IoT device apps – however, it is NOT required:

  • Variables – declaring data type (int, float, boolean, String, etc.) and name (unique identifier), assigning and changing values, converting data type, global vs. local scope

  • Program Functions – setup() function, loop() function, creating custom functions, calling a custom function, passing arguments into a function, returning value from a function

  • Input/Output Functions – such as: pinMode(), digitalRead(), digitalWrite(), analogRead(), analogWrite(), tone(), etc.

  • Libraries and Objects – including external library file in device app, constructing new object using defined class in library, using object properties and methods

  • Comparison Operators – such as: >, <, ==, !=, etc.

  • Logical Operators (NOT, AND, OR): !, &&, ||

  • Conditional Statements using if and else

  • Loops – such as: for, while, etc.

Web Development

Previous experience and familiarity with these web development concepts is highly recommended before programming IoT web apps – however, mastery is NOT required:

HTML

  • Tag syntax for common HTML elements – such as: <div>, <h1>, <h2>, <p>, <span>, <a>,<img>, <button>, <input>, <ul>, <li>, etc.

  • Nesting of HTML elements within other elements

  • Use of class and id attributes for HTML elements

  • Loading external files – such as: CSS style sheets, JavaScript files, images, other web pages, etc.

CSS

  • CSS selectors for HTML elements, classes, and ids

  • Common properties used in styles – such as: background-color, color, font-size, margin, padding, border, width, height, display, etc.

JavaScript (including jQuery)

  • Variables – declaring names (unique identifiers), assigning and changing values, data types (numbers, strings, boolean, etc.), global vs. local scope

  • Functions – creating functions, calling a function, passing arguments into a function, returning value from a function

  • Objects – constructing new object using defined class, using object properties and methods

  • Comparison Operators – such as: >, <, ==, !=, etc.

  • Logical Operators (NOT, AND, OR): !, &&, ||

  • Conditional Statements using if and else

  • Loops – such as: for, while, etc.

  • Events – such as: onclick, onchange, etc.

  • jQuery selectors for HTML elements, classes, and ids

  • jQuery syntax for basic functions – such as: .html(), .show(), .hide(), .addClass(), .removeClass(), etc.

Familiarity with these JavaScript concepts will make it easier for students to learn and apply similar concepts when programming their IoT device apps (using either the Wiring or Arduino programming language).

B. Hello World Test

In this second tutorial, you'll program a "Hello World" app for your IoT device.

Tutorial Goals

The goals of this second tutorial are to help you:

  • Verify your Photon device connects to Wi-Fi and the Particle Cloud service

  • Understand how to use Particle Build to create Photon device apps

  • Create a Hello World app to learn how to program your Photon device

What is a Hello World app?

When learning a new programming language, the first step that many people take is to create what is called a "Hello World" program. Traditionally, this program simply displays the text "Hello World" on the screen and only requires a few lines of code. The purpose is to demonstrate that you can create a simple yet functional program in the new coding language. It's the first step before creating more complex programs.

However, your Photon circuit board does not have a built-in screen. Your Photon kit does have a micro OLED screen that can be connected to the Photon – but that would require connecting 7 different jumper wires and coding a more complex app. Eventually, you'll be able to do this – but we need something much simpler for your first Photon app.

The good news is your Photon circuit board has a built-in blue LED light (D7) that can be controlled by your device's app. You won't have to connect any extra parts or wires yet – and you can program a simple app that makes the built-in LED blink on and off repeatedly, as a way of saying "Hello World."

Wiring Programming Language

All the apps that run on your Photon device will be coded using Particle's version of the open-source Wiring programming language framework for microcontrollers.

The Particle firmware on your Photon runs a modified version of the Wiring language with a few minor differences, as well as some additional methods (functions) customized for the Photon hardware.

One example of a minor difference:

  • In the original Wiring language, the analogRead() method reads the value of an analog input pin and returns the value as an integer (whole number) between 0-1023.

  • In the Particle firmware, the analogRead() method does the same thing but returns the value as an integer between 0-4095 (providing a higher level of precision).

The Particle firmware contains additional methods (functions) that are not part of the original Wiring language. For example, there are methods which are used to make the Photon interact with Particle Cloud. There are methods which can be used to control built-in hardware components on the Photon circuit board (such as the Wi-Fi module, RGB light, etc.).

WIRING VS. ARDUINO: Arduino is another programming language framework for microcontrollers. It turns out that Arduino is based on Wiring, so the two languages are nearly identical (though there are some differences). In most cases, a program originally written in Arduino will work on your Photon with only minor revisions. So once you've learned how to program in one of these languages, you've basically learned both.

WIRING VS. C++: Wiring (like Arduino) is a programming framework written in C++, so you can also directly incorporate C++ code within your device app.

B-1 Start IoT Device

Let's start your Photon to verify it connects to Wi-Fi and Particle Cloud.

Power On Photon

Start your Photon by powering on the circuit board:

  • Connect a power cable into the barrel jack or Micro-USB port on the circuit board, and connect the other end of the cable to a power source (such as: battery, computer USB port, etc.).

CHOOSE ONE: Only one power source (barrel jack or Micro-USB) needs to be connected.

REMINDER: The Photon circuit board does not have an "on/off" switch. As soon as a power source is connected to its barrel jack or Micro-USB port, the Photon will power on and start running. To turn off the Photon, you have to disconnect its power source.

Once the circuit board has power, you should see its red Power LED light turn on.

You should also see the RGB LED light turn on – it will blink green while the Photon automatically tries to connect to Wi-Fi.

Once the Photon has successfully connected to Wi-Fi and Particle Cloud, the RGB LED will be cyan (light blue) and "breathing" (slowly blinking).

CONNECTION ISSUES: If your Photon is having issues (can't connect to Wi-Fi, etc.), you'll see a different RGB pattern (such as: breathing green, breathing pink, etc.). You may have to consult with your teacher to troubleshoot your device.

How does Photon connect to Wi-Fi?

When your Photon is powered on (or restarted), it will automatically try to connect to a Wi-Fi network. It does this by using its saved list of Wi-Fi logins (network names and passwords). Every Photon can be programmed to store login information for up to 5 different Wi-Fi networks.

A brand new Photon will not have any Wi-Fi logins saved yet. However, the Photon provided to you by your teacher will most likely already have a Wi-Fi login programmed into it.

What is Particle Cloud?

Once your Photon is connected to Wi-Fi, the Photon will automatically try to connect to Particle Cloud, which is a cloud service that Particle provides for all of its microcontroller devices. All of your Photon's internet communications are routed through Particle Cloud.

Particle Cloud can be used to:

  • Code and store all your different Photon device apps (using Particle Build code editor)

  • Update the app stored on your Photon device

  • Update the firmware on your Photon device

  • Send and receive data between your Photon device app and your web app

  • Manage your Photon device remotely

SETUP NEW DEVICE: The Photon device provided to you by your teacher should already be setup with a Wi-Fi login and Particle account that you will use. If not, then the Photon will need to be setup as a new device by programming it with a Wi-Fi login, creating a Particle account, and adding the device to your account by claiming its device ID.

A. Meet Your IoT Kit

In this first tutorial, you'll become familiar with your team's IoT electronics kit.

Tutorial Goals

The goals of this first tutorial are to help you:

  • Understand the features of your Photon circuit board (pins, ports, buttons, LED lights)

  • Identify the other components in your Photon kit and their purposes (inputs, outputs, connectors, and cables)

  • Understand how to create electronic circuits by connecting components to the Photon circuit board (using power pins, I/O pins, jumper wires, and breadboard)

Photon Kit

This guidebook is tailored for an IoT electronics kit called the SparkFun Inventor's Kit for Photon, which will simply be referred to as the Photon kit.

SparkFun is a company that sells products to help people build and program electronics devices. Photon is a Wi-Fi enabled microcontroller (small computer) from a company called Particle that sells IoT hardware and services that help inventors and other companies create their own IoT products.

SparkFun created its own Photon kit by incorporating the Photon P1 microcontroller into an easy-to-use circuit board and packaged it with a set of inputs, outputs, wires, and other parts to help you start inventing your own IoT devices. It is also possible to purchase additional parts (sensors, motors, etc.) that can be used with this Photon kit.

SparkFun Inventor's Kit for Photon

NOTE: Your instructor may have provided you with a different IoT electronics kit. If your IoT kit is programmed using Arduino or Wiring, then you may still be able to use (or modify) the tutorials and references in this coding guidebook.

WI-FI NETWORK: Photon devices are relatively easy to setup to connect to home Wi-Fi networks or mobile hotspot devices. Photon devices running firmware version 0.7.0 or higher can be setup to connect to WPA2 Enterprise Wi-Fi networks (such as those typically found in schools, universities, and corporations). Teachers may need to coordinate with their school's IT administrator to follow Particle's guide to WPA2 Enterprise Setup.

Code Introduction

This IoT Code Guidebook is a supplement the .

This is Version 2.0 (In Development)

During the summer of 2022, we will be updating the code documentation for our IoT project to match the .

Expect frequent updates to this documentation!

What's in this Guidebook?

This guidebook contains a series of IoT code tutorials to help you get familiar with using your IoT electronics kit to build smart devices and program apps for them.

In addition, this guidebook contains coding references to help show and explain how to create a device app and web app that interact with each other through the internet. There are also references that show and explain how to connect specific inputs and outputs to your device and how to add code in your device app to control the inputs and outputs.

Finally, this guidebook also contains links to external resources, such as an online code editor (web IDE) for creating your device app, programming language references, and additional experiments for learning how to use your IoT kit.

Be sure to check out the recommended that will help ensure students are successful with the IoT code tutorials and IoT project.

HOW TO COPY CODE: When using these coding tutorials and references, you can copy a code block by clicking the copy icon displayed in the upper-right corner of the code block.

Your IoT Electronics Kit

This guidebook is tailored for an IoT electronics kit called the , which will simply be referred to as the Photon kit.

SparkFun sells a variety of other sensors and outputs that can be used with the Photon kit. If possible, it is highly recommended to add an to the kit for more design possibilities.

NOTE: Your instructor may have provided you with a different IoT electronics kit. If your IoT kit uses Arduino, then you can still use this guidebook to help get familiar with using your IoT kit to build smart devices and program apps for them. The Photon kit is programmed using a language called that is nearly identical to . In addition, the is similar to an Arduino circuit board (though there are a few differences).

FYI: This IoT code tutorial focuses on coding web apps (using JavaScript) that interact with a Photon device. However, it is also possible to code (using Objective-C, Swift, or Java) that interact with a Photon device.

Copyright and License

Copyright © 2016-2021 Michael Frontz and Jim Lyst, Indiana University School of Informatics and Computing at IUPUI

This material is part of the high school computer science curriculum developed for the program, an award-winning community partnership in central Indiana that is broadening student participation in computing and helping students develop the skills essential for success in the 21st century workplace. The iDEW program is managed by the .

This work is licensed under a . You are free to use, share, or adapt this material for noncommercial purposes as long as you provide proper attribution and distribute any copies or adaptations under this same license.

// example code block

void setup() {
​
}
​
void loop() {
​
}
IoT Project Guidebook
new IoT kit
prerequisite knowledge
SparkFun Inventor's Kit for Photon
ultrasonic sensor
Wiring
Arduino
Photon circuit board
native mobile apps for iOS and Android
Computing by Design
Informatics Diversity-Enhanced Workforce (iDEW)
Indiana University School of Informatics and Computing at IUPUI
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License

B-5 Setup Function

Next you'll add a command in your app code to designate the LED pin as an output.

Set Pin Mode for LED

A variety of inputs and outputs can be connected to the I/O pins on your Photon circuit board. Your app code needs to identify which I/O pins are being used and whether each of these pins will be used for an input or output. This is referred to as setting the pin modes.

You'll need to set the pin mode for the built-in LED that you'll be using. Add this code to your app by inserting it within the setup() function (between the curly braces):

pinMode(LED, OUTPUT);

The pinMode() method requires two parameters inside its parentheses (in this order):

  1. The I/O pin number, which can be the actual pin number (such as: D7, etc.) or a variable that stores a pin number. In this case, the variable LED is listed (which has a value equal to D7).

  2. The mode value, which can be INPUT, INPUT_PULLUP, or OUTPUT. Your Photon uses this value to change the electrical behavior of the pin, so the pin can either receive signals from an input or send signals to an output. In this case, the mode was set to OUTPUT because your app will be sending "on" and "off" signals to the LED light.

At this point, your app code should look similar to this:

int LED = D7;

void setup() {
    pinMode(LED, OUTPUT);
}

void loop() {

}

Notice that the pinMode() statement shown in the app code above is indented (using the tab key). This is a useful practice when adding code statements within curly braces because it helps make the code easier to read and understand – especially if your app contains many code statements nested within each other.

Verify Your App Code

The Particle Build code editor does NOT check your code syntax as you type, so be sure to periodically verify your code to check for errors.

Verify your app code by clicking the Verify icon in the left navigation bar. (Particle Build will first save your code before verifying it.)

Verify Icon

While Particle Build is verifying your code, it will display the message "Compiling code" in the status bar at the bottom of the code editor panel. When the verification process is complete, the status bar will indicate the results:

  • If your code compiled without any errors, the status bar will display a success message.

  • If your code contains an error, the status bar will display an error message with a description of the error and a link to the specific line number in your code where the error was detected (though sometimes the root cause of the error occurs on a previous line). You'll want to fix the error and then try verifying your code again.

MULTIPLE ERRORS: Sometimes your app code might contain multiple errors. However, Particle Build will stop verifying the code at the first error that is detected. Once you fix that error and verify the code again, you might see a new error message for another error that occurs later in the code.

B-4 Global Variable

You'll add a variable in your app code to represent the built-in LED light.

Add Global Variable for LED

Your "Hello World" app will make the Photon's built-in blue LED light turn on and off in a blinking pattern. This will be accomplished by sending separate "on" and "off" signals to the LED's pin.

Each I/O pin on the Photon circuit board is identified by a pin number (such as: A0, A1, A2, D0, D1, D2, etc.). In this case, the Photon's built-in blue LED light is connected to pin D7 (via internal circuitry).

When coding a Photon device app, you will typically create a global variable to store a pin number for each input or output connected to your Photon. This will help make your code easier to understand because the variable names help identify each input or output.

You'll need to create a global variable to store the pin number of the built-in LED. Add this code statement to your app by inserting it (as a separate line of code) before the setup() function:

int LED = D7;

HOW TO COPY CODE: When using this IoT code guidebook, you can copy a code block simply by clicking the copy icon displayed in the upper right of the code block.

This code statement does 3 things (in order):

  1. It declares a data type for the variable's value. In this case, int stands for integer (whole number). Photon pin numbers are always treated as int values (even though they have letters).

  2. It declares the variable's name. In this case, the variable will be called LED. You get to decide what to name your variables. Choose names that will make sense to anyone reviewing your code.

  3. It assigns a value to the variable. In this case, the variable's value will be equal to D7, which is the pin number for the Photon's built-in LED light.

Notice that this code statement ends with a semi-colon. Typically, each code statement in your app will end with a semi-colon. The semi-colon separates code statements, similar to how periods separate sentences in written English.

  • The exceptions to ending with a semi-colon are certain statements (such as functions, conditionals, loops, etc.) that use curly braces to enclose other code statements. However, within the curly braces, each code statement ends with a semi-colon.

Although you can actually list multiple code statements on the same line (because their semi-colons will separate them), each code statement is traditionally listed on its own separate line to make it easier to read the code.

Save Your App Code

The Particle Build code editor does NOT autosave your work as you type, so be sure to periodically save your code.

Save your app code by clicking the Save icon in the left navigation bar.

Save Icon

Tips for Naming Variables

You get to decide what to name each variable in your app's code. However, here are a few rules and recommendations to help you name your variables:

RULES

  • Each global variable must have a unique name.

  • A variable's name cannot be one of the keywords in the Wiring programming language.

  • Variable names must be one word (no spaces allowed).

  • Variable names can contain lowercase letters, uppercase letters, numbers, and certain special characters (such as underscores, etc.) – but the name cannot start with a number.

RECOMMENDATIONS

  • Make each variable's name concise yet descriptive, so it will be easy to read and understand.

    • Example of variable name that's concise yet descriptive: button

    • Example of variable name that's too concise: b

    • Example of variable name that's too descriptive: greenbuttonthatturnslighton

  • If your variable name combines multiple words, you can make the name easier to read by either using an underscore between words – or using "camelCase" (lowercase letters, but new words start with an uppercase letter).

    • Examples of variable names using underscores: red_light, motion_sensor

    • Examples of variable names using camelCase: redLight, motionSensor

  • If you have multiple inputs or outputs of the same type (multiple LED lights, multiple buttons, etc.), add an adjective or number to their variable names to help identify them in your app code.

    • Examples of variable names with adjectives: redLED, blueLED

    • Examples of variable names with numbers: button1, button2

B-3 New App Template

Let's title your new app template, and learn about the basic code structure for Photon device apps.

Title Your App

In the Code menu panel, you'll notice that your current app doesn't have a title yet.

It's recommended to give each app a unique title. Particle Build will allow you to save different apps that have the same title – but this could get confusing, so try to use unique app titles.

NOTE: You cannot have any blank spaces in an app's title. If you want to visually separate words in your app's title, just use a hyphen or an underscore.

Enter hello-world as your app's title.

You'll see the app's title show up in the "My Apps" list.

HOW TO RENAME APP: If you wanted to change the title of your current app, just click the title to enter a different title.

Photon App Structure

Your code editor should show the basic structure for a new Photon device app:

Setup Function

Every Photon device app must have one (and only one) setup() function. You can add lines of code between this function's opening and closing curly braces.

The setup() function will run one time when your app first starts (which is when your Photon is first powered on – or is restarted using its Reset button).

The code added within the setup() function typically sets pin modes for the device's inputs and outputs, initializes settings for certain inputs and outputs, or performs other "setup" actions that need to occur at the start of the program.

Even if you didn't add any code within the setup() function, your app must still have this function.

Loop Function

Every Photon device app must have one (and only one) loop() function. You can add lines of code between this function's opening and closing curly braces.

After the setup() function is done running, the loop() function will start to run. When all the code within the loop() function has been performed, the loop() function will automatically run itself again. It keeps running in an endless loop (until the device is restarted or powered off).

The code added within the loop() function performs the main tasks of your program.

Even if you didn't add any code within the loop() function, your app must still have this function.

VOID: Why is listed before the setup() and loop() functions? This is because each function in your Photon device app must declare a data type (such as: integer, boolean, etc.) for the data value returned by the function. In this case, void indicates the function does NOT return any data value.

Other Sections of App

Besides having the required setup() and loop() functions, your Photon device apps will typically have some or all of the following:

  • Comments

  • Libraries

  • Global Variables

  • Custom Functions

Comments

Comments are optional notes that you can insert to help explain or clarify portions of the code to anyone reviewing the program. Comments can be or .

Any comments in the app are ignored when the program is compiled and uploaded to your device.

Libraries

Some device apps might include (i.e., import) one or more library files. A library is a file of pre-built code that provides additional functions that your program can utilize. For example, certain inputs and outputs have their own code library with functions to make it easier to control the input or output.

Particle Build has a Libraries menu where you can search for existing libraries (or upload your own library file that you've created). When you select a library to be added to your app, Particle Build will automatically insert an statement for the library at the beginning of your app code.

Global Variables

Your device app will typically have code that declares global variables which store data used in your program's functions, such as pin numbers for sensors, etc.

Global variables are usually listed before the setup() function (to make it easier to read the code).

Custom Functions

You can also add your own custom functions to your device app. Each custom function must have a unique function name.

Custom functions are used to contain code that performs specific tasks or subtasks. Custom functions are optional, but they can help break up your code into smaller modules that are easier to understand (and easier to re-use). So rather than listing all your main program code within the loop() function, you can subdivide some or all the code into custom functions.

The code within a custom function is only run if and when that custom function is "called" (by listing the function's name) within the setup() or loop() function. A custom function can also be "called" within another custom function.

Custom functions are usually listed after the loop() function (to make it easier to read the code).

B-7 Flash App to Device

Next you'll flash your "Hello World" app to your Photon device to run the app.

Flash App to Photon

Be sure your Photon is powered on and connected to Wi-Fi and Particle Cloud.

Flash your app code to your Photon device by clicking the Flash icon in the left navigation bar. (Particle Build will first save and verify your code before flashing it.)

Your Photon will download the app from Particle Cloud over Wi-Fi and store the app in your Photon's flash memory. While this is occurring, you should see that the RGB light on your Photon's circuit board will blink pink.

Once the download is complete, your Photon will automatically restart itself. You'll see the RGB light on your Photon blink green while it tries to reconnect to Wi-Fi. Once your Photon has reconnected to Wi-Fi and Particle Cloud, the RGB will be "breathing" cyan (light blue).

Confirm App Works

Once your Photon has downloaded the new app and restarted, your new app will automatically start running:

  • Confirm that the blue D7 LED light on your Photon's circuit board blinks on and off in a repeating pattern (with the light turning on for 1 second and then turning off for 1 second).

If so, then you've successfully programmed the "Hello World" app for your Photon device. Your teacher may want to see your Photon device to confirm that your team's app is working.

APP ISSUES: If the app doesn't work correctly (such as: D7 LED doesn't turn on, D7 LED doesn't turn off, etc.), then double-check your app code in Particle Build. If necessary, consult with another team or your teacher to figure out what the issue might be.

void setup() {

}

void loop() {

}
// Comments are notes to yourself or others reading your code
// Each single-line comment starts with two forward slashes
​
/*
A multi-line comment block starts with a forward slash and asterisk
You can include as many lines of notes in the block as you need
A multi-line comment block ends with an asterisk and forward slash
*/
void
single-line
multi-line blocks
#include
Flash Icon

D-1 Connect Motion Sensor

NEED LED & BUTTON: Be sure the LED and button from your Smart Light device are still connected. If not, connect an LED to the D0 pin and connect a push button to the D2 pin.

Your Photon kit includes a motion sensor that uses passive infrared (PIR) light to detect movement in the surrounding environment up to 10 feet away.

In this step, your team will connect the motion sensor to your Photon circuit board using the breadboard.

You'll need these components:

  • Motion sensor (with 3-pin connector)

  • 3 jumper wires (use different colors to help identify them; it may help to match the sensor wires)

Follow these instructions explaining how to connect the motion sensor. The sensor can be connected to almost any I/O pin, but connect it to the D3 pin (which will be different from the wiring diagram).

5V REQUIRED: The motion sensor requires 5V of power to operate, so the sensor's red wire must be connected to the VIN pin or V-USB pin, depending on your Photon's power source.

  • If your Photon is being powered through the barrel jack, connect to the VIN pin.

  • If your Photon is being powered through the Micro-USB port, connect to the V-USB pin.

Example Wiring Diagram for a Motion Sensor

C-3 Connect Button

Physical buttons that people can push are used as inputs on many different types of devices. Your Photon kit should have a set of 4 push buttons with different cap colors: red, yellow, green, and blue.

In this step, your team will connect a push button to your Photon circuit board using the breadboard.

You'll need these components:

  • 1 push button (could be any color, but use same color as your LED)

  • 2 jumper wires (use two different colors to help identify them)

. The button can be connected to almost any I/O pin, but connect it to the D2 pin (which will match the wiring diagram).

C-1 Connect LED

LEDs (light-emitting diodes) are small, bright, long-lasting, energy-efficient lights. Your Photon kit has a set of LED lights with different bulb colors: red, yellow, green, and blue.

In this first step, your team will connect an LED light to your Photon circuit board using the breadboard.

You'll need these components:

  • 1 LED light (any color)

  • 1 resistor

  • 2 jumper wires (use two different colors to help identify them)

. The LED can be connected to almost any I/O pin, but connect it to the D0 pin (which will match the wiring diagram).

D-7 Web App HTML

Next, you'll create a web app that will interact with your Smart Security device through Particle Cloud.

Your web app will consist of an HTML file namedindex.html, a CSS file named style.css, and a JavaScript file named script.js.

Remember that Particle Build is only used to code your Photon device app. You'll need to use a different code editor to create the HTML, CSS, and JS files for your web app. Consult your teacher to determine which code editor will be most appropriate to use for your web app files.

Add Starter HTML

, and paste it into a blank HTML file named index.html.

The starter HTML contains blank lines where you'll add custom HTML for your specific web app.

Add Custom HTML

Copy this HTML, and paste it into the blank lines within the <body> of your starter HTML code:

COPY CODE: When using this IoT code guidebook, you can copy a code block simply by clicking the copy icon displayed in the upper right of the code block.

Preview Web App

If you preview the web app at this point, it's very plain (because there's no CSS in the style.css file) and it doesn't function yet (because there's no JS in the code.js file).

C-8 Web App CSS

Next, you'll add the CSS for your web app's stylesheet.

Add CSS

Copy this CSS, and paste it into a blank CSS file named style.css:

As you can see, this CSS has style declarations for 4 types of elements in your HTML:

  1. The CSS for body styles the <body> section in your HTML.

  2. The CSS for .card styles elements in your HTML that have class="card". The <div> element has this class.

  3. The CSS for .light-on styles any elements in your HTML that have class="light-on". Currently, no elements have this class. However, your web app JS will add this class to the <div> element if your light is turned on (changing the card's background color to yellow) and will remove this class if your light is turned off (changing the card's background color back to gray).

  4. The CSS for button styles the <button> element in your HTML.

CSS: If you want to learn more about CSS or need a quick reference, check out the .

Preview Web App

If you preview the web app at this point, you can see how the CSS has changed the appearance of the web app, but it still doesn't function yet (because there's still no JS in the code.js file).

Physical Outputs

Here are references for how to connect and code each physical output in your SparkFun Photon kit:

Physical Inputs

Here are references for how to connect and code each physical input in your SparkFun Photon kit:

  • (not standard part of SparkFun Photon kit, but your teacher may have added it)

OTHER SENSORS: There are references for other sensors such as , , and in the old project guidebook. These references will eventually be transferred into this new code guidebook.

LED Lights
Speaker
Servo Motor
Micro OLED Display
Push Buttons
Trimpot Dial
Motion Sensor
Magnetic Switch
Light Sensor
Temperature Sensor
Soil Moisture Sensor
Accelerometer
Ultrasonic Sensor
RFID Reader
Fingerprint Scanner
GPS Receiver
        <h2>Smart Security System</h2>
        <div class="card">
            <h2 id="system-mode">Connecting...</h2>
            <label class="switch">
                <input type="checkbox" name="toggle" onclick="toggleMode();">
                <span class="slider round"></span>
            </label>
            <h3>Last Motion Event</h3>
            <p id="event-time">None</p>
        </div>
        <div id="motion-alert" class="card">
            <h2>Motion Detected</h2>
        </div>
Copy this starter HTML for your web app
body {
    font-family:  Helvetica, Arial, sans-serif;
    font-size: 1em;
    text-align: center;
}

.card {
    width: 250px;
    height: 200px;
    margin: 0 auto 20px;
    padding: 10px;
    background-color: #ccc; /* gray */
    border: 2px solid #aaa;
    border-radius: 10px;
    box-shadow: 0px 4px 8px rgba(0,0,0,0.2);
}

.light-on {
    background-color: #ffff99; /* yellow */
}

button {
    width: 100px;
    padding: 10px;
    font-size: 1em;
    color: #444;
    background-color: white;
    border-radius: 10px;
}
W3Schools CSS Tutorial and Reference
Follow these instructions explaining how to connect the button
LED and Button connected to Photon
Follow these instructions explaining how to connect the LED
LED (with resistor) connected to Photon

B-2 Login to Web IDE

Now that your Photon is connected to Wi-Fi and Particle Cloud, your team will log in to Particle Build, the code editor that will be used to create your "Hello World" app.

What is Particle Build?

Particle Build is an online code editor (web IDE) provided by Particle. Particle Build is part of the Particle Cloud platform. You will use Particle Build to code and store all your Photon device apps.

The Photon device itself can only store and run one app at a time. However, you can create and save multiple apps in Particle Build. When you need to update the specific app stored on your Photon device, you'll do this in Particle Build – and your Photon will download the new app over Wi-Fi.

Your team will need a Particle account to log in to Particle Build. However, your teacher will most likely provide your team with an existing Particle account login (email & password) that's already associated with your specific Photon device. Every Photon has a unique device ID it uses to communicate with Particle Cloud, and each device ID can only be associated with one Particle account.

Log In to Particle Build

One person on your team should log in to Particle Build using your team's Particle account login.

Once you're logged in, you'll see the Particle Build code editor, which defaults to the "Code" menu and shows a blank app template.

Particle Build User Interface

User Interface

The user interface for Particle Build is divided into 4 sections:

  • On the far left is a vertical navigation bar with icons.

  • On the middle left is a menu panel showing options for the current navigation selection.

  • On the right side is the code editor panel showing the code for your current app.

  • On the bottom of the code editor panel is a horizontal status bar that displays messages.

Navigation Bar

If you hover your mouse pointer over an icon in the navigation bar, the icon's name will be displayed. Here is a summary of the navigation icons from top to bottom:

Icon

Name

Purpose

Flash

Flashes the current app to your Photon device over Wi-Fi (The app will first be saved and verified. If there are errors in the app, it will not be flashed.)

Verify

Complies the current app to check for errors (The app will first be saved.)

Save

Saves the current app in Particle Build

Code

Lists all your saved apps. Click an app's title to open it in the code editor.

Libraries

Lists libraries that can be included in your app to add functionality

Help

Lists quick help for device (might not be available for your Photon)

Docs

Opens new tab with Particle Reference Documentation for your device

Devices

Lists your devices. You can view the device ID, and signal device over Wi-Fi. (If you have multiple devices, you can select which device to flash apps to.)

Console

Opens new tab with Console showing your device's events in Particle Cloud

Settings

Provides options to: log out, change password, or get your access token.

Toggle the Menu Panel

The middle menu panel can be toggled between "show" and "hide" by clicking the same navigation icon repeatedly.

In the left navigation bar, click the Code icon.

Code Icon

The middle menu panel will become hidden.

Click the Code icon again to show the menu panel again.

In general, you'll probably want to keep the menu panel shown – but if you want extra space for your code editor panel, you can temporarily hide the menu panel.

View Devices Menu

In the left navigation bar, click the Devices icon.

Devices Icon

The middle menu panel will list your Particle devices. You should see a device name listed under P1 (because your device is a Photon P1). Your device's connection status is shown as a colored dot to the right of its name. If your device is connected to Wi-Fi and Particle Cloud, the dot should be cyan (light blue) and "breathing" (slowly blinking) – just like the RGB LED on your Photon circuit board.

Click the drop-down arrow to the right of the device's connection status dot. This will show additional information about your device:

  • You'll see the device ID, which is a unique ID used by your device to interact with Particle Cloud. Later when you create web apps to interact with your device, you'll need your device ID.

  • You'll see the firmware version that is currently saved on your device. If an updated version is available, your device's firmware will be automatically updated the next time you flash an app.

Signal Device

If you wanted to double-check your device and its connection (imagine you had multiple devices), an easy way is to signal it from Particle Build.

Click the Signal button. Particle Cloud will send a signal to your device over Wi-Fi. Your Photon's RGB LED will respond by cycling through a rainbow of colors.

Click the button again to stop signaling your device. Your Photon's RGB will return to breathing cyan.

Return to Code Menu

In the left navigation bar, click the Code icon to return to your list of apps.

Code Icon

D. Smart Security Device

In this fourth tutorial, you'll modify your "Smart Light" device into a "Smart Security" device and program new apps for the device.

Tutorial Goals

The goals of this fourth tutorial are to help you:

  • Gain further experience by creating another practice IoT device and programming its apps

  • Become better prepared to create your own IoT device and apps for your team project

Smart Security System

For decades, security systems have been used to monitor homes and businesses for emergencies (burglary, fire, flood, etc.). These systems use some combination of: motion sensors, door/window sensors, glass break sensors, video cameras, smoke detectors, flood sensors, etc. Today, many security systems are being connected to the internet to offer additional features.

You'll create a prototype of a Smart Security device by modifying your Smart Light device (which has an LED light and push button) to add a motion sensor and a speaker:

  • The LED light will be used to indicate whether the security system is currently "armed" (LED is on) or "disarmed" (LED is off).

  • The push button will be used to switch the security system between "armed" and "disarmed" mode. (The button will simulate a security system's keypad, which is used to enter a numeric passcode. For this prototype device, you'll simply press the button to toggle the system between modes, as if you had correctly entered a passcode.)

  • The motion sensor will detect whether something is moving within the surrounding area.

  • The speaker will be used to produce an alarm sound if motion is detected.

You'll use a copy of your Smart Light device app as starter code for your Smart Security device app. You'll modify the existing code controlling the LED and button before adding new code to control the motion sensor and speaker.

You'll also program a web app that interacts with your Photon over the internet to perform these tasks:

  • Monitor the security system's current mode ("armed" or "disarmed")

  • Remotely toggle the security system between "armed" or "disarmed" mode

  • Receive an event notification if the security system detects motion

  • View the date and time of the last motion event detected

D-5 Speaker Code

Next, you'll add code in your Smart Security device app to control the speaker.

The basic steps to control a speaker in your app code are:

  1. Declare a global variable to store the I/O pin number for the speaker.

  2. Set the pin mode for the speaker pin in the setup() function.

  3. Use tone() statements to produce sounds.

Global Variable for Speaker

Declare a global variable to store the I/O pin number for the speaker by adding this code statement before the setup() function:

int speaker = D1;

If you connected your speaker to a different I/O pin other than D1, then modify this code statement to list the correct pin number for your speaker.

Set Pin Mode for Speaker

Set the pin mode for your speaker pin by adding this code statement within the setup() function (between the curly braces):

pinMode(speaker, OUTPUT);

Produce Tone using Speaker

The speaker will be used to produce an "alarm sound" if the motion sensor detects motion.

The tone() method is used to produce a sound of a specific frequency (pitch) for a specific duration of time. The speaker can produce tones ranging in frequency from 20Hz (very low pitch) to 20KHz (very high pitch), covering the full range of sounds that humans can hear.

Add this code statement within your checkMotion() custom function (inside the curly braces of the if statement that checks the value of motionState – add the code before the delay()):

tone(speaker, 1000, 250);

The tone() method requires three parameters inside its parentheses (in this order):

  1. The I/O pin number, which can be the actual pin number (such as: D1, etc.) or a variable that stores a pin number. In this case, the variable named speaker is listed.

  2. The frequency for the tone, which can be an integer value (whole number) or a variable that stores an integer. The value can be between 20-20000 hertz. Lower numbers will have a lower pitch, while higher numbers will have a higher pitch. In this case, the frequency will be 1000 hertz, which will be a "less annoying" pitch than what an alarm sound would typically use.

  3. The duration for the tone, which can be an integer number (whole number) or a variable that stores an integer. The value represents the number of milliseconds that the tone will be played (1000 ms = 1 second). In this case, the duration will be 250 ms (0.25 seconds), which will be a much shorter duration than what an alarm sound would typically use.

Flash App to Device

Be sure your Photon device is connected to Wi-Fi and Particle Cloud.

Flash your app code to your Photon device by clicking the Flash icon in the left navigation bar. (Particle Build will first save and verify your code before flashing it.)

Flash Icon

Once your Photon has downloaded the new app and restarted, the updated app will start running:

  • Press the button to "arm" your Smart Security device. (This simulates having entered a passcode into a keypad to arm the device.) The LED light should turn on when the device is in "armed" mode. Confirm that the speaker produces an alarm sound when motion is detected. The sensor should be able to detect motion in the environment up to 10 feet away.

  • Press the button again to "disarm" the device (the LED should turn off). Because of the 2 second delay required when motion is detected, you may have to press the button more than once (or hold the button down slightly longer). Once the device is in "disarmed" mode, confirm that motion near the sensor does not produce an alarm sound.

C. Smart Light Device

In this third tutorial, you'll create a "Smart Light" device and program its apps.

Tutorial Goals

The goals of this third tutorial are to help you:

  • Practice connecting physical inputs and outputs to your Photon device

  • Program a Photon app that controls your device's physical inputs and outputs

  • Program a web app that interacts with your Photon device through Particle Cloud

What is a Smart Light?

The Philips Hue smart light bulb was introduced in 2012. Today, there are several companies that offer smart light bulb systems.

From the outside, a smart light bulb looks like a regular light bulb. However, what seems like a simple light bulb is actually a full-fledged IoT device: inside the bulb are multiple LED lights wired to a microcontroller circuit board that connects to your Wi-Fi network.

The smart light interacts with a mobile app that allows you to control an individual light or a group of lights. The mobile app might offer features such as:

  • Remotely turn the light(s) on or off

  • Set automatic timers to turn the light(s) on or off at specific times

  • Adjust the brightness of the light(s)

  • Change the color of the light(s)

  • Sync the light(s) to music, movies, or games

  • Control the light(s) using a voice assistant (such as: Alexa, Siri, etc.)

For this tutorial, you'll create a prototype of a Smart Light device using one LED. Your device will include a button to manually turn the light on or off. You'll program a Photon device app to control the LED using the button. You'll also program a web app that interacts with your Photon device over the internet to monitor the light's status and to allow you to remotely turn the light on or off.

B-8 Modify App

Your last step is to modify the "Hello World" app, as some extra practice.

Modify App Code

In Particle Build, modify the code within the loop() function to change the LED blinking pattern. Here are some possible options your team could choose:

  • Make the D7 LED blink faster

  • Make the D7 LED blink slower

  • Make the D7 LED blink in a different pattern (such as two quick blinks followed by a longer pause)

Add Comment

It's recommended to add a comment at the very beginning of your code to list a title for your app, plus any other information that might be helpful to you or to anyone else reviewing the program code.

For example, this comment could list your app's title, your team's information (team name and/or team members), your teacher's name, and your class period.

Add a block comment at the beginning of your app code before the setup() function:

/*
Hello World Test
Team Info
Teacher - Class Period
*/

Modify this comment to list your specific information. Check with your teacher to find out if there is other information that should be listed within this block comment.

Flash Modified App

Flash your modified app to your Photon to confirm it does what you intended it to do.

Your teacher may want to see your modified app code running on your Photon.

Download Copy of App

If you need to download a copy of your app code to your computer in order to submit it to your teacher, there are two different download icons shown in the Code Menu panel:

  1. The first icon (cloud with download arrow) to the right of "Current App" is used to download the compiled version of the app (firmware binary).

  2. The second icon (angle brackets with download arrow) to the right of "Files" is used to download a zip file containing your app source code (.ino file).

Click the second download icon to download a zip file containing your app source code:

Download Icon

In this case, the zip file will be named hello-world.zip. You'll need to uncompress the zip file to get your app source code file, which will be named hello-word.ino. If necessary, this .ino file can be opened in a text editor on your computer.

UNCOMPRESS ZIP: To uncompress a zip file downloaded to your computer:

  • On a Windows computer, right-click the zip file, and select "Extract All." Browse to the destination folder where you want to save the uncompressed file, and click "Extract."

  • On a Mac computer, just double-click the zip file.

Going Further

In the next tutorial, you'll start connect an input and output to your Photon to create a "Smart Light" device.

D-2 Connect Speaker

Your Photon kit includes a small speaker that can produce tones or play simple music (note by note).

In this step, your team will connect the speaker to your Photon circuit board using the breadboard.

You'll need these components:

  • Speaker

  • 2 jumper wires (use different colors to help identify them)

​Follow these instructions explaining how to connect the speaker. The speaker can be connected to any I/O pin capable of PWM, but connect it to the D1 pin (which will be different from the wiring diagram).

Example Wiring Diagram for a Speaker

A-1 Circuit Board

GOAL: Understand the features of your Photon circuit board (pins, ports, buttons, LED lights)

TASK: Review the information below as you examine the circuit board in your Photon kit, and answer the questions in .

Circuit Board

The SparkFun Photon kit contains a printed circuit board (PCB) that incorporates the Particle Photon P1 microcontroller, which will act like the “brain” of your IoT device. This circuit board also has various pins, ports, buttons, and LED lights. SparkFun refers to this circuit board as the Photon RedBoard (because of its color).

You can connect various inputs (such as: sensors, buttons, etc.) and outputs (such as: motors, lights, etc.) to the pins on the circuit board to create a device. Then you can control your device by programming an app that will run on the Photon microcontroller.

SparkFun Photon RedBoard

  • Photon P1 Microcontroller

  • Input/Output Pins

  • Power Supply Ports and Pins

  • Buttons

  • LED Lights

Photon Microcontroller

A microcontroller is a small computer on a single integrated circuit that contains a processor (CPU), memory, storage, and programmable input/output pins. The Photon microcontroller also has an integrated Wi-Fi chip and antenna, which makes it great for IoT devices.

Photon P1 Tech Specs

  • CPU: 32-bit 120Mhz ARM Cortex M3

  • Memory: 128KB RAM

  • Storage: 1MB Flash

  • Wi-Fi: 2.4GHz 802.11b/g/n

Compared to the tech specs of a "regular" computer, a microcontroller is much less powerful – it has a slower processor, less memory, and less storage. This is because microcontrollers are used in devices that have dedicated functions (such as: automobile engine control systems, medical devices, office machines, appliances, etc.). These dedicated devices typically don’t require as much computing power.

Firmware and Device App

A microcontroller is controlled by its firmware, which acts as its operating system. Periodically, your Photon will need to update its firmware. If this is necessary, the firmware update will occur automatically when you download a new app to your Photon over Wi-Fi.

A microcontroller is designed to store only one app, which will run automatically. If you need to change your Photon device's app, the new app has to be downloaded over Wi-Fi (and will replace the old app). You will have to code the apps for your Photon – though you'll get some practice and help to do so.

Particle Cloud

When the Photon is powered on, it will automatically try to connect to Wi-Fi (using a programmed list of Wi-Fi network logins). Once the Photon is connected to Wi-Fi, it will automatically try to connect to Particle Cloud, which is a cloud service that Particle provides for all of its microcontroller devices. All of the Photon's internet communications are routed through Particle Cloud.

Particle Cloud can be used to:

  • Code and store all your different Photon device apps (using online Particle Build code editor)

  • Update the app stored on your Photon device

  • Update the firmware on your Photon device

  • Send and receive data between your Photon device app and your web app

  • Manage your Photon device remotely

Input/Output Pins

The Photon circuit board has numerous I/O pins used to connect various inputs (such as: sensors, buttons, etc.) and outputs (such as: motors, lights, etc.). These I/O pins have small plugs that allow you to easily connect (and disconnect) the wires for inputs and outputs.

Digital Pins

The circuit board has a set of digital pins labeled as: D0, D1, D2, D3, D4, D5, D6, D7. Digital pins are used to connect inputs or outputs that use binary values (such as: HIGH or LOW, etc.). For example:

  • Digital Input: A motion sensor detects either "motion" or "no motion."

  • Digital Output: A LED light can be set to be "on" or "off."

Analog Pins

The circuit board has a set of analog pins labeled as: A0, A1, A2, A3, A4, A5. Analog pins are used to connect inputs or outputs that use a range of values (such as: 0-255, etc.) For example:

  • Analog Input: A photocell can detect a range of values based on the amount of light measured.

  • Analog Output: A speaker can produce a range of tones that have different frequencies.

TWIN PINS: Analog pins A2, A3, A4, and A5 are each represented by two pins on the Photon board. The duplicate pins are labeled as: SS/A2, SCK/A3, MISO/A4, MOSI/A5.

If you use one of these pins, you should not use its twin. For example, you could connect a part to either A2 or SS/A2 (choose only one), but you could not connect two different parts to these twin pins at the same time.

Analog Output Using PWM

Any analog pin can be used for analog inputs. However, only certain pins can be used for analog outputs. (Confusingly, some of the pins capable of analog output are labeled as digital pins.)

The Photon uses (PWM) to make a digital output signal (which has only two values: HIGH or LOW) act like an analog output signal (which has a range of values). Certain outputs (such as: speaker, servo motor, etc.) require a connection to an I/O pin capable of PWM.

These Photon pins can be used as analog outputs using PWM: A4, A5, D0, D1, D2, D3, RX, TX, WKP.

Special Pins

The circuit board also has I/O pins with "special" labels. Most of these "special" pins are used to connect with parts that require specific data communication protocols:

  • SPI Pins: SS/A2, SCK/A3, MISO/A4, MOSI/A5

    • SPI stands for "Serial Peripheral Interface"

    • For example, a Micro OLED display would be connected using the SPI pins.

  • I2C Pins: SDA/D0, SCL/D1

    • I2C stands for "Inter-Integrated Circuit"

    • For example, an accelerometer would be connected using the I2C pins.

  • UART Pins: RX, TX

    • UART stands for "Universal Asynchronous Receiver-Transmitter"

    • For example, a fingerprint scanner would be connected using the UART pins.

However, any of these "special" pins can also be used as "regular" I/O pins.

Power Supply Ports and Pins

The Photon circuit board must receive power from an external power source (such as: USB, battery, or outlet). The Photon circuit board will then supply power to any connected inputs and outputs.

Power Supply Ports

The Photon circuit board can receive power through either one of its power supply ports:

  • Barrel Jack: A barrel jack adapter can be plugged in to provide power from an external supply such as a battery, outlet, etc.

  • Micro-USB: A Micro-USB cable can be plugged in to provide power from a computer's USB port, USB charger, etc.

POWER ON/OFF: The Photon circuit board does not have an "on/off" switch. As soon as a power source is connected to the USB port or barrel jack, the Photon will power on and start running. To turn off the Photon, you have to disconnect its power source.

Power Supply Pins

The Photon circuit board can supply power to connected inputs and outputs through these pins:

POSITIVE PINS

  • I/O Pins: These pins can supply 3.3 volts (by reducing the incoming voltage from the USB or barrel jack power source). Certain inputs and outputs (but not all) get their power from an I/O pin.

  • 3.3V: This pin supplies 3.3 volts (by reducing the incoming voltage from the USB or barrel jack power source).

  • V-USB: If a power source is connected to the Micro-USB port, this pin supplies ~5 volts.

  • VIN: If an external power supply is connected to the barrel jack, this pin supplies the same voltage as the external supply (which could range from 4.5-15 volts). For example, if a 9V battery adapter were plugged into the barrel jack, this pin would supply 9 volts. If a USB adapter were plugged into the barrel jack, this pin would supply ~5 volts.

NEGATIVE PINS

  • GND: This pin acts as the ground (negative terminal) when powering inputs and outputs. The Photon circuit board has 3 available GND pins.

A breadboard can be used to connect multiple inputs and outputs to the same power supply pins. Section 1.3 of this tutorial will explain how this works.

Buttons

The Photon circuit board has two built-in buttons used for special purposes:

  • Mode: This button is used to switch your Photon between different modes such as: Connected, Listening, Safe, and Device Firmware Upgrade. Normally, you will not need to use this button.

  • Reset: This button can be used to restart your Photon – forcing it to reconnect to the internet and restart its device app. Occasionally, you might use this button to restart your app.

LED Lights

The Photon circuit board has three built-in LED lights:

  • Power: This red LED indicates the Photon is receiving power (from the barrel jack or USB). If this LED is off, then no power source is connected (or the Photon device is damaged).

  • RGB: This LED changes its to indicate the current mode and connection status of the Photon device.

  • D7: This blue LED is connected to the D7 pin and can be controlled by your Photon device app, which can be helpful for testing purposes.

Normal RGB Patterns

Whenever you connect a power source to the Photon (or restart it using the Reset button), the Photon should power on, connect to Wi-Fi, connect to Particle Cloud, and start running its device app.

During this startup process, the RGB color will change from green to cyan (light blue) and the RGB activity will change from "blinking" (fast blinking) to "breathing" (slow blinking).

Whenever the device app or firmware on the Photon is updated, the RGB will blink pink during the download and installation. Once the update is complete, the Photon will automatically restart itself.

Other RGB Patterns

If your Photon device displays one of these other RGB patterns, then the Photon has encountered an issue or has been placed into a different mode. Consult your teacher to troubleshoot your device.

More Info

The provides more details about this circuit board.

A-3 Electronic Circuits

GOAL: Understand how to create electronic circuits by connecting components to the Photon circuit board (use of power pins, I/O pins, jumper wires, and breadboard)

TASK: Review the information below to begin to understand how to use the components in your Photon kit to create electronic circuits, and answer the questions in .

Electronic Circuits

Each input and output connected to your Photon circuit board must form an , which is a continuous path that conducts electricity from the positive (+) terminal of a power source, through the input or output, and back to the negative (-) terminal of the power source.

Electronic vs. Electric

An electronic circuit is a special type of electric circuit. Here are the two key differences:

1. VOLTAGE & CURRENT

The current in an electric circuit could be only a few volts, or it could be hundreds of volts (or more). Some electric circuits operate on , while others use .

Electronic circuits always operate on low voltage direct current.

2. PURPOSE

Electric circuits transfer electricity to components (such as: light bulbs, motors, etc.) that transform some of the electrical energy into other types of energy (such as: light, motion, etc.) in order to perform a useful physical task.

Electronic circuits have special components with that use electrical signals to process and transfer information.

The electronic circuits in your IoT devices will actually do both: they will perform a useful physical task by processing and transferring information.

Parallel Circuits

Each input and output connected to your Photon should have its own circuit – i.e., its own separate path to conduct electricity without having to travel through another input or output. These are called parallel circuits. Using parallel circuits has these advantages:

  • Parallel circuits ensure each input and output receives its full voltage from the circuit board (because the voltage is not being split with another input or output on the same circuit).

  • Parallel circuits allow each input and output to be independently controlled by the circuit board.

For each parallel circuit, most of the conductive path will consist of jumper wires and the breadboard (via its internal metal strips). The rest of the conductive path will include the input or output itself (via its internal wires or circuitry) and the circuit board (via its power pins, I/O pins, and other internal circuitry).

AVOID SHORT CIRCUITS: Do NOT try this, but if you were to connect a wire directly from the positive side of a power source to the negative side (without any input or output in the middle), you would create a that leads to excessive current flow.

Short circuits can possibly: burn up your wire, damage your circuit board, damage your USB power supply, damage or drain your battery, etc.

Power for Circuit Board

The power for your circuits will be supplied by the Photon circuit board, which itself must receive power from another source.

The Photon circuit board can receive power through either one of its power supply ports:

  • Barrel Jack: A barrel jack adapter can be plugged in to provide power from an external supply such as a battery, outlet, etc.

  • Micro-USB: A Micro-USB cable can be plugged in to provide power from a computer's USB port or a USB charger.

CHOOSE ONE: Only one power source (barrel jack or Micro-USB) needs to be connected to the Photon circuit board.

CAUTION: Be careful when plugging or unplugging the Micro-USB cable to avoid breaking the Micro-USB port on the Photon. Be sure the correct side of the cable is facing up.

Power for Inputs and Outputs

The Photon circuit board can supply power to inputs and outputs through these pins:

Positive Pins

  • I/O Pins: These pins can supply 3.3 volts (by reducing the incoming voltage from the USB or barrel jack power source). Only certain inputs and outputs will get their power from an I/O pin.

  • 3.3V: This pin supplies 3.3 volts (by reducing the incoming voltage from the USB or barrel jack power source).

  • V-USB: If a power source is connected to the Micro-USB port, this pin supplies ~5 volts.

  • VIN: If a power source is connected to the barrel jack, this pin supplies the same voltage as the external source (which could range from 4.5-15 volts). For example, if a 9V battery with adapter were plugged into the barrel jack, this pin would supply 9 volts. If a USB adapter were plugged into the barrel jack, this pin would supply ~5 volts.

Negative Pins

  • GND: This pin acts as the ground (negative terminal) when powering inputs and outputs. The Photon circuit board has 3 available GND pins.

CAUTION: The inputs and outputs in your Photon kit have different power requirements:

  • Certain inputs and outputs (such as: micro OLED display, etc.) require only 3.3 volts of power – using a higher voltage could damage these components.

  • Certain inputs and outputs (such as: servo motor, etc.) require 5 volts or more – using a lower voltage could prevent these components from working.

Breadboard

A breadboard has a large number of additional pins (plugs) that are useful for connecting inputs and outputs to your circuit board. First, your inputs and outputs connect to pins in the breadboard, and then jumper wires are used to help connect those breadboard pins to specific pins on your circuit board.

One purpose of using a breadboard is it allows you to connect multiple inputs and outputs to some of the same power supply pins – while still ensuring each input and output has its own parallel circuit.

For example, the Photon circuit board has only one V-USB pin to supply 5V of power, but your device might have multiple inputs and outputs that require 5V – so the breadboard can be used to allow these components to share this one V-USB pin.

Anatomy of Breadboard

To understand how a breadboard works and is used, you need to understand the "anatomy" of your breadboard. The image on the left below shows an external view of your breadboard, while the image on the right shows what's inside the breadboard:

First, let's examine the external view of your breadboard. While the breadboard might seem like one large rectangle of holes, it actually consists of 4 smaller rectangular sections:

  1. On the far left is a power rail consisting of two columns of pins: one column is labeled as positive (+) and the other column is labeled as negative (-).

  2. In the left center is a set of terminal strips consisting of rows of pins: each row is numbered (from 1-30) and the pins within each row are lettered (from A-E).

  3. In the right center is another set of terminal strips consisting of rows of pins: each row is numbered (from 1-30) and the pins within each row are lettered (from F-J). Notice there is a divide between the left set of terminal strips and the right set of terminal strips.

  4. On the far right is another power rail consisting of two columns of pins: one column is labeled as positive (+) and the other column is labeled as negative (-).

Inside the breadboard, there are metal strips underneath the pin holes. The image of the internal view shows these metal strips – and makes it easier to visualize the 4 separate sections of the breadboard. (The red arrows are pointing to the metal strips under the power rails.)

When you plug a wire into a breadboard pin, the wire makes contact with the specific metal strip underneath that pin hole location. If another wire is plugged into another pin along the same metal strip, the metal strip will allow electricity to be conducted between the wires. If the wires are touching different metal strips, then the wires are NOT connected to each other.

These metal strips inside the breadboard act like additional wires. While these metal strips may be "hidden" inside your breadboard, they become part of your circuits as you connect inputs and outputs.

Here are some examples to help explain further how the terminal strips and power rails work:

TERMINAL STRIPS

  • If you were to plug a wire into pin A of row 1 and then plug another wire into pin E of row 1, these wires would be connected because they're touching the same metal strip.

  • If you were to plug a wire into pin A of row 1 and then plug another wire into pin F of row 1, these wires would NOT be connected because they're touching different metal strips. Remember that the terminal strip rows on the left and right sides are separate from each other.

  • If you were to plug a wire into pin A of row 1 and then plug another wire into pin A of row 2, these wires would NOT be connected because they're touching different metal strips. Remember that the terminal strip rows are separate from each other.

POWER RAILS

  • If you were to plug a wire into a pin of the positive (+) column of the left power rail and then plug another wire into another pin in the positive (+) column of the left power rail, these wires would be connected because they're touching the same metal strip.

  • If you were to plug a wire into a pin of the positive (+) column of the left power rail and then plug another wire into a pin of the negative (-) column of the left power rail, these wires would NOT be connected because they're touching different metal strips.

  • If you were to plug a wire into a pin of the positive (+) column of the left power rail and then plug another wire into a pin of the positive (+) column of the right power rail, these wires would NOT be connected because they're touching different metal strips.

Connecting Inputs and Outputs

Certain inputs or outputs can be connected directly to pins on the Photon circuit board. However, in most cases, you'll need to use the breadboard to help connect some (or all) of your inputs and outputs.

Each input or output has at least 2 wires that must be connected (one for positive and the other for negative). Some inputs or outputs have additional wires used for sending or receiving signals.

The wires for inputs and outputs connect to the pins of different terminal strips. Then jumper wires are used to connect each of these terminal strips directly (or indirectly) to its corresponding power pin or I/O pin on the Photon circuit board.

Here are two basic rules for connecting inputs and outputs to the breadboard:

  • Different wires for the same component should NOT connect to pins in the same terminal strip. For example, the temperature sensor has 4 wires that should connect to different terminal strips.

    • Jumper wires are the only exception to this rule: a jumper wire is supposed to share a terminal strip with a wire of an input or output in order to connect it directly (or indirectly) to its corresponding power pin or I/O pin on the circuit board.

  • Wires for different components should NOT connect to pins in the same terminal strip. For example, the wires of a push button and LED light should connect to different terminal strips.

    • are the only exception to this rule: a resistor is supposed to share a terminal strip with a wire of an input or output because the purpose of the resistor is to limit the amount of electric current flowing through the input or output to prevent damaging them. The LED lights and photocell (light sensor) in your Photon kit require the use of resistors.

Connecting Power Rails

Think of each power rail like a power strip you might use at home or school: you first have to plug the power strip into an outlet, and then the power strip can provide power to other devices plugged into it. Since your breadboard has two power rails (far left and far right), it's like having two power strips.

Some IoT devices won't need to use either power rail on the breadboard. However, most IoT devices will use one of the power rails. A few IoT devices might need to use both power rails (e.g., if your device has multiple components needing 3.3V as well as multiple components needing 5V).

In order to use a power rail on the breadboard to supply power to inputs or outputs, you must first use jumper wires to connect the power rail to power pins on the Photon circuit board:

  • The positive (+) column of the power rail would connect to a positive (+) pin on the Photon board (such as the 3.3V pin, V-USB pin, or VIN pin – do NOT connect a power rail to an I/O pin).

  • The negative (-) column of the power rail would connect to a negative (-) pin on the Photon board (i.e., any one of the GND pins).

Sometimes you might only need to connect the negative (-) column of a power rail. This is because every input and output needs to connect back to GND (and there are only 3 GND pins available on the Photon board). Since certain inputs and outputs use their I/O pin as their voltage source (+), sometimes it might not be necessary to connect and use the positive (+) column of the power rail.

Once a power rail has been connected to power pins on the Photon circuit board, you can use jumper wires to connect multiple inputs and outputs to this same power rail:

  • Use a jumper wire to connect the terminal strip for the ground (-) wire of the input or output to any negative (-) pin in the power rail.

  • For inputs or outputs that don't get power from their I/O pin, use a jumper wire to connect the terminal strip for the power (+) wire of the input or output to any positive (+) pin in the power rail (as long as the power rail is supplying the correct voltage required by the input or output).

All of this information about using jumper wires and the breadboard to connect inputs and outputs to the circuit board will really only make sense once you have hands-on experience building some practice devices. Tutorials 2, 3, and 4 will help provide that experience.

More Info

SparkFun has tutorials that provide more information about circuits and breadboards:

C-5 Modify Button Code

Next, you'll modify your app code to make the button toggle the LED on or off with each button press – similar to how a light switch normally works.

Global Variable for LED Status

You'll add a global variable that track the LED's current status ("off" or "on"). Whenever the button is pressed, this variable will be checked, in order to toggle the LED to the opposite status.

Declare a global variable to store the LED's status by adding this code statement before the setup() function:

This code statement declares a variable named lightStatus which has a data type of , which is the data type used for storing text. The initial value of this variable is made equal to "off".

USE DOUBLE QUOTES: Use double quotation marks to enclose your text when assigning the value of a String variable:

  • CORRECT (double quotes): String myText = "Hello World";

  • INCORRECT (single quotes): String myText = 'Hello World';

Turn Off LED in Setup

Since the lightStatus was initially set to "off", let's be sure the LED is turned off when the app starts by adding this code statement within the setup() function (after setting the LED pin mode):

Custom Function to Toggle LED

Let's create a custom function named toggleLight() that will be "called" (performed) whenever the button is pressed.

The toggleLight() custom function will check the current value of lightStatus ("off" or "on") and then toggle the LED and lightStatus to the opposite status.

Add the toggleLight() function after the loop() function (after its closing curly brace):

Now you can "call" (perform) this custom function whenever the button is pushed. A function is "called" by simply listing the function's name as a code statement.

Replace all the existing code within the loop() function (everything inside its curly braces) with this code instead:

Now when the button is pressed, the toggleLight() function will be called, performing the code within that custom function.

Notice that a brief delay() of 175 milliseconds was included. This is necessary to give people just enough time to release the button after pressing it:

  • If there is no delay (or the delay is too brief), the device will seem unpredictable because the loop() will repeat so quickly that it toggles the light multiple times for the same button press.

  • If the delay is too long, the device will seem unresponsive because the button has to be held down longer before the button press is detected.

So this delay() value shouldn't be too brief or too long – it needs to be just right. A value between 150-200 ms should work well for most people. You can test your button's behavior, and then adjust the specific value higher or lower to make your button seem more responsive.

Flash App to Device

Flash your app code to your Photon device by clicking the Flash icon in the left navigation bar.

Once your Photon has downloaded the app and restarted, the updated app will start running:

  • Confirm that the LED light toggles between "on" and "off" each time the button is pressed. (If you hold the button down, you'll see the LED continuously toggles between on and off.)

You may notice that occasionally a button press isn't detected immediately. This is normal because there will be occasions when you press the button while the Photon happens to be in the middle of the delay() period. However, if the button seems very unresponsive, you can adjust the delay() value in your app code, and then flash the updated app to your device to test the new value.

At this point, your Photon device should be operating similar to a normal light that can be switched on and off.

D-3 LED and Button Code

Next, you'll use your Smart Light device app as starter code for your Smart Security device app. The LED and button code in the two apps will be nearly identical – you'll just make a few minor changes. After that, you'll be ready to start adding new code for the motion sensor and speaker.

Log In to Particle Build

One person on your team should log in to using your team's Particle account login.

Once you're logged in, you should see a new app template in the code editor. (If not, just click the "Create New App" button in the Code menu panel.)

Title New App

Enter smart-security as your app's title.

Copy Smart Light Code

You'll use your smart-light app as starter code for your smart-security app:

  1. The Code menu panel lists all your saved apps under "My apps." Click on your smart-light app to load its code into the code editor panel. (If the Code menu panel is not visible, just click the Code icon in the left navigation bar to show the Code menu panel.)

  2. In the code editor panel, select all the existing code in your smart-light app, and copy it.

  3. In the Code menu panel, click on your smart-security app listed under "My apps" to load it into the code editor panel. (If the Code menu panel is not visible, just click the Code icon in the left navigation bar to show the Code menu panel.)

  4. Select all the existing code in your smart-security app, and then replace it by pasting in the copied code from your other app.

Save your smart-security app code by clicking the Save icon in the left navigation bar.

Modify App Code

The LED and button code in the Photon app will remain essentially the same. You'll just make some minor changes to the lightStatus variable and toggleLight() function:

  1. Change the name of lightStatus to deviceMode. There should be 6 places in the code where this change needs to be made.

  2. The possible values for lightStatus were "off" or "on". Find the 3 places in the code where "off" is listed, and change each one to "disarmed" instead. There is 1 place in the code where "on" needs to be changed to "armed" instead.

  3. Change the name of toggleLight to toggleMode. There should be 4 places in the code where this change needs to be made.

  4. In the comments at the top of the code, change Smart Light Device to Smart Security Device.

These modifications do not change how the code functions – it just makes the code make more sense when you read it, since this app will control a Smart Security device (instead of a Smart Light).

Flash App to Device

Be sure your Photon device is connected to Wi-Fi and Particle Cloud.

Flash your app code to your Photon device by clicking the Flash icon in the left navigation bar. (Particle Build will first save and verify your code before flashing it to your device.)

Once your Photon has downloaded the new app and restarted, the updated app will start running:

  • Confirm that the device still functions like the Smart Light did: the LED light should toggle between on and off each time the button is pressed. When the LED is turned on, it indicates the security system is in "armed" mode. When the LED is turned off, the security system is "disarmed."

In the next steps, you'll add code for the motion sensor and speaker to made the security system fully functional when it's "armed."

C-4 Add Button Code

Next, you'll add code in your Smart Light device app to control the LED using the push button.

The basic steps to use a push button in your app code are:

  1. Declare a global variable to store the I/O pin number for the button.

  2. Set the pin mode for the button pin in the setup() function.

  3. Use a digitalRead() statement to check whether the button is currently pressed, and add code statements that should be performed if the button is pressed (or not pressed).

Global Variable for Button Pin

Declare a global variable to store the I/O pin number for the button by adding this code statement before the setup() function:

If you connected your button to a different I/O pin other than D2, then modify this code statement to list the correct pin number for your button.

Set Pin Mode for Button

Set the pin mode for your button pin by adding this code statement within the setup() function (between the curly braces):

Turn On LED If Button Pressed

The digitalRead() method is used to check whether a button is currently pressed.

The digitalRead() method will return a value of either LOW or HIGH:

  • LOW indicates that the button is currently pressed.

  • HIGH indicates that the button is NOT currently pressed.

A variable named buttonState will store the value returned by the digitalRead() method.

An will be used to turn on the LED if the button is being pressed (if buttonState has a value equivalent to LOW).

An will be included to turn off the LED if the button is not being pressed.

Replace all the existing code within the loop() function (everything inside its curly braces) with this code instead:

COPY CODE: Remember that you can copy a code block in this guidebook simply by clicking the copy icon in the upper right of the code block.

Flash App to Device

Flash your app code to your Photon device by clicking the Flash icon in the left navigation bar.

Once your Photon has downloaded the app and restarted, the updated app will start running:

  • Confirm that the LED light that you connected to your Photon circuit board turns on when you press (and hold) the button – and turns off when the button is released.

Of course, nobody would want to continually press a button to keep a light turned on – however, this is a good way to verify that your button is connected correctly. In the next step, you'll modify the app code so the LED light toggles on or off with each button press.

Troubleshooting Issues

If the LED does not turn on when the button is pressed, then there is a mistake in your app code – or a mistake in your wiring connection – or a mistake in both.

If the LED light is turned off and pressing the button has no effect, then verify that one of the button's legs is connected (via a jumper wire) to the same I/O pin number that is assigned to the button variable in your app code. If necessary, change either your wiring or your code, so the pin numbers match. If you revised your code, flash the updated app to your device.

If that still doesn't solve the issue, then double-check all your button wiring by referring back to the connection instructions.

B-6 Loop Function

Next you'll add commands in your app code to turn the LED on and off in a repeating pattern.

Turn On LED

Your app can receive signals from inputs using the digitalRead() or analogRead() methods, depending on whether the values being received will be digital or analog.

Your app can send signals to outputs using the digitalWrite() or analogWrite() methods, depending on whether the values being sent will be digital or analog.

DIGITAL VS. ANALOG: Digital inputs and outputs use binary values (such as: HIGH vs. LOW, etc.). Analog inputs and outputs use a range of values (such as: 0-255, etc.)

The LED can be controlled as a digital output that is either "on" or "off".

You'll need to send an "on" signal to the LED pin. Add this code to your app by inserting it within the loop() function (between the curly braces):

The digitalWrite() method requires two parameters inside its parentheses (in this order):

  1. The I/O pin number, which can be the actual pin number (such as: D7, etc.) or a variable that stores a pin number. In this case, the variable LED is listed (which has a value equal to D7).

  2. The signal value, which can be HIGH or LOW. Your Photon uses this value to send an electrical signal through the pin: HIGH is a signal of 3.3 volts which represents "on," while LOW is a signal of 0 volts which represents "off." In this case, the signal was set to HIGH because you want to turn on the LED light.

Add Time Delay

You'll want to leave the LED turned on for a short amount of time before you send the "off" signal.

Because the Photon's app code runs very fast, there will be certain situations where you'll want to insert delays into the code, in order to allow time for certain events to occur. Typically, these delays are intended to give people time to perceive the event and/or respond to the event.

Your app can use the delay() method to insert a time delay. It acts like a timer that makes the app wait before performing the next line of code.

You'll need to add a delay after the LED has been turned on. Add this code to your app by inserting it (as a separate line of code) within the loop() function (after the digitalWrite() statement):

The delay() method requires one parameter inside its parentheses:

  • The time value, which can be an integer number (whole number) or a variable that stores an integer. The value represents the number of milliseconds for the delay (1000 ms = 1 second). In this case, the delay was set to 1000 ms (1 second).

Turn Off LED

Next, you'll send an "off" signal to the LED pin. Add this code to your app by inserting it (as a separate line of code) within the loop() function (after the delay() statement):

You can see that the second parameter in this digitalWrite() statement was set to LOW, which represents "off" for a digital output.

Add Another Delay

When all the code within the loop() function has been performed, the loop() will automatically repeat itself. Since the first line of code in your loop() turns on the LED, you'll want to add another delay to leave the LED turned off for a short amount of time before the loop() repeats itself.

Add this code to your app by inserting it within the loop() function (after the second digitalWrite() statement):

Now, the code within your loop() function should perform these tasks (in order):

  1. Turn On LED light

  2. Wait 1 second

  3. Turn Off LED light

  4. Wait 1 second

  5. Repeat

REPEATING LOOP: You don't need to add a command to make the loop() function repeat – it automatically repeats itself after its last line of code has been performed.

digitalWrite(LED, HIGH);
delay(1000);
digitalWrite(LED, LOW);
delay(1000);
String lightStatus = "off";
digitalWrite(LED, LOW);
void toggleLight(){
    if (lightStatus == "off") {
        digitalWrite(LED, HIGH);
        lightStatus = "on";
    }
    else {
        digitalWrite(LED, LOW);
        lightStatus = "off";
    }
}
    int buttonState = digitalRead(button);
    
    if (buttonState == LOW) {
        toggleLight();
        delay(175); // wait before trying to read button again
    }
String
int button = D2;
pinMode(button, INPUT_PULLUP);
    int buttonState = digitalRead(button);
    
    if(buttonState == LOW) {
        digitalWrite(LED, HIGH);
    }
    else {
        digitalWrite(LED, LOW);
    }
if statement
else statement

A-2 Other Components

GOAL: Identify the other components in your Photon kit and their purposes (inputs, outputs, connectors, and cables)

TASK: Review the information below, and then complete this assignment by finding each component in your Photon kit & identifying its name and function.

Physical Inputs

Your Photon kit includes these physical inputs, which can be connected to your circuit board:

  • Push Buttons – detects if button is being pushed (kit has red, yellow, green & blue buttons)

  • Trimpot Dial – detects position of dial (can be turned clockwise or counter-clockwise)

  • Motion Sensor – detects if something is moving in nearby environment

  • Magnetic Switch – detects if something is open or closed (such as door, window, etc.)

  • Photocell (Light Sensor) – measures amount of light in environment

  • Humidity & Temperature Sensor – measures relative humidity & temperature of air

  • Soil Moisture Sensor – measures amount of moisture in soil (or similar material)

  • Accelerometer – measures acceleration or tilt in 3 dimensions; can also detect taps or bumps

The following is not a standard part of the Photon kit, but your teacher may have added it:

  • Ultrasonic Sensor – measures distance to nearest object

Physical Outputs

Your Photon kit includes these physical outputs, which can be connected to your circuit board:

  • LED Lights – produces light (kit has red, yellow, green & blue LED lights)

  • Speaker – produces sound (tone) at any frequency from 20Hz to 20kHz

  • Servo Motor – rotates to any angle from 0° to ~180°

  • Micro OLED Display – displays text and simple graphics in monochrome

Connectors

Your Photon kit includes these components to help connect inputs and outputs to your circuit board:

  • Breadboard – provides additional pins to help connect and power your inputs and outputs

  • Jumper Wires – help connect inputs and outputs to pins on breadboard and circuit board

  • Resistors – help limit electric current for certain inputs or outputs (such as LED lights, etc.)

Power Cables

Your Photon kit will include one or more cables to provide power to your circuit board:

  • USB to Micro-USB Cable – powers circuit board by connecting to USB port or charger

  • 9V to Barrel Jack Adapter – powers circuit board by connecting to 9V battery

Only one power source (Micro-USB or Barrel Jack) needs to be connected.

USB to Barrel Jack: SparkFun sells a USB to Barrel Jack Adapter cable which is a great alternative to the cables included in the kit. This cable connects a USB port (computer, charger, etc.) to the barrel jack. If using this cable, the Photon's VIN pin will supply ~5 volts.

More Info

The product page for the SparkFun Inventor's Kit for Photon provides links to details about each part included in the kit. (Click the "Includes" tab on the product page to see the links to the parts.)

Creative Commons License

RGB Color

RGB Activity

Photon Device Status

Green

Blinking

Trying to connect with Wi-Fi

Cyan (light blue)

Blinking

Connected to Wi-Fi + Trying to connect with Particle Cloud

Cyan (light blue)

Breathing

Connected to Wi-Fi and Particle Cloud (device app running)

Pink

Blinking

Receiving new device app or new firmware over Wi-Fi

RGB Color

RGB Activity

Photon Device Status

Green

Breathing

Connected to Wi-Fi – but could not connect to Particle Cloud

Blue (dark blue)

Breathing

Could not connect to Wi-Fi

Blue (dark blue)

Blinking

Listening Mode (ready to add new Wi-Fi login)

Pink

Breathing

Safe Mode (does not run device app)

White

Breathing

Device's Wi-Fi module has been turned off

Orange-Yellow

Blinking

DFU Mode (ready for manual device firmware upgrade)

Red

Blinking

Firmware crash error

this document
pulse-width modulation
color and activity pattern
SparkFun Photon RedBoard Hookup Guide
SparkFun Photon RedBoard
Photon P1 Microcontroller
this document
electronic circuit
direct current (DC)
alternating current (AC)
semiconductors
short circuit
Resistors
What is a Circuit?
How to Use a Breadboard
External View of Breadboard (on left) and Internal View of Breadboard (on right)
Particle Build
Save Icon
Flash Icon

D-8 Web App CSS

Next, you'll add the CSS for your web app's stylesheet.

Add Starter CSS

​Copy this starter CSS for your web app, and paste it into a blank CSS file named style.css.

Add Custom CSS

Copy this CSS, and add it after your starter CSS:

.card {
    width: 250px;
    margin: 0 auto 20px;
    padding: 10px;
    color: black;
    background-color: white;
    border: 2px solid #aaa;
    border-radius: 10px;
    box-shadow: 0px 4px 8px rgba(0,0,0,0.2);
}

#motion-alert {
    display: none; /* hide until motion event notification */
    color: white;
    background-color: #ff3333; /* red */
}

/* CSS to change Checkbox Input into Toggle Switch */
.switch {
  position: relative;
  display: inline-block;
  width: 60px;
  height: 34px;
}

.switch input {
    display:none;
}

.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #ccc; /* gray when unchecked */
  -webkit-transition: .4s;
  transition: .4s;
}

.slider:before {
  position: absolute;
  content: "";
  height: 26px;
  width: 26px;
  left: 4px;
  bottom: 4px;
  background-color: white;
  -webkit-transition: .4s;
  transition: .4s;
}

input:checked + .slider {
  background-color: #00cc00; /* green when checked */
}

input:focus + .slider {
  box-shadow: 0 0 1px #00cc00;
}

input:checked + .slider:before {
  -webkit-transform: translateX(26px);
  -ms-transform: translateX(26px);
  transform: translateX(26px);
}

.slider.round {
  border-radius: 34px;
}

.slider.round:before {
  border-radius: 50%;
}

Your CSS should now have style declarations for several HTML elements:

  1. The CSS for body styles the <body> section of your HTML.

  2. The CSS for .card styles elements in your HTML that have class="card". There are 2 <div> elements that have this class. The first <div> will be a "card" displaying information about your security system (current mode, toggle switch for mode, and time of last motion event). The second <div> will be a "card" displaying a pop-up notification when motion is detected.

  3. The CSS for #motion-alert styles elements in your HTML that have id="motion-alert". The second <div> has this id name and will be hidden (display: none). When a motion event notification is received, your web app JS will use jQuery to briefly show this "card" and then hide it.

  4. The rest of the CSS (for .switch, .slider, and input) changes the checkbox input in your HTML to look and act like a toggle switch.

Preview Web App

If you preview the web app at this point, you can see how the CSS has changed the appearance of the web app, but it still doesn't function yet (because there's still no JS in the code.js file).

If you click your toggle switch, it will change appearance using CSS (but it requires JS to fully function).

C-2 Copy Hello World App

Next, you'll use the "Hello World" app as starter code for your "Smart Light" device app. You'll use this code to verify that you connected the LED correctly.

Log In to Particle Build

One person on your team should log in to Particle Build using your team's Particle account login.

Once you're logged in, you should see a new app template in the code editor. (If not, just click the "Create New App" button in the Code menu panel.)

Title New App

Enter smart-light as your app's title.

Copy Hello World Code

You'll use the hello-world app as starter code for your smart-light app:

/*
Hello World Test
Team Info
Teacher - Class Period
*/

int LED = D7;

void setup() {
    pinMode(LED, OUTPUT);
}

void loop() {
    digitalWrite(LED, HIGH);
    delay(1000);
    digitalWrite(LED, LOW);
    delay(1000);
}

COPY CODE: When using this IoT code guidebook, you can copy a code block simply by clicking the copy icon displayed in the upper right of the code block.

  1. Copy the "Hello World" code above.

  2. In the code editor panel, select all the existing code in the smart-light app, and then replace it by pasting in the copied code.

Save your smart-light app code by clicking the Save icon in the left navigation bar.

Save Icon

Modify App Code

You'll need to make a few changes to the app code:

  1. Modify the comment block: Change Hello World to Smart Light Device, and be sure your team info, teacher's name, and class period are correctly listed.

  2. Modify line 7 that declares the LED variable: Change the variable's value from D7 to D0 (or whichever pin number your LED is connected to). This will allow your app to control your LED.

Flash App to Device

Be sure your Photon device is connected to Wi-Fi and Particle Cloud.

Flash your app code to your Photon device by clicking the Flash icon in the left navigation bar. (Particle Build will first save and verify your code before flashing it to your device.)

Flash Icon

Once your Photon has downloaded the new app and restarted, the updated app will start running:

  • Confirm that the LED light that you connected to your Photon circuit board blinks on and off in a repeating pattern (with the light turning on for 1 second and then turning off for 1 second). The blue D7 light should be turned off.

Troubleshooting Issues

If the LED light that you connected is not blinking, then there is a mistake in your app code – or a mistake in your wiring connection – or a mistake in both.

If the blue D7 light is blinking, then check your app code to verify whether you changed the pin number assigned to the LED variable. If necessary, revise your code, and flash the updated app to your device.

Otherwise, verify that the LED light's positive leg (the bent leg) is connected (via a jumper wire) to the same I/O pin number that is assigned to the LED variable in your app code. If necessary, change either your wiring or your code, so the pin numbers match. If you revised your code, flash the updated app to your device.

If that still doesn't solve the issue, then double-check all your wiring by referring back to the connection instructions.

D-6 Particle Cloud Code

Next, you'll modify your Smart Security device app to allow a web app to interact with your Photon through the internet.

Particle Cloud

Remember that all your Photon's internet communications are routed through Particle Cloud, which provides these ways for your web app to interact with your Photon device:

  1. A web app can get the value of a Photon device variable

  2. A web app can call a custom function on a Photon device

  3. A web app can get event notifications from a Photon device

The web app that you'll be creating for your Smart Security device will perform these tasks:

  1. The web app will display whether the security device is currently armed or disarmed. The web app will do this by getting the value of the deviceMode variable in your Photon device app.

  2. The web app will display a toggle switch that can be clicked to remotely toggle the security device between armed and disarmed mode. The web app will do this by calling the toggleMode() function in your Photon device app.

  3. The web app will display a notification if the security device detects motion while the device is armed. The web app will also display the date and time when a motion event was last detected. The web app will do this by receiving event notifications sent from your Photon device app.

You'll need to add some code to your Photon device app to allow it to interact with your web app.

Share Variable and Function

Your Photon app should have existing code statements from your Smart Light app which you modified that will share the deviceMode variable and toggleMode() function through Particle Cloud.

Be sure the following code statements are already listed within the setup() function (do not add this code again if it already exists):

Particle.variable("deviceMode", deviceMode);
Particle.function("toggleMode", toggleMode);

Send Event Notification

Your Photon device app can send an event notification using theParticle.publish() method. This will create a "cloud event" in Particle Cloud that will stream the event notification to your web app.

By default, Particle Cloud will clear each cloud event after 60 seconds to prevent your web app from receiving outdated notifications.

An event notification can be sent with or without data:

  • An event notification sent without data acts like a simple alert that the event occurred.

  • An event notification sent with data will include additional information as a text string (up to 255 characters).

Particle Cloud will allow your Photon device to send about 1 event notification per second. If your device sends event notifications more frequently than this, Particle Cloud will intentionally slow down your event stream (with a 4-second delay), which can cause issues with your web app performance.

To prevent this, include a delay() of at least 1 second after a Particle.publish() statement (because a 1-second delay added by you is better than a 4-second delay added by Particle Cloud).

For your Smart Security device, your Photon app should send an event notification (without additional data) whenever the motion sensor detects motion.

Send an event notification through Particle Cloud by adding this code statement within your checkMotion() custom function (after the tone() statement but before the delay() statement):

Particle.publish("motion");

The Particle.publish() method requires a parameter for the cloud event name, which can be up to 63 characters in length. The name must be listed within double quotation marks. In this case, "motion" will be the name of the cloud event.

Since your code already has a delay() statement on the next line for the motion sensor, this existing delay() will also prevent your Photon app from sending event notifications too frequently.

Flash App to Device

Flash your app code to your Photon device by clicking the Flash icon in the left navigation bar.

Once your Photon has downloaded the app and restarted, the updated app will start running. You shouldn't notice any changes in the device's behavior, but your Photon app will now send a "motion" event notification to Particle Cloud every time motion is detected while the device is armed.

D-4 Motion Sensor Code

Next, you'll add code in your Smart Security device app to control the motion sensor.

The basic steps to use a motion sensor in your app code are:

  1. Declare a global variable to store the I/O pin number for the motion sensor.

  2. Set the pin mode for the motion sensor pin in the setup() function.

  3. Use a digitalRead() statement to check whether the sensor detects any motion, and add code statements that should be performed if motion is detected (or not detected).

Global Variable for Sensor

Declare a global variable to store the I/O pin number for the motion sensor by adding this code statement before the setup() function:

int motion = D3;

If you connected your motion sensor to a different I/O pin other than D3, then modify this code statement to list the correct pin number for your motion sensor.

Set Pin Mode for Sensor

Set the pin mode for your motion sensor pin by adding this code statement within the setup() function (between the curly braces):

pinMode(motion, INPUT_PULLUP);

Add Function to Check Sensor

The digitalRead() method is used to check whether the sensor currently detects any motion.

The digitalRead() method will return a value of either HIGH or LOW (which are treated as if they were int values):

  • HIGH indicates that motion is NOT currently detected.

  • LOW indicates that motion is currently detected.

A variable named motionState will store the value returned by the digitalRead() method.

An if statement will be used to perform a set of actions if motion is detected (if motionState has a value equivalent to LOW).

You'll add a custom function named checkMotion() that will contain all this code.

Add this checkMotion() custom function after the loop() function (you can add it before or after the toggleMode() function):

void checkMotion() {
    int motionState = digitalRead(motion);
    
    if (motionState == LOW) {
        // add code to do something if motion detected
        
        delay(2000); // wait 2 seconds before checking sensor again
    }
}

Inside the if statement, you'll need to add code to do something if motion is detected. In the next step of this tutorial, you'll add code here to make an "alarm sound" using the speaker. Later, you'll also add code to send an event notification to the web app that you'll be creating.

You'll notice that a delay() of 2 seconds is performed when motion is detected. This delay is needed to allow the sensor to capture a new "snapshot" of the environment before checking the sensor again.

Call Function in Loop If Armed

The checkMotion() function will only be performed if it is called within another function, such as the loop() function. However, the motion sensor should only be checked if the device's mode is currently set to "armed".

Add this code within the loop() function (after the closing curly brace of the existing if statement that checks the value of buttonState):

    if (deviceMode == "armed") {
        checkMotion();
    }

This code will only call the checkMotion() function if the value of deviceMode is equivalent to "armed".

Save your smart-security app code by clicking the Save icon in the left navigation bar.

Save Icon

Get Device Events

Your Photon device app can send event notifications to your web app through Particle Cloud. The event notification can also include data (in the form of a text string).

For example, your Photon device could monitor a building using motion sensors. If a sensor detects motion, an event notification could be sent to your web app to alert you. The notification could also include data, such as the location of the specific motion sensor that was triggered.

Your Photon device app will use the Particle.publish() method to send an event notification through Particle Cloud. The event notification can also include additional data (as text).

A "cloud event" will be created that sends the event notification to your web app.

Your web app will use the particle.getEventStream() method to start listening for event notifications streamed through Particle Cloud.

By default, Particle Cloud will clear each cloud event after 60 seconds. This is to prevent your web app from receiving outdated notifications.

Photon Device App

Your Photon device app will use the Particle.publish() method to send an event notification through Particle Cloud to your web app. The event notification can be sent with or without data.

Particle Cloud will allow your Photon device to send about 1 event notification per second. If your device sends event notifications more frequently than this, Particle Cloud will intentionally slow down your event stream (with a 4-second delay), which can cause issues with your web app performance.

To prevent this, include a delay() of at least 1 second after a Particle.publish() statement (because a 1-second delay added by you is better than a 4-second delay added by Particle Cloud).

Send Event Without Data

An event notification can be sent without any additional data. It acts like a simple alert of a specific event or condition occurring.

Add this code (be sure to modify) in your Photon app wherever an event notification should be sent (typically somewhere in the loop() function or a custom function):

Particle.publish("cloudEvent");
delay(1000); // 1 second delay after publishing event

In this case, the Particle.publish() method has just one parameter inside its parentheses:

  1. The cloud event name, which can be up to 63 characters in length. The name must be listed within double quotation marks. Change "cloudEvent" to the actual name that you want to use.

Send Event With Data

Alternatively, an event notification can be sent with additional data in the form of a text string.

Add this code (be sure to modify) in your Photon app wherever an event notification should be sent (typically somewhere in the loop() function or a custom function):

Particle.publish("cloudEvent", "data");
delay(1000); // 1 second delay after publishing event

In this case, the Particle.publish() method has two parameters inside its parentheses:

  1. The cloud event name, which can be up to 63 characters in length. The name must be listed within double quotation marks. Change "cloudEvent" to the actual name that you want to use.

  2. The event data, which is a text string that can be up to 255 characters in length. You can directly list the data as text within double quotation marks, or you can list the name of a String variable that stores the data. Change "data" to the actual text data (or String variable name) that should be sent with the event notification.

Web App JS

Your web app JS will use the particle.getEventStream() method to start listening for event notifications streamed through Particle Cloud.

Add this code (be sure to modify) in your web app JS:

particle.getEventStream({ deviceId: myDevice, name: "cloudEvent", auth: myToken }).then(function(stream) {
  stream.on('event', function(feed) {
    // add code to do something when event notification received
    // any text data received is stored as: feed.data
    
  });
});

MODIFY CODE: You will need to make these changes to the example code above:

  1. Change "cloudEvent" to the name of your cloud event whose value you want

  2. Add code inside the particle.getEventStream() method to do something when an event notification is received. If the event notification includes text data, the data is stored as: feed.data

The particle.getEventStream() method requires your Photon device ID, the name of your cloud event, and your Photon access token:

  1. myDevice is a global variable in your web app JS that should store your Photon device ID

  2. "cloudEvent" is the name of your cloud event that you want to receive notifications from. The name must be listed inside double quotation marks. Be sure to change "cloudEvent" to the actual name of your cloud event.

  3. myToken is a global variable in your web app JS that should store your Photon access token

If an event notification includes any data, this text data gets temporarily stored in a local variable called: feed.data

You will need to add code within the particle.getVariable() method to do something when an event notification is received – and if applicable, do something with the text stored in feed.data.

For example, you could add code to:

  • Display a message in your web app (by using jQuery to modify the HTML)

  • Change the style of your web app (by using jQuery to modify the CSS)

  • Save the text data in your web app (by assigning its value to a JS global variable)

C-7 Web App HTML

Next, you'll create a web app that will interact with your Smart Light device through Particle Cloud.

Your web app will consist of an HTML file namedindex.html, a CSS file named style.css, and a JavaScript file named script.js.

Particle Build is only used to code your Photon device app. You'll need to use a different code editor to create the HTML, CSS, and JS files for your web app. Consult your teacher to determine which code editor will be most appropriate to use for your web app files.

Add HTML

Copy this HTML, and paste it into a blank HTML file named index.html:

COPY CODE: When using this IoT code guidebook, you can copy a code block simply by clicking the copy icon displayed in the upper right of the code block.

This HTML does three main things:

  1. It loads a CSS stylesheet file.

  2. It loads three JavaScript files.

  3. It displays a "card" with the light's name, the light's status, and a button that can be clicked to remotely toggle the light on or off.

LOAD CSS STYLESHEET

In the <head> section, line 7 of the HTML has a <link> tag to load a CSS stylesheet file. The CSS stylesheet will be used to modify the appearance of certain HTML elements in your web app.

At the moment, your web app CSS file named style.css is either blank or hasn't been created yet.

LOAD JAVASCRIPT FILES

At the bottom of the <body> section, lines 16-18 of the HTML contain <script> tags to load three JavaScript files into your web app:

  1. Particle API JS library: particle.min.js

  2. jQuery JS library: jquery.min.js

  3. Your web app JS file: script.js

The contains methods to allow your web app to interact with your Photon device through Particle Cloud. You'll use Particle methods in your web app JS file.

The contains methods that make it easy to modify the content and style of your web app by dynamically changing its HTML and CSS. You'll use jQuery methods in your web app JS file.

At the moment, your web app JS file named script.js is either blank or hasn't been created yet.

DISPLAY CARD FOR LIGHT

In the <body> section of your web app, lines 10-15 of the HTML display an <h1> heading and then a <div> section that will become a "card" displaying the following information:

  1. The name of the light, which is simply named Light 1 in this case, but this could be changed to something more specific such as Desk Light, Hall Light, etc.

  2. The status of the light, which has been displayed using the placeholder text of Connecting.... Once the web app has connected to Particle Cloud, your web app JS will dynamically change this placeholder text to display the actual light status as either ON or OFF.

  3. A button to toggle the light on or off, which has been given a placeholder label of Wait. Once the web app has connected to Particle Cloud, your web app JS will dynamically change this button label to either Turn Off (if the light is currently on) or Turn On (if the light is currently off).

HTML: If you want to learn more about HTML or need a quick reference, check out the .

Preview Web App

If you preview the web app at this point, it's very plain (because there's no CSS in the style.css file) and it doesn't function yet (because there's no JS in the code.js file).

Web App Prep Steps

In order for your web app to interact with your Photon device through Particle Cloud, you'll need to complete the following preparation steps:

  1. Your web app HTML file needs to load several JS files (such as: Particle API JS library, etc.).

  2. Your web app JS file needs to create a new Particle() object.

  3. Your web app JS file needs to declare variables to store your Photon device ID and access token.

Once these steps have been completed, you'll be ready to add code in your web app JS to read device variables, call device functions, and get device event notifications.

Load JS Files

Your web app HTML file (index.html) should include <script> tags to load these JavaScript files:

  1. Particle API JS library: particle.min.js

  2. jQuery JS library: jquery.min.js

  3. Your web app JS file: script.js

The contains methods to allow your web app to interact with your Photon device through Particle Cloud. You'll use Particle methods in your web app JS file.

The contains methods that make it easy to modify the content and style of your web app by dynamically changing its HTML and CSS. You'll use jQuery methods in your web app JS file.

JQUERY = OPTIONAL: Loading jQuery is optional. However, it will be much easier to code your web app JS if you can incorporate jQuery statements.

IMPORTANT: The <script> tag in your HTML that loads the Particle API JS file (particle.min.js) must be listed before the <script> tag that loads your web app JS file (script.js). Otherwise, if their order is reversed, your web app won't be able to interact with your Photon.

Option 1: Load from CDN

If possible, use a content delivery network (such as or ) to load the Particle API JS library and jQuery JS library.

Your web app JS file will be loaded as a local file from your web app folder (where your HTML and CSS files are located).

Add this to your web app HTML file within the <body> section (just before the closing </body> tag):

Option 2: Load Local Files

Alternatively, you could download local copies of the Particle API JS library and jQuery JS library. You will want the minified version of each file (min.js), which has a smaller file size. If necessary, consult with your teacher to be sure you obtain the correct files.

Place the copies of the files into your web app folder (where your HTML and CSS files are located).

Add this to your web app HTML file within the <body> section (just before the closing </body> tag):

Be sure the file names listed in the <script> tags match the file names in your web app folder.

Create Web App JS File

Be sure your web app folder contains a JavaScript file named: script.js

This web app JS file will contain your JavaScript code to interact with your Photon device through Particle Cloud. Your JS code will also dynamically modify your HTML and CSS to display updated information from your Photon device.

Create Particle Object

The Particle API JS library defines a class called Particle() that can be used to create an object variable with built-in methods (functions) to interact with a Photon device through Particle Cloud.

Your web app JS code must create a new Particle() object, and assign it to a global variable, which is typically just named particle.

Add this code statement at the beginning of your web app JS code:

Device ID & Access Token

In order for a web app to interact with a Photon device through Particle Cloud, the web app must provide a correct device ID and access token with each request. This ensures your web app communicates with the correct device – and prevents unauthorized apps from communicating with your device.

Your web app JS code will declare global variables to store your Photon device ID and access token. You'll get their values from your Particle Build account.

Add this code towards the beginning of your web app JS code, and then modify it:

IMPORTANT: You must modify this JS code to insert your actual Photon device ID and access token. Otherwise, your web app will not work properly.

Your Photon's unique device ID is listed in the Devices menu of your Particle Build account:

  1. Click the Devices icon in the left navigation bar.

  2. In the Devices menu panel, click the drop-down arrow to the right of your Photon device name.

  3. Select and copy the device ID.

  4. Paste the device ID into your JS code as the value for myDevice (the device ID must be listed within quotation marks).

Your Photon's unique access token is listed in the Settings menu of your Particle Build account:

  1. Click the Settings icon in the left navigation bar.

  2. In the Settings menu panel, select and copy the access token.

  3. Paste the access token into your JS code as the value for myToken (the access token must be listed within quotation marks).

RESET TOKEN: If desired, you can reset your access token in the Settings menu of Particle Build. This generates a new random access token. However, your existing web apps will need to be updated with the new access token, in order to connect to Particle Cloud.

<script src="https://cdnjs.cloudflare.com/ajax/libs/particle-api-js/7.3.0/particle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="script.js"></script>
<script src="particle.min.js"></script>
<script src="jquery.min.js"></script>
<script src="script.js"></script>
var particle = new Particle();
var myDevice = "0000"; // Photon device ID
var myToken = "0000"; // Photon access token
Particle API JS library
jQuery JS library
cdnjs
jsDelivr
<!DOCTYPE html>
<html>
    <head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smart Light</title>
        <link href="style.css" rel="stylesheet" type="text/css">
    </head>
    <body>
        <h1>My Smart Lights</h1>
        <div id="light1" class="card">
            <h2 id="light1-name">Light 1</h2>
            <h2 id="light1-status">Connecting...</h2>
            <button id="light1-button" onclick="toggleLight1();">Wait</button>
        </div>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/particle-api-js/7.3.0/particle.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        <script src="script.js"></script>
    </body>
</html>
Particle API JS library
jQuery JS library
W3Schools HTML Tutorial and Reference

Particle Build

What's Particle Build?

​Particle Build is an online code editor (web IDE) provided by Particle. Particle Build is part of the Particle Cloud platform. You will use Particle Build to code and store all your Photon device apps.

The Photon device itself can only store and run one app at a time. However, you can create and save multiple apps in Particle Build. When you need to update the specific app stored on your Photon device, you'll do this in Particle Build – and your Photon will download the new app over Wi-Fi.

Your team will need a Particle account to log in to Particle Build. However, your teacher will most likely provide your team with an existing Particle account login (email & password) that's already associated with your specific Photon device. Every Photon has a unique device ID it uses to communicate with Particle Cloud, and each device ID can only be associated with one Particle account.

One person on your team should log in to Particle Build using your team's Particle account login.

Once you're logged in, you'll see the Particle Build code editor, which defaults to the "Code" menu and shows a blank app template.

Particle Build User Interface

The user interface for Particle Build is divided into 4 sections:

  • On the far left is a vertical navigation bar with icons.

  • On the middle left is a menu panel showing options for the current navigation selection.

  • On the right side is the code editor panel showing the code for your current app.

  • On the bottom of the code editor panel is a horizontal status bar that displays messages.

Navigation Bar

If you hover your mouse pointer over an icon in the navigation bar, the icon's name will be displayed. Here is a summary of the navigation icons from top to bottom:

Icon

Name

Purpose

​

Flash

Flashes the current app to your Photon device over Wi-Fi (The app will first be saved and verified. If there are errors in the app, it will not be flashed.)

​

Verify

Complies the current app to check for errors (The app will first be saved.)

​

Save

Saves the current app in Particle Build

​

Code

Lists all your saved apps. Click an app's title to open it in the code editor.

​

Libraries

Lists libraries that can be included in your app to add functionality

​

Help

Lists quick help for device (might not be available for your Photon)

​

Docs

Opens new tab with Particle Reference Documentation for your device

​

Devices

Lists your devices. You can view the device ID, and signal device over Wi-Fi. (If you have multiple devices, you can select which device to flash apps to.)

​

Console

Opens new tab with Console showing your device's events in Particle Cloud

​

Settings

Provides options to: log out, change password, or get your access token.

Toggle the Menu Panel

The middle menu panel can be toggled between "show" and "hide" by clicking the same navigation icon repeatedly.

In general, you'll probably want to keep the menu panel shown – but if you want extra space for your code editor panel, you can temporarily hide the menu panel.

Speaker

The small speaker included in the Photon kit can produce tones or play simple music (note by note). The speaker can produce tones ranging in frequency from 20Hz (very low pitch) to 20KHz (very high pitch), covering the full range of sounds that humans can hear.

How to Connect Speaker

A speaker is a part, meaning there is one way to correctly connect its positive and negative terminals. If a polarized part is connected incorrectly (by switching the positive and negative), the part may not work or could become damaged.

The speaker in your Photon kit has a positive leg and a negative leg. These can be identified by labels on the bottom of the speaker:

Also, there is a positive symbol ( ⊕ ) printed on the side of the speaker to identify which side has the positive leg. This allows you to verify the polarity while the speaker is plugged into a breadboard.

Requires PWM Pin

The positive leg of the speaker must be connected to an I/O pin capable of (PWM), which is a process used to make a digital output signal (which has only two values: HIGH or LOW) act like an analog output signal (which has a range of values).

These Photon I/O pins are capable of PWM output: A4, A5, D0, D1, D2, D3, RX, TX, WKP.

Connect to Breadboard

To connect a speaker to your Photon using the breadboard, you will need:

  • Speaker

  • 2 jumper wires (use different colors to help identify them)

Here are the steps to connect the speaker to your Photon using the breadboard:

  1. Insert the positive and negative legs of the speaker into different terminal strip rows on the breadboard. (Different terminal strip rows have different row numbers.)

  2. Plug one end of a jumper wire into the same terminal strip row as the positive leg of the speaker. Plug the other end of this jumper wire into a PWM-capable I/O pin on the Photon circuit board.

  3. Plug one end of the other jumper wire into the same terminal strip row as the negative leg of the speaker. Plug the other end of this jumper wire into a pin hole connected to GND: either plug it into a negative power rail on the breadboard (which is connected to GND via a different jumper wire), or plug it directly into a GND pin on the Photon circuit board.

Here's a wiring diagram showing a possible way to connect a speaker:

Keep in mind that your connection can look different than this example diagram:

  • Your speaker legs could be inserted into different row numbers on the breadboard. (The example connects the negative leg to row 3 and the positive leg to row 5.)

  • Your speaker legs could be inserted into a different column on the breadboard. (The example connects the LED legs into column F of the terminal strip rows.)

  • The positive leg of your speaker could connect to a different I/O pin capable of PWM output. (The example connects to the D2 pin.)

  • The negative leg of your speaker could connect (through a jumper wire) either to a different GND pin or to a negative power rail connected to a GND pin. (There are three available GND pins.)

How to Code Speaker

The basic steps to control a speaker in your app code are:

  1. Declare a global variable to store the I/O pin number for the speaker.

  2. Set the pin mode for the speaker pin in the setup() function.

  3. Use tone() statements to produce sounds.

Global Variable

You should declare a global variable to store the I/O pin number that the speaker is connected to. This will make it easier to understand your code (and easier to modify the code if you were to connect the speaker to a different pin number).

Add this code statement (modify if necessary) before the setup() function:

This line of code does 3 things (in order):

  1. It declares a data type for the variable's value. In this case, int stands for integer (whole number). Photon pin numbers are always treated as int values (even though they have letters).

  2. It declares the variable's name. In this example, the variable will be called speaker. You can change the variable name, but choose a name that will make sense to anyone reading the code.

  3. It assigns a value to the variable. In this example, the variable's value will be equal to D2. If necessary, modify this value to match the actual I/O pin that your speaker is connected to.

Set Pin Mode

You need to set the pin mode for the speaker to be used as an output.

Add this code statement (modify if necessary) within the setup() function:

The pinMode() method requires two parameters inside its parentheses (in this order):

  1. The I/O pin number, which can be the actual pin number (such as: D0, etc.) or a variable that stores a pin number. In this example, a variable named speaker is listed. If necessary, change this to match the variable name for your speaker.

  2. The mode value, which will always be OUTPUT for a speaker.

Produce Tone

The tone() method is used to produce a sound of a specific frequency (pitch) for a specific duration of time. The speaker can produce tones ranging in frequency from 20Hz (very low pitch) to 20KHz (very high pitch), which covers the full range of sounds that humans can hear.

Add this code statement (modify as necessary) to your app within the setup() function, loop() function, or a custom function:

The tone() method requires three parameters inside its parentheses (in this order):

  1. The I/O pin number, which can be the actual pin number (such as: D2, etc.) or a variable that stores a pin number. In this example, a variable named speaker is listed. If necessary, modify this to match the variable name for your speaker.

  2. The frequency for the tone, which can be an integer value (whole number) or a variable that stores an integer. The value can be between 20-20000 hertz. Lower numbers will have a lower pitch, while higher numbers will have a higher pitch. In this example, the frequency will be 2000 hertz. Modify this value to the frequency you want for your sound.

  3. The duration for the tone, which can be an integer number (whole number) or a variable that stores an integer. The value represents the number of milliseconds that the tone will be played (1000 ms = 1 second). In this example, the duration will be 250 ms (0.25 seconds).

VOLUME: There isn't a way to change the volume of a tone produced by your Photon. However, you will notice that certain frequencies will naturally seem louder to your ears.

Continuous Tone

If you want to produce a continuous tone that keeps playing, you can either use a negative value for the duration – or you can leave out the duration parameter entirely:

To turn off a continuous tone, use the noTone() method when you're ready to stop the sound:

Get Device Variable

Your Photon device app can share a variable through Particle Cloud, so your web app can get the value of the variable.

For example, your Photon device app could measure the temperature of a room using a sensor, store the measurement in a variable, and share this variable's value through Particle Cloud, so your web app can get the variable's value and display it.

Your Photon device app will use the Particle.variable() method to share the value of a device variable through Particle Cloud.

A "cloud variable" will be created to store the value of your device variable. Whenever the value of your device variable changes, the value stored in the cloud variable will be automatically synced to match.

Your web app will use the particle.getVariable() method to get the value of your cloud variable.

Photon Device App

Your Photon device app will use the Particle.variable() method to share the value of a device variable through Particle Cloud by creating a cloud variable.

Add this code statement (be sure to modify) within the setup() function of your Photon app:

The Particle.variable() method requires two parameters inside its parentheses (in this order):

  1. The cloud variable name, which can be up to 12 characters in length. If possible (for simplicity), make your cloud variable name match your device variable name. However, the cloud variable is allowed to have a different name. The cloud variable name must be listed within double quotation marks. Change "cloudVar" to the actual name that you want to use for the cloud variable.

  2. The Photon device variable name, which is the variable in your Photon device app whose value will be shared in Particle Cloud. Change deviceVar to the actual name of the variable in your Photon app that you want to share.

Particle Cloud will let your Photon device share up to 20 cloud variables at one time. Each of your cloud variables in Particle Cloud has to be given a unique name (up to 12 characters in length).

If your Photon device app needs to share multiple variables, use a separate Particle.variable() statement for each device variable being shared.

Allowed Data Types

NOTE: The only data types that are allowed to be shared as cloud variables are:

  • int (whole numbers)

  • double (decimal numbers)

  • String (text, up to 622 characters)

Be sure each Photon device variable being shared as a cloud variable uses one of these data types.

Web App JS

Your web app JS will use the particle.getVariable() method to get the value of a Photon device variable stored as a cloud variable in Particle Cloud.

Add this code (be sure to modify) in your web app JS:

MODIFY CODE: You will need to make these changes to the example code above:

  1. Change webFunction() to the name you want to use for your custom function

  2. Change "cloudVar" to the name of your cloud variable whose value you want

  3. Add code inside the particle.getVariable() method to do something with the variable value returned as: data.body.result

This code adds a custom function named webFunction() to your web app JS. This custom function contains a call to the particle.getVariable() method, which will also contain code you'll add to perform action(s) based on the variable value returned by Particle Cloud.

Be sure to change webFunction() to the actual name that you want to use for this JS function. For example, if the function is supposed to get the value of a temperature variable from your Photon device, you might name the function something like: getTemperature()

The particle.getVariable() method requires your Photon device ID, the name of your cloud variable, and your Photon access token:

  1. myDevice is a global variable in your web app JS that should store your Photon device ID

  2. "cloudVar" is the name of your cloud variable, which must be listed inside double quotation marks. Be sure to change "cloudVar" to the actual name of your cloud variable.

  3. myToken is a global variable in your web app JS that should store your Photon access token

When Particle Cloud returns the value of your cloud variable, this value gets temporarily stored in a local variable called: data.body.result

You will need to add code within the particle.getVariable() method to do something with the value stored in data.body.result.

For example, you could add code to:

  • Display the value in your web app (by using jQuery to modify the HTML)

  • Change the style of your web app based on the value (by using jQuery to modify the CSS)

  • Save the value in your web app (by assigning the value to a JS global variable)

Set Interval to Get Variable

If your web app needs to continuously monitor the value of a cloud variable, you can use the window.setInterval() method to automatically call (perform) a function at a set time interval (such as every 0.5 seconds, etc.).

Add this code statement (be sure to modify) near the top of your web app JS:

The window.setInterval() method requires two parameters inside its parentheses (in this order):

  1. The name of the function to be called, which will be the name of the custom function in your JS that contains the particle.getVariable() method for the variable you need to continuously monitor. The custom function's name should be listed without a set of parentheses. Change webFunction to the name of your custom function.

  2. The time interval between calls, which will be the amount of time between each call to the function. The time interval is specified in milliseconds (1000 ms = 1 second). In this case, the interval was set to 2000 ms (2 seconds). Change this value to an appropriate time interval for your web app.

Getting Multiple Variables

If you want to get the values of multiple cloud variables at the same time, you can include separate calls to the particle.getVariable() method within the same custom function:

If your web app needs to get different cloud variables at different times, then create separate custom functions to get each cloud variable individually:

Photon Device App

All the apps that run on your Photon device will be coded using Particle's version of the open-source Wiring programming language framework for microcontrollers.

The Particle firmware on your Photon runs a modified version of the Wiring language with a few minor differences, as well as some additional methods (functions) customized for the Photon hardware.

WIRING VS. ARDUINO: Arduino is another programming language framework for microcontrollers. It turns out that Arduino is based on Wiring, so the two languages are nearly identical (though there are some differences). In most cases, a program originally written in Arduino will work on your Photon with only minor revisions. So once you've learned how to program in one of these languages, you've basically learned both.

WIRING VS. C++: Wiring (like Arduino) is a programming framework written in C++, so you can also directly incorporate C++ code within your device app.

Photon App Template

When you create a new device app in Particle Build, a basic app template is provided that consists of an empty setup() function and an empty loop() function:

void setup() {​

}

​void loop() {​

}

If you want an app template that provides more guidance, you can replace the default app template with the code below, which has some comments to explain each major section of your app:

/*
Team Name
App Title
*/

// global variables - store pin numbers and other data used in functions


// setup() function runs one time when app first starts - set pin modes, etc.
void setup() {

}

// after setup() finishes, loop() function runs repeatedly - main tasks of app
void loop() {

}

// custom functions - tasks or subtasks usually called within loop() function

COPY CODE: When using this IoT code guidebook, you can copy a code block simply by clicking the copy icon displayed in the upper right of the code block.

Setup Function

Every Photon device app must have one (and only one) setup() function. You can add lines of code between this function's opening and closing curly braces.

The setup() function will run one time when your app first starts (which is when your Photon is first powered on – or is restarted using its Reset button).

The code added within the setup() function typically sets pin modes for the device's inputs and outputs, initializes settings for certain inputs and outputs, or performs other "setup" actions that need to occur at the start of the program.

Even if you didn't add any code within the setup() function, your app must still have this function.

Loop Function

Every Photon device app must have one (and only one) loop() function. You can add lines of code between this function's opening and closing curly braces.

After the setup() function is done running, the loop() function will start to run. When all the code within the loop() function has been performed, the loop() function will automatically run itself again. It keeps running in an endless loop (until the device is restarted or powered off).

The code added within the loop() function performs the main tasks of your program.

Even if you didn't add any code within the loop() function, your app must still have this function.

VOID: Why is void listed before the setup() and loop() functions? This is because each function in your Photon device app must declare a data type (such as: integer, boolean, etc.) for the data value returned by the function. In this case, void indicates the function does NOT return any data value.

Other Sections of App

Besides having the required setup() and loop() functions, your Photon device apps will typically have some or all of the following:

  • Comments

  • Libraries

  • Global Variables

  • Custom Functions

Comments

Comments are optional notes that you can insert to help explain or clarify portions of the code to anyone reviewing the program. Comments can be single-line or multi-line blocks.

It's a good idea to have at least one comment at the beginning of your app code to provide a name and/or description of your app.

Any comments in your app are ignored when the program is compiled and uploaded to your device.

// Comments are notes to yourself or others reading your code
// Each single-line comment starts with two forward slashes
​
/*
A multi-line comment block starts with a forward slash and asterisk
You can include as many lines of notes in the block as you need
A multi-line comment block ends with an asterisk and forward slash
*/

Libraries

Some device apps might include (i.e., import) one or more library files. A library is a file of pre-built code that provides additional functions that your program can utilize. For example, certain inputs and outputs have their own code library with functions to make it easier to control the input or output.

Particle Build has a Libraries menu where you can search for existing libraries (or upload your own library file that you've created). When you select a library to be added to your app, Particle Build will automatically insert an #include statement for the library at the beginning of your app code.

Global Variables

Your device app will typically have code that declares global variables which store data used in your program's functions, such as pin numbers for sensors, etc.

Global variables are usually listed before the setup() function (to make it easier to read the code).

Custom Functions

You can also add your own custom functions to your device app. Each custom function must have a unique function name.

Custom functions are typically used to contain code that performs specific tasks or subtasks. Having custom functions in your app is optional, but they can help break up your code into smaller modules that are easier to understand (and easier to re-use). So rather than listing all your main program code within the loop() function, you can subdivide some or all of the code into custom functions.

The code within a custom function is only run if and when that custom function is "called" (by listing the function's name) within the setup() or loop() function. A custom function can also be "called" within another custom function.

Custom functions are usually listed after the loop() function (to make it easier to read the code).

Resources

If you want to learn more about programming your Photon device, consult these references:

  • Wiring Programming Reference

  • Particle Firmware Reference

Speaker

Photon Pin

Positive Leg

any I/O pin capable of PWM output

Negative Leg

GND

int speaker = D2;
pinMode(speaker, OUTPUT);
tone(speaker, 2000, 250);
tone(speaker, 2000); // continuous tone of 2000 hertz
noTone(speaker);
polarized
pulse-width modulation
Speaker (side view)
Speaker (bottom view): Polarity Labels for Legs
Particle.variable("cloudVar", deviceVar);
function webFunction() {
    particle.getVariable({ deviceId: myDevice, name: "cloudVar", auth: myToken }).then(function(data) {
        // add code to do something with value returned as: data.body.result
        
        
    }, function(err) {
        console.log("An error occurred:", err);
    });
}
window.setInterval(webFunction, 2000);
function webFunction() {
    // get 1st variable
    particle.getVariable({ deviceId: myDevice, name: "cloudVar1", auth: myToken }).then(function(data) {
        // add code to do something with value returned as: data.body.result
        
        
    }, function(err) {
        console.log("An error occurred:", err);
    });

    // get 2nd variable
    particle.getVariable({ deviceId: myDevice, name: "cloudVar2", auth: myToken }).then(function(data) {
        // add code to do something with value returned as: data.body.result
        
        
    }, function(err) {
        console.log("An error occurred:", err);
    });
}
function webFunction1() {
    particle.getVariable({ deviceId: myDevice, name: "cloudVar1", auth: myToken }).then(function(data) {
        // add code to do something with value returned as: data.body.result
        
        
    }, function(err) {
        console.log("An error occurred:", err);
    });
}

function webFunction2() {
    particle.getVariable({ deviceId: myDevice, name: "cloudVar2", auth: myToken }).then(function(data) {
        // add code to do something with value returned as: data.body.result
        
        
    }, function(err) {
        console.log("An error occurred:", err);
    });
}

Call Device Function

Your Photon device app can share a custom function through Particle Cloud, so your web app can call the function to make it run on your Photon device.

For example, your Photon device app could share a custom function that toggles an LED light on or off, so your web app would be able to call this function to remotely turn the light on or off.

Your Photon device app will use the Particle.function() method to share a custom function through Particle Cloud.

A "cloud function" will be created that acts like a reference to the custom function in your device app.

Your web app will use the particle.callFunction() method to make the custom function run on your Photon device by calling its cloud function reference.

Photon Device App

Your Photon device app will use the Particle.function() method to share a custom function through Particle Cloud by creating a cloud function. In addition, you will also need to modify the custom function to work with Particle Cloud.

Share Device Function

Add this code statement (be sure to modify) within the setup() function of your Photon app:

Particle.function("cloudFunc", deviceFunc);

The Particle.function() method requires two parameters inside its parentheses (in this order):

  1. The cloud function name, which can be up to 12 characters in length. If possible (for simplicity), make your cloud function name match your device function name. However, the cloud function is allowed to have a different name. The cloud function name must be listed within double quotation marks without parentheses after its name. Change "cloudFunc" to the actual name that you want to use for the cloud function.

  2. The Photon device function name, which is the custom function in your Photon device app that will be shared through Particle Cloud. List the function name without parentheses after its name. Change deviceFunc to the actual name of the custom function in your Photon device app that you want to share.

Particle Cloud will let your Photon device share up to 15 cloud functions at one time. Each of your cloud functions in Particle Cloud has to be given a unique name (up to 12 characters in length).

If your Photon device app needs to share multiple functions, use a separate Particle.function() statement for each device function being shared.

Modify Device Function

In order to share a custom function in your Photon device app with Particle Cloud, the custom function must be modified to do the following:

  • The custom function must accept a String parameter when the function is called.

  • The custom function must return an integer value when the function is performed.

For example, a typical custom function in your device app would have this generic format:

void deviceFunc() {
    // code statements to be performed by function
}

The code for this custom function would need to be modified to accept a String parameter (i.e., text) and return an integer value (i.e., whole number). Here's a modified version of the function:

int deviceFunc(String data) {
    // code statements to be performed by function
    return 1;
}

Here are the 3 modifications that were made to the custom function:

  1. String data is listed inside the parentheses after the function name. This represents the parameter that the function will accept: String is the data type for the parameter (i.e., text) , and data is the name of a local variable that will receive and store the parameter value (text string). If desired, you could use a different variable name other than data.

  2. int is listed in front of the function name (instead of void), which indicates the function will return an integer value (whole number).

  3. The code statement return 1; is included inside the function (at the end before the closing curly brace), which will return an integer value of 1. This is the simplest way to have the function return a value.

IMPORTANT: Your custom function must have these modifications – even if your custom function doesn't do anything with the text passed into the data parameter – and even if your device app doesn't do anything with the integer value returned by the custom function.

Calling Device Function

Once a custom function in your Photon device app has been modified to be shared through Particle Cloud, your Photon app (and your web app) must include a text parameter when calling the function.

If the custom function doesn't actually do anything with the parameter, then this text string parameter can be any text – even an empty text string of "" will work.

For example, in your Photon app, a code statement to call the custom function would be:

deviceFunc("text");
  • deviceFunction represents the name of the custom function. Change this to the name of your custom function.

  • "text" represents the text string being passed into the function as a parameter. If this text parameter isn't actually used within the function, then it can be any text string enclosed within double quotation marks – even an empty text string of "" will work.

Using String Parameter

As stated previously, the Photon device function being shared through Particle Cloud must accept a String parameter. The function doesn't actually have to do anything with this text data (other than receive it when the function is called).

However, depending on what your custom function does, the text string passed into the data parameter could be used to decide what action(s) are performed within the custom function.

For example, imagine you created a custom function named turnLight() to turn an LED light either on or off based on the value of a text string passed into the function as a parameter:

int turnLight(String data) {
    if(data == "on")
        digitalWrite(LED, HIGH);
    }
    else if(data == "off") {
        digitalWrite(LED, LOW);
    }
    return 1;
}

To turn on the LED, your Photon app (or your web app) would call turnLight() and include"on" as the parameter. In your Photon app, the code statement would be: turnLight("on");

To turn off the LED, your Photon app (or your web app) would call turnLight() function and include "off" as the parameter. In your Photon app, the code statement would be: turnLight("off");

Web App JS

Your web app JS will use the particle.callFunction() method to make a custom function run on your Photon device by calling its cloud function reference in Particle Cloud.

Add this code (be sure to modify) in your web app JS:

function webFunction() {
    particle.callFunction({ deviceId: myDevice, name: "cloudFunc", argument: "text", auth: myToken });
}

MODIFY CODE: You will need to make these changes to the example code above:

  1. Change webFunction() to the name you want to use for your custom function

  2. Change "cloudFunc" to the name of your cloud function you want to call

  3. If necessary, change "text" to a different text parameter – only necessary if your Photon device function uses the text parameter to decide what actions are performed.

This code adds a custom function named webFunction() to your web app JS. This custom function contains the particle.callFunction() method.

Be sure to change webFunction() to the actual name that you want to use for this JS function. If helpful, you could use the same name as the Photon device function being called. For example, if the JS function is supposed to call a function named toggleLight() in your Photon device app, you could also name the JS function as toggleLight().

The particle.callFunction() method requires your Photon device ID, the name of your cloud function, an argument (a String parameter for the Photon function), and your Photon access token:

  1. myDevice is a global variable in your web app JS that should store your Photon device ID

  2. "cloudFunc" is the name of your cloud function, which must be listed inside double quotation marks. Be sure to change "cloudFunc" to the actual name of your cloud function.

  3. "text" is the String parameter that will be passed into the Photon device function. If this text parameter isn't actually used within the Photon function, then it can be any text string enclosed within double quotation marks – even an empty text string of "" will work.

  4. myToken is a global variable in your web app JS that should store your Photon access token

Calling JS Function

Your web app will need a way to call the JS function which contains the particle.callFunction() method that makes a function run on your Photon device.

One common way to do this is to add a button in your web app HTML that can be clicked by the user. The button should have an onclick event attribute that will call the JS function (which will in turn call your Photon function).

Add this to your web app HTML file within the <body> section where you want the button to appear:

<button onclick="webFunction()">Button Label</button>
  • Change webFunction() to the name of the JS function to be called when the button is clicked. This should be a JS function that contains a particle.callFunction() method.

  • Change Button Label to whatever text you want displayed in the button as its label. Be sure to use a label that will make sense to the user.

NOTE: You could use a different HTML element other than a button. Just be sure it will be clear to the user that the element is "clickable" (and it's clear what will happen when it is clicked).

Motion Sensor

The motion sensor included in your Photon kit uses passive infrared (PIR) light to detect movement in the surrounding environment up to about 10 feet away.

Motion Sensor

How to Connect Motion Sensor

The motion sensor has a 3-wire JST connector with 3 pins for plugging into a breadboard. (If the end of your connector doesn't have 3 metal pins, attach the JST right angle connector included in your kit.)

To connect a motion sensor to your Photon using the breadboard, you will need:

  • Motion sensor (with 3-pin JST right angle connector)

  • 3 jumper wires (use different colors to help identify them; it may help to match the sensor wires)

Motion Sensor

Photon Pin

Black - Data

any I/O pin

White - Ground

GND

Red - Power (5-12V)

5V through VIN or V-USB

5V REQUIRED: The motion sensor requires 5V of power to operate.

  • If your Photon is being powered through the barrel jack, connect to the VIN pin.

  • If your Photon is being powered through the Micro-USB port, connect to the V-USB pin.

Here are the steps to connect the motion sensor to your Photon using the breadboard:

  1. Insert the 3 pins of the motion sensor connector into different terminal strip rows on the breadboard. (Different terminal strip rows have different row numbers.)

  2. Plug one end of a jumper wire into the same terminal strip row as the sensor's black wire. Plug the other end of this jumper wire into an I/O pin on the Photon circuit board.

  3. Plug one end of a second jumper wire into the same terminal strip row as the sensor's white wire. Plug the other end of this jumper wire into a pin hole connected to GND: either plug it into a negative power rail (which is connected to GND via a different jumper wire), or plug it directly into a GND pin on the Photon circuit board.

  4. Plug one end of a third jumper wire into the same terminal strip row as the sensor's red wire. Plug the other end of this jumper wire into either the VIN pin or V-USB pin on the Photon circuit board (or to a positive power rail on the breadboard that is connected to VIN or V-USB). If your Photon is being powered through the barrel jack, connect to the VIN pin. Otherwise, if your Photon is being powered through the Micro-USB port, connect to the V-USB pin.

Here's a wiring diagram showing a possible way to connect a motion sensor:

Keep in mind that your connection can look different than this example diagram:

  • Your motion sensor pins could be inserted into different row numbers. (The example connects the sensor pins to rows 16-18 on the left side of the breadboard.)

  • Your motion sensor pins could be inserted into a different column of the breadboard. (The example connects the sensor pins into column A of the terminal strip rows.)

  • Your sensor's black wire could connect (through a jumper wire) to a different I/O pin. (The example connects to the D0 pin.)

  • Your sensor's white wire could connect (through a jumper wire) to either to a different GND pin or to a negative power rail connected to a GND pin. (There are three available GND pins.)

  • Your sensor's red wire could connect (through a jumper wire) to either the VIN pin or V-USB pin (or to a positive power rail that's connected to one of these pins). (The example connects directly to the V-USB pin.)

How to Code Motion Sensor

The basic steps to use a motion sensor in your app code are:

  1. Declare a global variable to store the I/O pin number for the motion sensor.

  2. Set the pin mode for the motion sensor pin in the setup() function.

  3. Use a digitalRead() statement to check whether the sensor detects any motion, and add code statements that should be performed if motion is detected (or not detected).

Global Variable

You should declare a global variable to store the I/O pin number that the motion sensor's data wire is connected to. This will make it easier to understand your code (and easier to modify the code if you were to connect the motion sensor to a different pin number).

Add this code statement (modify if necessary) before the setup() function:

int motion = D0;

This line of code does 3 things (in order):

  1. It declares a data type for the variable's value. In this case, int stands for integer (whole number). Photon pin numbers are always treated as int values (even though they have letters).

  2. It declares the variable's name. In this example, the variable will be called motion. You can change the variable name, but choose a name that will make sense to anyone reading the code.

  3. It assigns a value to the variable. In this example, the variable's value will be equal to D0. If necessary, modify this value to match the actual I/O pin number that your button is connected to.

Set Pin Mode

You need to set the pin mode for the motion sensor to be used as an input.

Add this code statement (modify if necessary) within the setup() function:

pinMode(motion, INPUT_PULLUP);

The pinMode() method requires two parameters inside its parentheses (in this order):

  1. The I/O pin number, which can be the actual pin number (such as: D0, etc.) or a variable that stores a pin number. In this example, a variable named motion is listed. If necessary, change this to match the variable name for your button.

  2. The mode value, which will always be INPUT_PULLUP for a motion sensor.

Check If Motion Detected

The digitalRead() method is used to check whether the sensor currently detects any motion.

Add this code (modify as necessary) to your app within the loop() function or a custom function:

int motionState = digitalRead(motion);

if(motionState == LOW) {
​    // add code to do something if motion detected
​
    delay(2000); // wait 2 seconds before checking sensor again
}

In the first code statement, a local variable named motionState is declared that will have a data type of int (integer). This variable is made equal to whatever value is returned by the digitalRead() method. You can change the name of this variable, but it will make sense if it's similar to the variable name used for the motion sensor pin number.

The digitalRead() method requires one parameter insides its parentheses:

  1. The I/O pin number, which can be the actual pin number (such as: D0, etc.) or a variable that stores a pin number. In this example, the variable named motion is listed. If necessary, change this to match the variable name for your motion sensor's pin number.

The digitalRead() method will return a value of either HIGH or LOW (which are treated as if they were int values):

  • HIGH indicates that motion is NOT currently detected.

  • LOW indicates that motion is currently detected.

The condition listed inside the parentheses of the if statement checks whether the value of motionState is equivalent to LOW:

  • If this condition is true, the code within the curly braces of the if statement will be performed. You will need to add code statements within the curly braces that perform the actions you want.

  • If this condition is false (because the motionState is HIGH), the code within the curly braces will NOT be performed. Optionally, you can add an else statement to perform a different set of code statements when motion is not detected.

IMPORTANT: You will notice that a delay() of 2 seconds is included when motion is detected. This delay is needed to allow the motion sensor to capture a new "snapshot" of the environment before checking the sensor again.

Particle Cloud

The defining feature of an IoT device is its ability to send and receive information through the internet. This allows an IoT device to interact with other apps or other IoT devices. For this project, you'll be creating a web app that interacts with your Photon device through the internet.

All of your Photon's internet communications are routed through the Particle Cloud service, which offers these ways that a web app can interact with a Photon device through Particle Cloud:

  1. A web app can get the value of a Photon device variable

  2. A web app can call a custom function on a Photon device

  3. A web app can get event notifications from a Photon device

In order to make your Photon device interact with your web app, you'll need to add special code to both your Photon device app and your web app:

  • The Particle firmware on your Photon device has built-in cloud functions to allow your device to interact with a web app through Particle Cloud. You'll need to add code statements using these cloud functions in your Photon device app.

  • There is a Particle API JavaScript library that provides methods (functions) to allow your web app to interact with your Photon device app through Particle Cloud. You'll need to load this JS library in your web app's HTML file, and then add code statements using the library's methods in your web app's JavaScript file.

Magnetic Switch

Your Photon kit includes a that can be used to detect whether a door, window, drawer, box, etc. is open or closed.

The switch consists of two pieces, and it can detect whether these two pieces are close to each other:

  1. The piece with the wires contains a that moves in response to the presence or absence of a magnetic field.

  2. The other piece without the wires contains a magnet, so it can activate the reed switch when the two pieces are close to each other.

If the two pieces of the magnetic switch are within 20 mm (0.75 inches) of each other, the switch detects that it's "closed" – otherwise, the switch will detect that it's "open."

These magnetic switches are commonly used in security systems for doors and windows, but they are also used in many other products. For example, a doorbell uses a magnetic switch to detect when it is being pressed. Magnetic switches are also used in many laptops and tablets to detect when the lid/cover is open or closed, in order to automatically wake up the device or put it to sleep.

How to Connect Switch

The reed switch (the piece with the wires) will be connected to the Photon. Then the reed switch will be attached to a stationary edge near something that opens (such as: door, window, drawer, etc.). For example, the reed switch could be attached to the edge of a door frame – but not to the door itself.

The magnet (the piece without wires) would be attached to the object (door, window, etc.) that actually moves when opened. The two pieces of the magnetic switch should be positioned so they are very close together (no more than 0.75 inches apart) when the object (door, window, etc.) is closed.

To connect a magnetic switch to your Photon using the breadboard, you will need:

  • Magnetic Switch

  • 2 jumper wires (use different colors to help identify them)

Here are the steps to connect the magnetic switch to your Photon using the breadboard:

  1. Insert the two wires of the magnetic switch into different terminal strip rows on the breadboard. (Different terminal strip rows have different row numbers.)

  2. Plug one end of a jumper wire into the same terminal strip row as one switch wire. Plug the other end of this jumper wire into an I/O pin on the Photon circuit board.

  3. Plug one end of the other jumper wire into the same terminal strip row as the other switch wire. Plug the other end of this jumper wire into a pin hole connected to GND: either plug it into a negative power rail on the breadboard (which is connected to GND via a different jumper wire), or plug it directly into a GND pin on the Photon circuit board.

Here's a wiring diagram showing a possible way to connect a magnetic switch:

Keep in mind that your connection can look different than this example diagram:

  • Your magnetic switch wires could be inserted into different row numbers on either breadboard side. (The example connects the switch wires to rows 17-18 on the left side of the breadboard.)

  • Your magnetic switch wires could be inserted into a different column on the breadboard. (The example connects the switch wires into column A of the terminal strip rows.)

  • Your magnetic switch could connect (through a jumper wire) to a different I/O pin. (The example connects to the D0 pin on the Photon circuit board.)

  • Your magnetic switch could connect (through a jumper wire) either to a different GND pin or to a negative power rail connected to a GND pin. (There are three available GND pins on the Photon circuit board.)

How to Code Switch

The basic steps to use a magnetic switch in your app code are:

  1. Declare a global variable to store the I/O pin number for the switch.

  2. Set the pin mode for the switch pin in the setup() function.

  3. Use a digitalRead() statement to check whether the switch is currently open or closed, and add code statements that should be performed depending on the result.

Global Variable

You should declare a global variable to store the I/O pin number that the switch is connected to. This will make it easier to understand your code (and easier to modify the code if you were to connect the button to a different pin number).

Add this code statement (modify if necessary) before the setup() function:

This line of code does 3 things (in order):

  1. It declares a data type for the variable's value. In this case, int stands for integer (whole number). Photon pin numbers are always treated as int values (even though they have letters).

  2. It declares the variable's name. In this example, the variable will be called magSwitch. You can change the variable name, but choose a name that will make sense to anyone reading the code.

  3. It assigns a value to the variable. In this example, the variable's value will be equal to D0. If necessary, modify this value to match the actual I/O pin number that your switch is connected to.

SWITCH = KEYWORD: You cannot use "switch" as the name of a variable (or a custom function) because is a reserved keyword in the Wiring programming language.

Set Pin Mode

You need to set the pin mode for the magnetic switch to be used as an input.

Add this code statement (modify if necessary) within the setup() function:

The pinMode() method requires two parameters inside its parentheses (in this order):

  1. The I/O pin number, which can be the actual pin number (such as: D0, etc.) or a variable that stores a pin number. In this example, a variable named magSwitch is listed. If necessary, change this to match the variable name for your magnetic switch.

  2. The mode value, which will always be INPUT_PULLUP for a magnetic switch.

Check Switch

The digitalRead() method is used to check whether a magnetic switch is currently open or closed.

Add this code (modify as necessary) to your app within the loop() function or a custom function:

In the first code statement, a local variable named switchState is declared that will have a data type of int (integer). This variable is made equal to whatever value is returned by the digitalRead() method. You can change the name of this variable, but it will make sense if it's similar to the variable name used for the switch pin number.

The digitalRead() method requires one parameter insides its parentheses:

  1. The I/O pin number, which can be the actual pin number (such as: D2, etc.) or a variable that stores a pin number. In this example, the variable named magSwitch is listed. If necessary, change this to match the variable name for your switch's pin number.

The digitalRead() method will return a value of either HIGH or LOW (which are treated as if they were int values):

  • HIGH indicates that the magnetic switch is currently open.

  • LOW indicates that the magnetic switch is currently closed.

The condition listed inside the parentheses of the checks whether the value of switchState is to HIGH:

  • If this condition is true, the code within the curly braces of the if statement will be performed. You will need to add code statements within the curly braces that perform the actions you want when the magnetic switch is open.

  • Otherwise, if this condition is false (because switchState is LOW), the code within the curly braces of the else statement will be performed. You will need to add code statements within the curly braces that perform the actions you want when the magnetic switch is closed.

Alternatively, you could check for just one condition (either HIGH or LOW) without including an else statement to perform actions for the opposite condition.

​

Temperature Sensor

The RHT03 sensor in your Photon kit can measure the relative humidity and temperature of the air.

How to Connect RHT03 Sensor

To connect the RHT03 sensor to your Photon using the breadboard, you will need:

  • RHT03 Humidity and Temperature Sensor

  • 3 jumper wires (use different colors to help identify them)

The RHT03 humidity and temperature sensor has 4 metal legs. The front side of the sensor has openings to allow air in.

If you were looking at the front of the sensor and the sensor legs were numbered left to right as 1-4, the wiring connections would be:

3.3V OR 5V: The RHT03 sensor can operate on either 3.3V or 5V of power.

  • If your Photon is being powered through the barrel jack, you can connect the RHT03 sensor to either the 3.3V pin or VIN pin.

  • If your Photon is being powered through the Micro-USB port, you can connect the RHT03 sensor to either the 3.3V pin or V-USB pin.

Here are the steps to connect the RHT03 sensor to your Photon using the breadboard:

  1. Insert the four metal legs of the sensor into different terminal strip rows on the breadboard. (Different terminal strip rows have different row numbers.)

  2. Plug one end of a jumper wire into the same terminal strip row as the power leg of the sensor. Plug the other end of this jumper wire into the 3.3V pin or a 5V pin (VIN or V-USB) on the Photon circuit board (or to a positive power rail on the breadboard connected to 3.3V, VIN, or V-USB). If your Photon is being powered through the barrel jack, connect to either the 3.3V pin or VIN pin. Otherwise, if your Photon is being powered through the Micro-USB port, connect to either the 3.3V pin or V-USB pin.

  3. Plug one end of a second jumper wire into the same terminal strip row as the data leg of the sensor. Plug the other end of this jumper wire into any I/O pin on the Photon circuit board.

  4. Plug one end of the third jumper wire into the same terminal strip row as the ground leg of the sensor. Plug the other end of this jumper wire into a pin hole connected to GND: either plug it into a negative power rail (which is connected to GND via a different jumper wire), or plug it directly into a GND pin on the Photon circuit board.

Here's a wiring diagram showing a possible way to connect the RHT03 humidity and temperature sensor (ignore the wiring for the light sensor):

Keep in mind that your connection can look different than this example diagram:

  • Your RHT03 sensor legs could be inserted into different row numbers. (The example connects the RHT03 sensor legs to rows 1-4 on the right side of the breadboard).

  • Your RHT03 sensor legs could be inserted into a different column of the breadboard. (The example connects the RHT03 sensor legs into column H of the terminal strip rows).

  • Your RHT03 sensor could connect (through a jumper wire) to a different I/O pin. (The example connects the RHT03 sensor to the D3 pin.)

  • Your RHT03 sensor could connect (through a jumper wire) directly to the 3.3V pin or a 5V pin (VIN or V-USB) – or it could connect to a positive power rail on the breadboard that's connected to the 3.3V pin or a 5V pin.

  • Your RHT03 sensor could connect (through a jumper wire) either directly to a GND pin or to a negative power rail that's connect to a GND pin. (There are three available GND pins.)

How to Code RHT03 Sensor

The basic steps to control the RHT03 humidity and temperature sensor in your app code are:

  1. Include the SparkFun RHT03 library in your app.

  2. Declare a global variable to store the I/O pin number for the RHT03 sensor.

  3. Create a RHT03 object assigned to a global variable called rht.

  4. Use the rht.begin() method to start the RHT03 sensor in the setup() function.

  5. Use a sequence of rht.update(), rht.humidity(), and rht.tempF() statements to get new humidity and temperature readings.

Include Library

Your Photon app must include a code library that will allow you to control the RHT03 sensor.

  1. In Particle Build, click on the Libraries icon to open the Libraries menu panel.

  2. Type rht into the search field. Select the result called: SparkFunRHT03

  3. Click the button to "Include in Project"

  4. Select the title of your Photon app, and then click the "Confirm" button

Particle Build will automatically insert this #include statement at the beginning of your app code:

Global Variables

You should declare a global variable to store the I/O pin number that the RHT03 sensor's data leg is connected to. This will make it easier to understand your code (and easier to modify the code if you were to connect the motion sensor to a different pin number).

You will also need to create an object using the RHT03 class in the included library, and assign this object to a global variable.

Add this code statement (modify if necessary) before the setup() function:

The first line of code does 3 things (in order):

  1. It declares a data type for the variable's value. In this case, int stands for integer (whole number). Photon pin numbers are always treated as int values (even though they have letters).

  2. It declares the variable's name. In this example, the variable will be called rhtData. You can change the variable name, but choose a name that will make sense to anyone reading the code.

  3. It assigns a value to the variable. In this example, the variable's value will be equal to D3. If necessary, modify this value to match the actual I/O pin number that your sensor is connected to.

The second line of code creates a new object using the RHT03 class, and assigns the object to a global variable named rht.

Start Sensor in Setup

The rht.begin() method is used to start the RHT03 sensor, which will automatically set its pin mode.

Add this code statement within the setup() function to start the RHT03 sensor:

The rht.begin() method requires the sensor's I/O pin number. In this case, the global variable named rhtData stores this value. If you used a different name for the global variable storing your RHT03 sensor pin number, then insert that name instead.

Get Sensor Readings

The rht.update() method is used to get new sensor readings for the relative humidity and temperature of the air.

If the update is successful, the rht.update() method will return a value of 1 (which is equivalent totrue). Then you can use these other rht methods to get the updated values for the relative humidity (%) and temperature (in Fahrenheit or Celsius):

  • The rht.humidity() method returns the relative humidity of the air as a value between 0-100, representing a percentage. A higher number means the air is more humid (has more water vapor).

  • The rht.tempF() method returns the temperature of the air in degrees Fahrenheit – while the rht.tempC() method will return the temperature of the air in degrees Celsius.

Each humidity and temperature measurement is returned as a float value (decimal number). In most cases, it will be simpler to round these values to the nearest integer (whole number).

Add this code (modify as necessary) within the loop() function or a custom function:

This code creates two variables named temperature and humidity to store the values returned by the sensor, which have been rounded to integer values.

If you want the temperature in degrees Celsius, then replace rht.tempF() with rht.tempC().

Be sure to add code to do something with the temperature and/or humidity values.

C-9 Web App JS

Next, you'll add JavaScript code to allow your web app to interact with your Photon device through Particle Cloud. Remember that the web app will perform these two tasks:

  1. The web app will display whether the LED light is currently turned on or off. The web app will do this by getting the current value of the lightStatus variable in your Photon device app.

  2. The web app will display a button that can be clicked to remotely turn the LED light on or off. The web app will do this by calling the toggleLight() function in your Photon device app.

Create Particle Object

The Particle API JS library defines a class named Particle() which you'll use to create an . An object is a special type of variable that has its own methods (functions) and properties (variables).

Copy this JavaScript code statement, and paste it into a blank JS file named script.js:

This will create a new Particle() object and assign it to a global variable named particle. Your web app JS will use this object's methods to interact with Particle Cloud.

Add Device ID & Access Token

In order for a web app to interact with a Photon device through Particle Cloud, the web app must provide the Photon's device ID and access token with each request. This ensures your web app interacts with the correct device – and prevents unauthorized apps from accessing your device.

You will declare global variables in your web app JS to store your Photon device ID and access token. You'll need to get their values from your Particle Build account.

Add this JS code to your script.js file, and modify it to list your Photon device ID and access token:

IMPORTANT: You must modify this code to replace "0000" with your actual Photon device ID and access token. Otherwise, your web app will not work properly.

Your Photon's unique device ID is listed in the Devices menu of your Particle Build account:

  1. Click the Devices icon in the left navigation bar.

  2. In the Devices menu panel, click the drop-down arrow to the right of your Photon device name.

  3. Select and copy the device ID.

  4. Paste the device ID into your JS code as the value for myDevice (the device ID must be listed within quotation marks).

Your Photon's unique access token is listed in the Settings menu of your Particle Build account:

  1. Click the Settings icon in the left navigation bar.

  2. In the Settings menu panel, select and copy the access token.

  3. Paste the access token into your JS code as the value for myToken (the access token must be listed within quotation marks).

Get Device Variable

Your web app JS will use the particle.getVariable() method to get the value of a Photon device variable stored as a cloud variable in Particle Cloud.

Add this JS code to your script.js file:

This adds a custom function named checkLights() to your JS. Inside this custom function is a call to the particle.getVariable() method.

The particle.getVariable() method requires your Photon device ID, the name of the cloud variable, and your Photon access token:

  1. myDevice is the global variable that stores your Photon device ID

  2. "lightStatus" is the name of the cloud variable whose value you want to get.

  3. myToken is the global variable that stores your Photon access token

When Particle Cloud returns the value of your cloud variable, the value gets temporarily stored in a local variable called: data.body.result

In your Photon device app, the lightStatus variable has a value of either "on" or "off". Therefore, in your web app JS, data.body.result will also be one of these values.

Inside the particle.getVariable() method are JS and jQuery code statements (lines 4-13 above) that were added to perform actions based on the value returned for the Photon variable.

An if-else statement is used to determine whether data.body.result has a value equivalent to "on" or "off". Then jQuery statements (which start with $) are used to dynamically change the information displayed in the "card" by targeting specific :

  • $("#light1") targets the HTML element with id="light1" which is the <div> element that represents the "card" displaying the information for the light. The jQuery statements either add or remove the light-on CSS class (which changes the card's background color to yellow).

  • $("#light1-status") targets the HTML element with id="light1-status" which is an <h2> element. The jQuery statements change this element's HTML to list either ON or OFF.

  • $("#light1-button") targets the HTML element with id="light1-button" which is the <button> element that can be clicked to remotely turn the light on or off. The jQuery statements change this element's HTML to list either Turn Off or Turn On as the button's label.

JAVASCRIPT: If you want to learn more about JS or need a quick reference, check out the .

JQUERY: If you want to learn more about jQuery or need a quick reference, check out the .

Set Interval to Get Variable

If your web app needs to continuously monitor the value of a Photon variable, you can use the window.setInterval() method to automatically call a JS function at a set time interval (such as every 5 seconds, etc.).

Add this JS code statement to your script.js file:

The window.setInterval() method requires two parameters inside its parentheses (in this order):

  1. The name of the JS function to be called, which should be the name of the custom function in your JS that contains the particle.getVariable() method for the variable you need to monitor. The function's name should be listed without a set of parentheses. In this case,checkLights is the name of the function.

  2. The time interval between calls, which will be the amount of time between each call to the JS function. The time interval is specified in milliseconds (1000 ms = 1 second). In this case, the interval was set to 200 ms (every 0.2 seconds).

Call Device Function

Your web app JS will use the particle.callFunction() method to call a function in your Photon device app by calling its cloud function reference in Particle Cloud.

Add this JS code to your script.js file:

This adds a custom function named toggleLight1() to your JS. Inside this custom function is a call to the particle.callFunction() method.

The particle.callFunction() method requires your Photon device ID, the name of the cloud function, an argument (a String parameter for the Photon function), and your Photon access token:

  1. myDevice is the global variable that stores your Photon device ID

  2. "toggleLight" is the name of the cloud function that you want to call (which will call its corresponding function in your Photon device app)

  3. "data" is the String parameter that will be passed into the Photon device function. If this text parameter isn't actually used within the Photon function, then it can be any text string enclosed within double quotation marks – even an empty text string of "" will work.

  4. myToken is the global variable that stores your Photon access token

The <button> in your web app HTML contains an that will run this toggleLight1() function whenever the button in the web app is clicked.

Test Web App

Be sure your Photon device is connected to Wi-Fi and Particle Cloud.

Refresh your web app, and test it with your Photon device to make sure they interact correctly:

  • Verify that your web app displays the current status of your Smart Light. Use the push button connected to your Photon device to turn the LED light on or off. Verify that your web app updates automatically to show the correct light status.

  • Verify that your web app can remotely turn your Smart Light on and off. Click the button in your web app, and verify that your Photon device automatically toggles the LED light on or off.

Going Further

In the next tutorial, you'll modify your "Smart Light" device into a "Smart Security" device by adding a motion sensor and speaker to your existing LED light and push button. Then you'll program a new Photon app and new web app for the modified device.

D-9 Web App JS

Next, you'll add JavaScript code to allow your web app to interact with your Photon device through Particle Cloud. Remember that the web app will perform these tasks:

  1. The web app will display whether the security device is currently armed or disarmed. The web app will do this by getting the value of the deviceMode variable in your Photon device app.

  2. The web app will display a toggle switch that can be clicked to remotely toggle the security device between armed and disarmed mode. The web app will do this by calling the toggleMode() function in your Photon device app.

  3. The web app will display a notification if the security device detects motion while the device is armed. The web app will do this by receiving event notifications sent from your Photon device app.

Add Starter JS

, and paste it into a blank JS file named script.js.

IMPORTANT: You must modify this JS code to . Otherwise, your web app will not work properly.

Add Custom JS

Copy this JS, and paste it after your modified starter JS:

This custom JS does 5 main things:

  1. Stores an audio file in a JS global variable named alertSound

  2. Sets a time interval to call a JS function named checkMode()

  3. Adds a JS function named checkMode() that will get the value of a Photon variable

  4. Adds a JS function named toggleMode() that will call a Photon function

  5. Starts listening for "motion" event notifications sent by your Photon device

Variable for Audio File

A variable named alertSound is declared that stores an audio file named "notification.wav". , and place it in the same folder as your web app files.

Set Interval to Call Function

The window.setInterval() method will automatically call the function named checkMode() every 500 ms (0.5 seconds).

Get Photon Variable

The function named checkMode() contains a call to the particle.getVariable() method that will get the current value of the "deviceMode" variable in your Photon app.

Inside the particle.getVariable() method are JS and jQuery code statements (lines 8-15 above) that were added to perform actions based on the value returned for the Photon variable.

An if-else statement is used to determine whether data.body.result has a value equivalent to "armed" or "disarmed". Then jQuery statements (which start with $) are used to dynamically change the information displayed in the first "card" by targeting specific :

  • $("#system-mode") targets the HTML element with id="system-mode". The jQuery statements change this element's HTML to display either ARMED or DISARMED.

  • $("input [name=toggle]) targets the <input> element with name="toggle". The jQuery statements change its "checked" property to either true (checked) or false (unchecked), which changes the toggle switch slider position.

Since the window.setInterval() method will keep calling this function every 0.5 seconds, your web app will continuously monitor the current mode of your Smart Security device.

Call Photon Function

The function named toggleMode() contains a call to the particle.callFunction() method that will call the "toggleMode" function in your Photon app to remotely switch your device's mode between "armed" and "disarmed".

The <input type="checkbox"> in your web app HTML contains an that will call this toggleMode() function whenever the toggle switch in the web app is clicked.

Listen for Event Notifications

The particle.getEventStream() method is used to start listening for event notifications sent from your Photon app.

The particle.getEventStream() method requires your Photon device ID, the name of your cloud event, and your Photon access token:

  1. myDevice is the global variable that stores your Photon device ID

  2. "motion" is the name of the cloud event that you want to receive notifications from

  3. myToken is the global variable that stores your Photon access token

If an event notification includes any data, this text string data gets temporarily stored in a local variable called: feed.data

Code statements added within the particle.getVariable() method will be performed whenever an event notification is received.

In this case, JS and jQuery code statements (lines 29-33 above) were added that will perform these actions each time a new event notification is received:

  • Play the alertSound

  • Get the current date and time and store it in a variable named dateTime

  • Display the value of dateTime in the HTML element with id="event-time"

  • Show the HTML element with id="motion-alert", wait for 1500 ms (1.5 seconds), and then fade out the element until it is hidden. This creates a visible "pop-up" notification in your web app.

NOTE: Since your Photon app is sending the "motion" event notification without data, there aren't any JS or jQuery code statements using feed.data (because no text string is being received).

Test Web App

Be sure your Photon device is connected to Wi-Fi and Particle Cloud.

Refresh your web app, and test it with your Photon device to make sure they interact correctly:

  • Verify that your web app displays the current mode ("armed" or "disarmed") of your Smart Security device. Use the push button connected to your Photon device to change the device mode. When the LED is turned on, the device is in "armed" mode. When the LED is turned off, the device is "disarmed." Verify that your web app updates automatically to show the correct device mode.

  • Verify that your web app can remotely change the device mode. Click the toggle switch in your web app, and verify that your Photon device automatically toggles modes (by checking the LED). It may take up to 2 seconds for the mode to switch due to the delay(2000) in the Photon app.

  • While your Smart Security device is in "armed" mode, wave your hand over the motion sensor to trigger a motion event. Verify that your web app displays a motion notification pop-up (which will fade out after 1.5 seconds). Verify the web app displays the correct date and time for the last motion event notification.

Going Further

If you have time and want to experiment with the other inputs and outputs in your Photon kit, you could explore the . (You can skip ahead to Experiment 3 or later.)

There are also references in this guidebook that show and explain how to connect and code each of the and included in your Photon kit.

Your team should now be ready to start thinking of possible ideas for .

Push Buttons

Physical buttons that people can push are used as inputs on many different types of devices.

Your Photon kit has a set of 4 push buttons with different cap colors: red, yellow, green, and blue.

The buttons in your Photon kit are classified as momentary switches, which means they detect when they are being pressed or pushed. For example, the keys on a computer keyboard are momentary switches: they are only "on" when you press them (and they turn "off" when you release them).

This is different from maintained switches, which physically toggle between one state and another state. For example, a light switch is a maintained switch: pressing (or flipping) the switch will turn it on, and it will stay this way until pressed again (or flipped back).

However, you can make a push button act like a maintained switch by adding a global variable in your app code to track the button's current status ("on" or "off"), and then toggling this status in your code each time the button is pushed.

How to Connect Button

Each push button has 2 pairs of metal legs on opposite sides of its base. Unlike other components that connect to only one half of a breadboard, the push button has to connect to both halves of the breadboard across the gap in the middle. This is simply due to the width of the button – there isn't enough space to connect the push button plus jumper wires on one half of the breadboard.

To connect a push button to your Photon using the breadboard, you will need:

  • Push button

  • 2 jumper wires (use different colors to help identify them)

Here are the steps to connect the push button to your Photon using the breadboard:

  1. Place the push button along the middle divider of the breadboard, so one pair of legs will align with pin holes in column D on the left half of the breadboard, while the other pair of legs (on the opposite side) will align with pin holes in column G on the right half of the breadboard. If necessary, you can gently bend the metal legs to align them better with the pin holes.

  2. Firmly press the button down to "snap" its base into place, so it's flat against the breadboard.

  3. Plug one end of a jumper wire into the same terminal strip row as one of the button legs on the right half of the breadboard. Plug the other end of this jumper wire into an I/O pin on the Photon circuit board.

  4. Plug one end of the other jumper wire into the same terminal strip row as the other button leg on the right half of the breadboard. Plug the other end of this jumper wire into a pin hole connected to GND: either plug it into a negative power rail (which is connected to GND via a different jumper wire), or plug it directly into a GND pin on the Photon circuit board.

Here's a wiring diagram showing a possible way to connect a push button (you can ignore the wiring for the LED and resistor):

Keep in mind that your connection can look different than this example diagram:

  • Your button legs could be inserted into different row numbers. (The example connects the button legs to row 4 and row 6.)

  • Your button leg could connect (through a jumper wire) to a different I/O pin. (The example connects to the D2 pin.)

  • Your button could connect (through a jumper wire) either directly to a GND pin or to a negative power rail that's connect to a GND pin. (There are three available GND pins.)

How to Code Button

The basic steps to use a push button in your app code are:

  1. Declare a global variable to store the I/O pin number for the button.

  2. Set the pin mode for the button pin in the setup() function.

  3. Use a digitalRead() statement to check whether the button is currently pressed, and add code statements that should be performed depending on the result.

Global Variable

You should declare a global variable to store the I/O pin number that the button is connected to. This will make it easier to understand your code (and easier to modify the code if you were to connect the button to a different pin number).

Add this code statement (modify if necessary) before the setup() function:

This line of code does 3 things (in order):

  1. It declares a data type for the variable's value. In this case, int stands for integer (whole number). Photon pin numbers are always treated as int values (even though they have letters).

  2. It declares the variable's name. In this example, the variable will be called button. You can change the variable name, but choose a name that will make sense to anyone reading the code.

  3. It assigns a value to the variable. In this example, the variable's value will be equal to D2. If necessary, modify this value to match the actual I/O pin number that your button is connected to.

MULTIPLE BUTTONS

If you have multiple buttons connected to your Photon, then be sure to give each button a unique variable name by adding an adjective or number to the variable names. For example:

Set Pin Mode

You need to set the pin mode for the button to be used as an input.

Add this code statement (modify if necessary) within the setup() function:

The pinMode() method requires two parameters inside its parentheses (in this order):

  1. The I/O pin number, which can be the actual pin number (such as: D2, etc.) or a variable that stores a pin number. In this example, a variable named button is listed. If necessary, change this to match the variable name for your button.

  2. The mode value, which will always be INPUT_PULLUP for a push button.

MULTIPLE BUTTONS

If you have multiple buttons connected to your Photon, then be sure to set the pin mode for each button pin variable. For example:

Check If Button Pressed

The digitalRead() method is used to check whether a button is currently pressed.

Add this code (modify as necessary) to your app within the loop() function or a custom function:

In the first code statement, a local variable named buttonState is declared that will have a data type of int (integer). This variable is made equal to whatever value is returned by the digitalRead() method. You can change the name of this variable, but it will make sense if it's similar to the variable name used for the button pin number.

The digitalRead() method requires one parameter insides its parentheses:

  1. The I/O pin number, which can be the actual pin number (such as: D2, etc.) or a variable that stores a pin number. In this example, the variable named button is listed. If necessary, change this to match the variable name for your button's pin number.

The digitalRead() method will return a value of either HIGH or LOW (which are treated as if they were int values):

  • HIGH indicates that the button is NOT currently pressed.

  • LOW indicates that the button is currently pressed.

The condition listed inside the parentheses of the checks whether the value of buttonState is to LOW:

  • If this condition is true, the code within the curly braces of the if statement will be performed. You will need to add code statements within the curly braces that perform the actions you want.

  • If this condition is false (because the buttonState is HIGH), the code within the curly braces will NOT be performed. Optionally, you can add an to perform a different set of code statements when the button is not pressed.

Web App - Single Screen

You can create a web app that interacts with your Photon device through Particle Cloud.

Your web app will consist of an HTML file namedindex.html, a CSS file named style.css, and a JavaScript file named script.js.

If your web app will consist of a single screen, you can use the starter code below for your HTML, CSS, and JS files. Then you'll have to add your own code, as well as modify certain parts of the starter code.

If your web app will need multiple screens, use this other starter code instead.

HTML

You can use this starter code for your HTML file named index.html:

<!DOCTYPE html>
<html>
    <head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Smart Device Web App</title>
        <link href="style.css" rel="stylesheet" type="text/css">
    </head>
    <body>
        <!-- Add HTML for your web app -->
        
        
        
        <!-- Load JavaScript files -->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/particle-api-js/7.3.0/particle.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        <script src="script.js"></script>
    </body>
</html>

COPY CODE: When using this IoT code guidebook, you can copy a code block simply by clicking the copy icon displayed in the upper right of the code block.

This HTML does three main things:

  1. It loads a CSS stylesheet file.

  2. It loads three JavaScript files.

  3. It has blank lines where you'll add HTML for your specific web app.

LOAD CSS STYLESHEET

In the <head> section, there is a <link> tag to load a CSS stylesheet file named style.css that you'll use to modify the appearance of certain HTML elements in your web app.

LOAD JAVASCRIPT FILES

At the bottom of the <body> section, there are <script> tags to load several JavaScript files into your web app:

  1. Particle API JS library: particle.min.js

  2. jQuery JS library: jquery.min.js

  3. Your web app JS file: script.js

The Particle API JS library contains methods to allow your web app to interact with your Photon device through Particle Cloud. You'll use Particle methods in your web app JS file.

The jQuery JS library contains methods that make it easy to modify the content and style of your web app by dynamically changing its HTML and CSS. You'll use jQuery methods in your web app JS file.

BLANK LINES FOR YOUR HTML

In the <body> section, there are several blank lines are where you will add HTML for your web app. (You can use more lines, obviously.) This is where you might display text, images, links, buttons, etc.

HOW TO CREATE MULTIPLE SCREENS

Your web app should consist of single HTML page. If you want different screens for your web app, then create a separate <div> section for each screen, and give each <div> a unique id name along with a class name shared by all the screen <div> sections.

This will allow your web app JS to use jQuery code to show one screen while hiding the other screens. First, you use jQuery to hide() all the screens (by selecting the class name), and then use jQuery to show() one specific screen (by selecting its unique id name). To switch to a different screen, just hide() all the screens again, and then show() the new screen.

CSS

You can use this starter code for your CSS file named style.css:

/* Add or modify CSS for your web app */
body {
    font-family:  Helvetica, Arial, sans-serif;
    font-size: 1em;
    text-align: center;
}

This CSS styles the <body> section of your web app. However, you can modify this CSS if desired.

You'll typically want to add CSS to style other HTML elements in your web app, in order to produce the desired layout and appearance for your app's user interface.

JS

You can use this starter code for your JS file named script.js (be sure to modify):

var particle = new Particle();
var myDevice = "0000"; // Photon device ID
var myToken = "0000"; // Photon access token

// Add JS for your web app

IMPORTANT: You must modify this JS code to insert your actual Photon device ID and access token. Otherwise, your web app will not work properly.

This JS creates a new Particle() object and assigns it to a global variable named particle. This object has built-in methods (functions) that can be used to interact with your Photon device through Particle Cloud.

This JS also declares global variables to store your Photon device ID and access token. You must modify these lines to list your actual device ID and access token, which you will need to get from your team's Particle Build account.

Then you'll need to add the other necessary JS for your web app. Because your HTML file loaded the Particle API JS library and jQuery JS library, you can include Particle statements and jQuery statements within your JS code.

Review the reference section on Particle Cloud to learn how to make your web app JS interact with your Photon device app.

Resources

If you want to learn more about web development or need a quick reference, consult these tutorials and references from W3Schools:

  • HTML

  • CSS

  • JavaScript

  • jQuery

Magnetic Switch

Photon Pin

First Wire (either one)

any I/O pin

Second Wire

GND

int magSwitch = D0;
pinMode(magSwitch, INPUT_PULLUP);
int switchState = digitalRead(magSwitch);​
if(switchState == HIGH) {​
    // add code to do something if switch is open
    
}
else {
    // add code to do something if switch is closed
    
}
magnetic switch
reed switch
switch()
if statement
equivalent
Magnetic Switch
Installing Magnetic Switch on Door

RHT03 Temperature Sensor

Photon Pin

Leg 1 – Power (3.3-6V)

3.3V or 5V (through VIN or V-USB)

Leg 2 – Data

any I/O pin

Leg 3 – Unused

(none)

Leg 4 – Ground

GND

// This #include statement was automatically added by the Particle IDE.
#include <SparkFunRHT03.h>
int rhtData = D3;
RHT03 rht;
rht.begin(rhtData);
if (rht.update() == true) {
    int temperature = round(rht.tempF());
    int humidity = round(rht.humidity());​
    // add code to do something with values
    
}
RHT03 Humidity and Temperature Sensor
Libraries Icon
var particle = new Particle();
var myDevice = "0000"; // Photon device ID
var myToken = "0000"; // Photon access token
function checkLights(){
    particle.getVariable({ deviceId: myDevice, name: "lightStatus", auth: myToken }).then(function(data) {
        // add code to do something with value returned as: data.body.result
        if (data.body.result == "on") {
            $("#light1").addClass("light-on");
            $("#light1-status").html("ON");
            $("#light1-button").html("Turn Off")
        }
        else if (data.body.result == "off") {
            $("#light1").removeClass("light-on");
            $("#light1-status").html("OFF");
            $("#light1-button").html("Turn On")
        }
    }, function(err) {
            console.log("An error occurred: ", err);
    });
}
window.setInterval(checkLights, 200);
function toggleLight1() {
    particle.callFunction({ deviceId: myDevice, name: "toggleLight", argument: "data", auth: myToken });
}
object
id selectors
W3Schools JavaScript Tutorial and Reference
W3Schools jQuery Tutorial and Reference
onclick event attribute
var alertSound = new Audio("notification.wav");

window.setInterval(checkMode, 500);

function checkMode() {
    particle.getVariable({ deviceId: myDevice, name: "deviceMode", auth: myToken }).then(function(data) {
        // add code to do something with value returned as: data.body.result
        if (data.body.result == "armed") {
            $("#system-mode").html("ARMED");
            $("input[name=toggle]").prop("checked", true);
        }
        else if (data.body.result == "disarmed") {
            $("#system-mode").html("DISARMED");
            $("input[name=toggle]").prop("checked", false);
        }
    }, function(err) {
            console.log("An error occurred: ", err);
    });
}

function toggleMode() {
    particle.callFunction({ deviceId: myDevice, name: "toggleMode", argument: "data", auth: myToken });
}

particle.getEventStream({ deviceId: myDevice, name: "motion", auth: myToken }).then(function(stream) {
  stream.on('event', function(feed) {
    // add code to do something when event notification received
    // any text data received is stored as: feed.data
    alertSound.play();
    var dateTime = new Date();
    dateTime = dateTime.toLocaleString();
    $("#event-time").html(dateTime);
    $("#motion-alert").show().delay(1500).fadeOut();
  });
});
​Copy this starter JS for your web app
insert your actual Photon device ID and access token
Download a copy of this audio file
id selectors
onclick event attribute
SparkFun Photon Experiment Guide
physical inputs
physical outputs
your IoT project challenge

Push Button

Photon Pin

One Leg (any leg)

any I/O pin

Adjacent Leg on same side

GND

int button = D2;
int button1 = D2;
int button2 = D3;
pinMode(button, INPUT_PULLUP);
pinMode(button1, INPUT_PULLUP);
pinMode(button2, INPUT_PULLUP);
int buttonState = digitalRead(button);

if(buttonState == LOW) {
​    // add code to do something if button pressed
​
}
if statement
equivalent
else statement
Push Buttons

Trimpot Dial

Your Photon kit includes a "trimpot" (trimmable potentiometer) that can be rotated and used as a dial. A potentiometer is a variable resistor that can be adjusted by sliding, rotating, or another type of physical interaction. Potentiometers are used in various devices such as: joysticks and game controllers, control knobs and sliders, dimmer switches for lights, volume knobs for stereos, etc.

The trimpot dial can be rotated clockwise or counterclockwise approximately 270° (it does NOT rotate all the way around). The position of the dial can be measured and used as an input for a value that has a range from minimum to maximum.

How to Connect Trimpot

The trimpot dial has 3 metal legs that will be inserted into pin holes on the breadboard.

To connect a trimpot dial to your Photon using the breadboard, you will need:

  • Trimpot

  • 3 jumper wires (use different colors to help identify them)

3.3V MAXIMUM: Analog inputs, such as the trimpot, require 3.3V of power for accurate measurements. Connect the trimpot to the 3.3V pin on your Photon, or connect it to a positive power rail that's connected to the 3.3V pin.

TWIN PINS: Analog pins A2, A3, A4, and A5 are each represented by two pins on the Photon board. The duplicate pins are labeled as: SS/A2, SCK/A3, MISO/A4, MOSI/A5. If you use one of these pins, you cannot use its twin at the same time.

Here are the steps to connect the trimpot to your Photon using the breadboard:

  1. Insert the three metal legs of the trimpot into different terminal strip rows on the breadboard. (Different terminal strip rows have different row numbers.)

  2. Plug one end of a jumper wire into the same terminal strip row as an outer leg of the trimpot. Plug the other end of this jumper wire into the 3.3V pin on the Photon circuit board (or plug it into a positive power rail that's connected to the 3.3V pin via a different jumper wire).

  3. Plug one end of a second jumper wire into the same terminal strip row as the middle leg of the trimpot. Plug the other end of this jumper wire into any analog I/O pin on the Photon circuit board.

  4. Plug one end of the third jumper wire into the same terminal strip row as the other outer leg of the trimpot. Plug the other end of this jumper wire into a pin hole connected to GND: either plug it into a negative power rail (which is connected to GND via a different jumper wire), or plug it directly into a GND pin on the Photon circuit board.

Here's a wiring diagram showing a possible way to connect a trimpot (ignore the wiring for the three push buttons):

Keep in mind that your connection can look different than this example diagram:

  • Your trimpot legs could be inserted into different row numbers. (The example connects the trimpot legs to rows 26-28 on the right side of the breadboard).

  • Your trimpot legs could be inserted into a different column of the breadboard. (The example connects the trimpot legs into column F of the terminal strip rows).

  • Your trimpot could connect (through a jumper wire) to a different analog I/O pin. (The example connects the trimpot to the A0 pin.)

  • Your trimpot could connect (through a jumper wire) either directly to the 3.3V pin or to a positive power rail on the breadboard that's connected to the 3.3V pin.

  • Your trimpot could connect (through a jumper wire) either directly to a GND pin or to a negative power rail that's connect to a GND pin. (There are three available GND pins.)

How to Code Trimpot

The basic steps to control a trimpot dial in your app code are:

  1. Declare a global variable to store the I/O pin number for the trimpot.

  2. Use the analogRead() method to measure the trimpot dial position.

  3. OPTIONAL: Use the map() method to convert the trimpot reading to a custom range.

Global Variable

You should declare a global variable to store the I/O pin number that the trimpot is connected to. This will make it easier to understand your code (and easier to modify the code if you were to connect the trimpot to a different pin number).

Add this code statement (modify if necessary) before the setup() function:

This line of code does 3 things (in order):

  1. It declares a data type for the variable's value. In this case, int stands for integer (whole number). Photon pin numbers are always treated as int values (even though they have letters).

  2. It declares the variable's name. In this example, the variable will be called trimpot. You can change the variable name, but choose a name that will make sense to anyone reading the code.

  3. It assigns a value to the variable. In this example, the variable's value will be equal to A0. If necessary, modify this value to match the actual I/O pin that your speaker is connected to.

PIN MODE: Analog inputs do NOT need to have their pin mode set within the setup() function. Their pin mode gets automatically set when the analogRead() method is used.

Read Trimpot

The analogRead() method is used to read the trimpot, which indicates the trimpot dial position.

Add this code (modify as necessary) to your app within the loop() function or a custom function:

A local variable named trimpotRead is declared that will have a data type of int (integer). This variable is made equal to whatever value is returned by the analogRead() method. You can change the name of this variable, but it will make sense if it's similar to the variable name used for the trimpot pin number.

The analogRead() method requires one parameter insides its parentheses:

  1. The I/O pin number, which can be the actual pin number (such as: A0, etc.) or a variable that stores a pin number. In this example, the variable named trimpot is listed. If necessary, change this to match the variable name for your trimpot's pin number.

The analogRead() method will return an integer (whole number) value ranging from 0-4095:

  • If the dial is rotated all the way to the left (counterclockwise), the value will be 0.

  • If the dial is rotated all the way to the right (clockwise), the value will be 4095.

  • If the dial is rotated somewhere in-between, the value will be proportional to the dial's position. For example, if the dial is rotated exactly halfway, the value will be 2048.

You'll need to add code to do something with the reading stored as trimpotRead. For example, this might be an if-else statement to perform certain actions based on whether trimpotRead is greater than (or less than) one or more specific values.

Map Value to Custom Range

In many cases, it may not be convenient to work with a value that ranges from 0-4095. Instead, it might be easier to have a value within a smaller custom range (such as: 0-10, 0-100, etc.) that makes more sense for your particular task.

The map() function can be used to convert a value from its original range (such as 0-4095) into a new range of your choice. You decide the minimum and maximum values for the new range.

For example, if a trimpot dial were being used to control the brightness of an LED light, you might want the trimpot to return a value between 0-255 because the analogWrite() method used to set the brightness of an LED requires a value in this range.

Add this code (modify as necessary) to your app within the loop() function or a custom function:

As necessary, change the values assigned to minValue and maxValue to whatever numbers you want to use for your custom range. Also, the minValue doesn't have to be zero.

Be sure to add code to do something with trimpotValue. For example, this might be an if-else statement to perform certain actions based on whether trimpotValue is greater than (or less than) one or more specific values.

NOTE: The code uses the round() method to round the mapped value to the nearest integer because the map() method returns a float (decimal value). Also, inside the map() method, the code intentionally adds 1 to the maxValue because otherwise it is very difficult to get the maximum value even if the trimpot dial is turned clockwise all the way.

CUSTOM FUNCTION TO READ ANALOG SENSORS

You could incorporate this code into a custom function called checkSensor() that will read an analog sensor and return a value mapped to a custom range:

When calling the checkSensor() function within the loop() function, you will need to include values for these 3 parameters (in order) inside its parentheses:

  1. the sensor's pin number, which will most likely be a variable that stores the pin number

  2. the desired minimum value for the range, which should be an integer (whole number)

  3. the desired maximum value for the range, which should be an integer (whole number)

The checkSensor() function will return the mapped sensor value as an integer, which your code should store in a variable of data type int.

For example, to call the checkSensor() function within the loop() function:

The checkSensor() function could also be used to read other analog sensors, such as a light sensor:

LED Lights

LEDs (light-emitting diodes) are small, bright, long-lasting, energy-efficient lights. LEDs have been commonly used in electronic products for decades. More recently, incandescent light bulbs used in homes and other buildings are being replaced with LED light bulbs due to their energy efficiency.

Your Photon kit has a set of LED lights in different bulb colors: red, yellow, green, and blue.

How to Connect LED

An LED light is a part, meaning there is one way to correctly connect its positive and negative terminals. If a polarized part is connected incorrectly (by switching the positive and negative), the part may not work or could become damaged.

Each LED in your Photon kit has a positive leg and a negative leg. These can be identified visually by length: the negative leg has been made slightly shorter.

You will use a breadboard to help connect the LED to your Photon circuit board. The negative leg will be connected to GND (-) through a resistor. The positive leg will be connected to an I/O pin, which will serve as the voltage source (+).

Bend LED Positive Leg

To make it easier to insert the LED into a breadboard, you can carefully bend the positive leg as shown below, so both legs have the same height. You can still identify them visually: the straight leg is the negative leg, and the bent leg is the positive leg.

Bend Resistor Legs

An LED can be easily burned out if it receives too much power. Therefore, a must be used to limit the amount of current flowing through the LED. The resistor is used to connect the negative leg of the LED to a GND (-) pin.

Your Photon kit contains a set of resistors with a resistance rating of 330 Ohms. In order to insert a resistor into the pin holes of a breadboard, you will need to bend both resistor legs into ~90° angles:

Connect to Breadboard

To connect an LED light to your Photon using the breadboard, you will need:

  • LED light with bent positive leg

  • Resistor with bent legs

  • 2 jumper wires (use different colors to help identify them)

RESISTOR REQUIRED: Connect the LED's negative leg to GND using a resistor, which will limit the amount of current flowing through the LED. Otherwise, you will burn out the LED.

Here are the steps to connect the LED light to your Photon using the breadboard:

  1. Insert the positive and negative legs of the LED into different terminal strip rows on the breadboard. (Different terminal strip rows have different row numbers.)

  2. Plug one end of a jumper wire into the same terminal strip row as the bent positive leg of the LED. Plug the other end of this jumper wire into an I/O pin on the Photon circuit board.

  3. Insert one end of the resistor into the same terminal strip row as the negative leg of the LED. Insert the other end of the resistor into a pin hole of the negative column of the closest power rail on the breadboard.

  4. If the negative power rail isn't already connected to a GND pin on the Photon circuit board, then plug one end of the other jumper wire into another pin hole in the negative power rail, and plug the other end of this jumper wire into a GND pin on the Photon circuit board.

Here's a wiring diagram showing a possible way to connect an LED light:

Keep in mind that your connection can look different than this example diagram:

  • Your LED legs could be inserted into different row numbers on the breadboard. (The example connects the positive leg to row 20 and the negative leg to row 21.)

  • Your LED legs could be inserted into a different column on the breadboard. (The example connects the LED legs into column I of the terminal strip rows.)

  • The positive LED leg could connect to a different I/O pin. (The example connects to the D0 pin.)

  • The negative power rail on your breadboard could connect to a different GND pin. (There are three available GND pins.)

How to Code LED

The basic steps to control an LED light in your app code are:

  1. Declare a global variable to store the I/O pin number for the LED.

  2. Set the pin mode for the LED pin in the setup() function.

  3. Use digitalWrite() statements to turn the LED on or off. (Another option is to use analogWrite() statements to control the brightness of the LED.)

Global Variable

You should declare a global variable to store the I/O pin number that the LED is connected to. This will make it easier to understand your code (and easier to modify the code if you were to connect the LED to a different pin number).

Add this code statement (modify if necessary) before the setup() function:

This line of code does 3 things (in order):

  1. It declares a data type for the variable's value. In this case, int stands for integer (whole number). Photon pin numbers are always treated as int values (even though they have letters).

  2. It declares the variable's name. In this example, the variable will be called LED. You can change the variable name, but choose a name that will make sense to anyone reading the code.

  3. It assigns a value to the variable. In this example, the variable's value will be equal to D0. If necessary, modify this value to match the actual I/O pin that your LED is connected to.

MULTIPLE LED LIGHTS

If you have multiple LED lights connected to your Photon, then be sure to give each LED a unique variable name by adding an adjective or number to the variable names. For example:

Set Pin Mode

You need to set the pin mode for the LED to be used as an output.

Add this code statement (modify if necessary) within the setup() function:

The pinMode() method requires two parameters inside its parentheses (in this order):

  1. The I/O pin number, which can be the actual pin number (such as: D0, etc.) or a variable that stores a pin number. In this example, a variable named LED is listed. If necessary, change this to match the variable name for your LED.

  2. The mode value, which will always be OUTPUT for an LED light because your app will send "on" and "off" signals (or brightness signals) to the LED light.

MULTIPLE LED LIGHTS

If you have multiple LED lights connected to your Photon, then be sure to set the pin mode for each LED pin variable. For example:

Turn LED On or Off

The digitalWrite() method is used to turn an LED on or off.

Add this code statement (modify if necessary) to your app within the setup() function, loop() function, or a custom function:

The digitalWrite() method requires two parameters inside its parentheses (in this order):

  1. The I/O pin number, which can be the actual pin number (such as: D0, etc.) or a variable that stores a pin number. In this example, a variable named LED is listed. If necessary, modify this to match the variable name for your LED.

  2. The signal value, which can be HIGH or LOW. Your Photon uses this value to send an electrical signal through the pin: HIGH is a signal of 3.3 volts which represents "on," while LOW is a signal of 0 volts which represents "off." Modify this value to either turn the LED on or off.

DIM LED WHEN PHOTON STARTS: Depending on which I/O pin an LED is connected to, the LED light might be on (at a dim brightness) when your Photon app first starts.

If you need an LED light to be turned off when your app first starts running, then be sure to include code to turn off the LED within the setup() function after setting its pin mode.

Adjust LED Brightness

Alternatively, you can use the analogWrite() method to adjust the brightness of an LED from minimum ("off") to maximum – or any value in-between.

However, the LED light must be connected to an I/O pin capable of PWM output. PWM stands for , which is a way to make a digital output signal (which has only two values: HIGH or LOW) act like an analog output signal (which has a range of values).

These Photon I/O pins are capable of PWM output: A4, A5, D0, D1, D2, D3, RX, TX, WKP.

Add this code statement (modify as necessary) to your app within the setup() function, loop() function, or a custom function:

The analogWrite() method requires two parameters inside its parentheses (in this order):

  1. The I/O pin number, which can be the actual pin number (such as: D0, etc.) or a variable that stores a pin number. In this example, a variable named LED is listed. If necessary, modify this to match the variable name for your LED.

  2. The signal value, which can be any integer value (whole number) between 0-255. Your Photon uses this value to send a PWM electrical signal through the pin: 0 is minimum brightness (LED will be off) while 255 is maximum brightness. In this example, a value of 128 represents 50% brightness. Modify this value based on the brightness needed.

ANALOG VS. DIGITAL

The analogWrite() and digitalWrite() methods are both capable of setting an LED to either minimum or maximum brightness:

  • Setting an LED to minimum brightness ("off") using analogWrite(LED, 0) produces the same result as using digitalWrite(LED, LOW)

  • Setting an LED to maximum brightness using analogWrite(LED, 255) produces the same result as using digitalWrite(LED, HIGH)

However, the analogWrite() method is the only way to set an LED to a brightness that's in-between these two extremes:

  • analogWrite(LED, 64) would set the LED to 25% brightness

  • analogWrite(LED, 128) would set the LED to 50% brightness

  • analogWrite(LED, 192) would set the LED to 75% brightness

  • etc.

Light Sensor

The Photon kit includes a light sensor (also known as a photocell) which is a variable resistor that changes its resistance in response to the amount of ambient light in the environment.

For example, some outdoor lights on houses and buildings use photocells to automatically turn the light on or off depending on whether it is dark or light outside. Most smartphones have light sensors to automatically adjust the brightness of the screen depending on the amount of ambient light detected.

How to Connect Light Sensor

The light sensor is a variable resistor: its resistance changes (depending on the amount of light it is exposed to). A static resistor (which has a fixed resistance) will be connected in series with the photocell to create a . This will allow the Photon to measure the resistance of the photocell, which indicates the amount of light reaching the sensor.

Bend Resistor Legs

A static resistor will be used to connect one leg of the light sensor to a GND (-) pin.

Your Photon kit contains a set of resistors with a resistance rating of 330 Ohms. In order to insert a resistor into the pin holes of a breadboard, you will need to bend both resistor legs into ~90° angles:

Connect to Breadboard

The light sensor has 2 metal legs that will be inserted into pin holes on the breadboard. One of the legs will actually have two connections – this is the voltage divider created using a static resistor.

To connect a light sensor to your Photon using the breadboard, you will need:

  • Light sensor (aka photocell)

  • Resistor with bent legs

  • 2 jumper wires (use different colors to help identify them)

3.3V MAXIMUM: Analog inputs, such as the light sensor, require 3.3V of power for accurate measurements. Connect the light sensor to the 3.3V pin on your Photon, or connect it to a positive power rail that's connected to the 3.3V pin.

RESISTOR REQUIRED: A static resistor will be used to create a voltage divider that allows the variable resistance of the light sensor to be measured.

TWIN PINS: Analog pins A2, A3, A4, and A5 are each represented by two pins on the Photon board. The duplicate pins are labeled as: SS/A2, SCK/A3, MISO/A4, MOSI/A5. If you use one of these pins, you cannot use its twin at the same time.

Here are the steps to connect the light sensor to your Photon using the breadboard:

  1. Insert the two legs of the light sensor into different terminal strip rows on the breadboard. (Different terminal strip rows have different row numbers.)

  2. Plug one end of a jumper wire into the same terminal strip row as one sensor leg. Plug the other end of this jumper wire into the 3.3V pin on the Photon circuit board (or plug it into a positive power rail that's connected to the 3.3V pin via a different jumper wire).

  3. Plug one end of a second jumper wire into the same terminal strip row as the second sensor leg. Plug the other end of this jumper wire into any analog I/O pin on the Photon circuit board.

  4. Insert one end of the resistor into the same terminal strip row as the second sensor leg. Insert the other end of the resistor into a pin hole of the negative column of the closest power rail on the breadboard.

  5. If the negative power rail isn't already connected to a GND pin on the Photon circuit board, then plug one end of a third jumper wire into another pin hole in the negative power rail, and plug the other end of this jumper wire into a GND pin on the Photon circuit board.

Here's a wiring diagram showing a possible way to connect a light sensor (ignore the wiring at the top for the temperature sensor):

Keep in mind that your connection can look different than this example diagram:

  • Your light sensor legs could be inserted into different row numbers on the breadboard. (The example connects the legs to row 27 and row 30.)

  • Your light sensor legs could be inserted into a different column on the breadboard. (The example connects the legs into column F of the terminal strip rows.)

  • Your light sensor could connect to a different analog I/O pin. (The example connects to the A0 pin.)

  • Your light sensor could connect (through a jumper wire) either directly to the 3.3V pin or to a positive power rail on the breadboard that's connected to the 3.3V pin.

  • The negative power rail on your breadboard could connect to a different GND pin. (There are three available GND pins.)

How to Code Light Sensor

The basic steps to control a light sensor (photocell) in your app code are:

  1. Declare a global variable to store the I/O pin number for the light sensor.

  2. Use the analogRead() method to measure the amount of light.

  3. OPTIONAL: Use the map() method to convert the sensor reading to a custom range.

Global Variable

You should declare a global variable to store the I/O pin number that the light sensor is connected to. This will make it easier to understand your code (and easier to modify the code if you were to connect the trimpot to a different pin number).

Add this code statement (modify if necessary) before the setup() function:

This line of code does 3 things (in order):

  1. It declares a data type for the variable's value. In this case, int stands for integer (whole number). Photon pin numbers are always treated as int values (even though they have letters).

  2. It declares the variable's name. In this example, the variable will be called light. You can change the variable name, but choose a name that will make sense to anyone reading the code.

  3. It assigns a value to the variable. In this example, the variable's value will be equal to A0. If necessary, modify this value to match the actual I/O pin that your speaker is connected to.

PIN MODE: Analog inputs do NOT need to have their pin mode set within the setup() function. Their pin mode gets automatically set when the analogRead() method is used.

Read Light Sensor

The analogRead() method is used to read the light sensor, which indicates the amount of ambient light reaching the sensor.

Add this code (modify as necessary) to your app within the loop() function or a custom function:

A local variable named lightRead is declared that will have a data type of int (integer). This variable is made equal to whatever value is returned by the analogRead() method. You can change the name of this variable, but it will make sense if it's similar to the variable name used for the trimpot pin number.

The analogRead() method requires one parameter insides its parentheses:

  1. The I/O pin number, which can be the actual pin number (such as: A0, etc.) or a variable that stores a pin number. In this example, the variable named light is listed. If necessary, change this to match the variable name for your trimpot's pin number.

The analogRead() method will return an integer (whole number) value ranging from 0-4095:

  • When there is less light detected, the reading will have a lower value.

  • When there is more light detected, the reading will have a higher value.

You'll need to add code to do something with the reading stored as lightRead. For example, this might be an if-else statement to perform certain actions based on whether lightRead is greater than (or less than) one or more specific values.

GATHER TEST VALUES

Depending on the specific purpose of the light sensor in your device, you may need to gather some test values under different conditions to see how dark or how bright the environment will actually be where your device will be used. This will help you determine which values to use in your code to make decisions. For example, if the light sensor will be used to turn on an LED light when a room is too dark, what value will be used to decide that the room is too dark?

For example, the code below uses a value of 250 to decide whether a room is too dark. However, you would need to gather test data to determine whether this value should be higher or lower.

Map Value to Custom Range

In many cases, it may not be convenient to work with a value that ranges from 0-4095. Instead, it might be easier to have a value within a smaller custom range (such as: 0-10, 0-100, etc.) that makes more sense for your particular task.

The map() function can be used to convert a value from its original range (such as 0-4095) into a new range of your choice. You decide the minimum and maximum values for the new range.

For example, if the light sensor were being used to automatically turn on an LED light when the environment is too dark, you might want the sensor to return a value between 0-100 as an easier way to determine the relative brightness of the environment.

Add this code (modify as necessary) to your app within the loop() function or a custom function:

As necessary, change the values assigned to minValue and maxValue to whatever numbers you want to use for your custom range. Also, the minValue doesn't have to be zero.

Be sure to add code to do something with lightValue. For example, this might be an if-else statement to perform certain actions based on whether lightValue is greater than (or less than) one or more specific values.

NOTE: The code uses the round() method to round the mapped value to the nearest integer because the map() method returns a float (decimal value). Also, inside the map() method, the code intentionally adds 1 to the maxValue because otherwise it is very difficult to get the maximum value even if the ambient light in the environment is very bright.

CUSTOM FUNCTION TO READ ANALOG SENSORS

You could incorporate this code into a custom function called checkSensor() that will read an analog sensor and return a value mapped to a custom range:

When calling the checkSensor() function within the loop() function, you will need to include values for these 3 parameters (in order) inside its parentheses:

  1. the sensor's pin number, which will most likely be a variable that stores the pin number

  2. the desired minimum value for the range, which should be an integer (whole number)

  3. the desired maximum value for the range, which should be an integer (whole number)

The checkSensor() function will return the mapped sensor value as an integer, which your code should store in a variable of data type int.

For example, to call the checkSensor() function within the loop() function:

The checkSensor() function could also be used to read other analog sensors, such as a trimpot dial:

Servo Motor

The servo motor included in your Photon kit can rotate back or forth to any position between 0° and ~180° and hold its position.

The servo motor comes with 4 different plastic mounts called "horns" that can be attached to the motor axis (the white part sticking out of the top of the motor – this is what actually rotates). There is a single-arm horn, a double-arm horn, a four-point horn, and a circular horn. Each horn slips onto the motor axis (the horn and axis have matching "teeth"). Each horn has holes, which can allow you to attach something to the horn using the included screws.

NO CONTINUOUS ROTATION

This servo motor can rotate to a specific angle (up to ~180°) and hold its position. It does NOT rotate continuously, like a motor used in a fan or an engine. If your IoT device requires a motor that can rotate continuously, then you need a or a .

How to Connect Servo Motor

The servo motor has a built-in 3-wire connector. You'll plug 3 jumper wires into the connector, and then plug the other end of each wire into the breadboard or directly into a pin on the Photon circuit board.

Requires PWM Pin

The white wire of the servo motor must be connected to an I/O pin capable of (PWM), which is a process used to make a digital output signal (which has only two values: HIGH or LOW) act like an analog output signal (which has a range of values).

These Photon I/O pins are capable of PWM output: A4, A5, D0, D1, D2, D3, RX, TX, WKP.

Connect to Photon

To connect a servo motor to your Photon using the breadboard, you will need:

  • Servo Motor (with 3-wire connector)

  • 3 jumper wires (use different colors to help identify them; it may help to match the motor wires)

5V REQUIRED: The servo motor requires 5V of power to operate.

  • If your Photon is being powered through the barrel jack, connect to the VIN pin.

  • If your Photon is being powered through the Micro-USB port, connect to the V-USB pin.

Here are the steps to connect the servo motor to your Photon using the breadboard:

  1. Plug one end of a jumper wire into the motor's white wire connector. Plug the other end of this jumper wire into a PWM-capable I/O pin on the Photon circuit board.

  2. Plug one end of a second jumper wire into the motor's red wire connector. Plug the other end of this jumper wire into either the VIN pin or V-USB pin on the Photon circuit board (or to a positive power rail on the breadboard that is connected to VIN or V-USB). If your Photon is being powered through the barrel jack, connect to the VIN pin. Otherwise, if your Photon is being powered through the Micro-USB port, connect to the V-USB pin.

  3. Plug one end of a third jumper wire into the motor's black wire connector. Plug the other end of this jumper wire into a pin hole connected to GND: either plug it into a negative power rail on the breadboard (which is connected to GND via a different jumper wire), or plug it directly into a GND pin on the Photon circuit board.

Here's a wiring diagram showing a possible way to connect a servo motor (ignore the wiring for the push button):

Keep in mind that your connection can look different than this example diagram:

  • Your servo motor's white wire could connect to a different I/O pin capable of PWM output. (The example connects to the D0 pin on the Photon circuit board).

  • Your servo motor's red wire could connect to either the VIN pin or V-USB pin – or to a positive power rail connected to one of these pins. (The example connects directly to the V-USB pin.)

  • Your servo motor's black wire could connect either to a different GND pin or to a negative power rail connected to a GND pin. (There are three available GND pins.)

  • Alternatively, you could connect the servo motor's wires into different terminal strip rows on a breadboard, and then use 3 additional jumper wires to connect to the Photon circuit board.

Connect Horn to Motor

Be sure to attach one of the horns to your servo motor. Otherwise, rotating the motor won't provide much use to your device.

Later, once you test out your code to rotate the servo motor, you may need to remove and re-position the horn, so it's lined up where you want it to be as it rotates to specific angles. The best way to do this is to rotate the servo motor to 0° (or another specific angle, such as 90°) and then remove & re-position the horn to be pointed correctly for this particular angle.

How to Code Servo Motor

The basic steps to control a servo motor in your app code are:

  1. Declare a global variable to store the I/O pin number for the servo motor.

  2. Create a Servo object assigned to a global variable called servo.

  3. Use a sequence of servo.attach(), servo.write(), and servo.detach() statements to rotate the motor to a specific angle.

Library

The servo motor requires a code library that defines a class called Servo which has built-in methods (functions) for controlling the motor. However, this library is already included in the Particle firmware on your Photon device, so you do not need an #include statement to add the library to your app.

Global Variables

You should declare a global variable to store the I/O pin number that the servo motor is connected to. This will make it easier to understand your code (and easier to modify the code if you were to connect the servo motor to a different pin number).

You will also need to create an object using the Servo class included in the Particle firmware, and assign this object to a global variable.

Add this code (modify if necessary) before the setup() function:

The first line of code does 3 things (in order):

  1. It declares a data type for the variable's value. In this case, int stands for integer (whole number). Photon pin numbers are always treated as int values (even though they have letters).

  2. It declares the variable's name. In this example, the variable will be called motor. You can change the variable name, but choose a name that will make sense to anyone reading the code.

  3. It assigns a value to the variable. In this example, the variable's value will be equal to D0. If necessary, modify this value to match the actual I/O pin that your servo motor is connected to.

The second line of code creates a new object using the Servo class, and assigns the object to a global variable named servo.

NOTE: The Servo class name starts with an uppercase letter "S", while the servo object variable name starts with a lowercase letter "s".

NO PIN MODE: Because you are controlling the servo motor using an object, you do not have to set a pin mode for the servo motor within the setup() function.

Function to Rotate Servo

The servo motor can rotate back or forth to any position between 0° and ~180° and hold its position.

Rotating the servo motor to a specific angle requires a sequence of four steps:

  1. Turn on the motor using the servo.attach() method.

  2. Rotate the motor to a specific angle using the servo.write() method.

  3. Allow time for the motor to finish rotating by using the delay() method.

  4. Turn off the motor using the servo.detach() method.

You'll add a custom function named rotateServo() that will contain all these steps. The function will accept a parameter representing the desired angle of rotation.

Add this rotateServo() custom function after the loop() function:

The rotateServo() function requires a parameter for the specific angle of rotation. The parameter value must be an integer (whole number) and will be stored in a local variable named angle.

Here's what the code inside the rotateServo() function does:

  1. The servo.attach() method turns on the motor. This method requires the servo motor I/O pin number. In this case, the global variable named motor stores this value. If you used a different name for the global variable storing your servo motor pin number, then insert that name instead.

  2. The servo.write() method rotates the motor. This method requires an integer value from 0-180 representing the angle for the rotation. In this case, the parameter variable named angle stores the value that will be used.

  3. A delay() of 500 ms (0.5 seconds) is included to give the motor enough time to physically rotate before turning the motor off again.

  4. The servo.detach() method turns off the motor. Otherwise, if the motor isn't turned off, the motor will be "jittery" as it tries to hold its position. After you turn off the motor, you may notice that it "debounces" (rotates backward slightly). This is normal.

Calling Servo Function

The rotateServo() function can be called within the setup() function, loop() function, or another custom function.

When calling the rotateServo() function, you must include the desired angle of rotation (0-180) within the parentheses after the function name.

For example, to make the servo motor rotate to an angle of 90°, insert this code statement to call the rotateServo() function:

APPROX. 180°: In reality, this servo motor can only physically rotate to about 160°, even if it is told to rotate to 180°. Just keep this in mind as you design and build your device.

CHECK HORN POSITION: Once you've got your servo motor working, you may need to remove and re-position its horn, so the horn is lined up where you want it to be as it rotates to specific angles. The best way to do this is to rotate the servo motor to 0° (or another specific angle, such as 90°) and then remove and re-position the horn to be pointed correctly for this particular angle.

ROTATE SERVO IN SETUP: In order to ensure that your device functions correctly, you should include a code statement to rotate your servo motor to a specific starting angle (such as 0°, 90°, 180°, etc.) in the setup() function. Otherwise, the servo motor will start at whatever angle it was at when the device was last powered off.

Read Servo Angle

If necessary, the servo.read() method can be used to get the current angle of the servo motor. The method will return an integer value (whole number) between 0-180 representing the last angle used in the servo.write() method.

Add this code statement wherever you need to read the current angle of the servo motor:

This code statement creates a local variable named angle to store the integer value returned by servo.read().

Trimpot

Photon Pin

Outer Leg (pick one)

3.3V

Middle Leg

any analog I/O pin (A0, A1, A2, A3, A4, A5)

Other Outer Leg

GND

int trimpot = A0;
int trimpotRead = analogRead(trimpot);
// add code to do something with trimpotRead
int trimpotRead = analogRead(trimpot);
int minValue = 0;
int maxValue = 255;
int trimpotValue = round(map(trimpotRead, 0, 4095, minValue, maxValue + 1));
// add code to do something with trimpotValue
int checkSensor(int pin, int minValue, int maxValue) {
    int sensorRead = analogRead(pin);
    int mapValue = round(map(sensorRead, 0, 4095, minValue, maxValue + 1));
    return mapValue;
}
int trimpotValue = checkSensor(trimpot, 0, 255);
// add code to do something with trimpotValue
int lightValue = checkSensor(light, 0, 100);
// add code to do something with lightValue
Trimpot Dial (side view)
Trimpot Dial (top view): Maximum Range of Rotation

LED Light

Photon Pin

Positive Leg (bent) = Power

any I/O pin

Negative Leg = Ground

GND using resistor

int LED = D0;
int redLED = D0;
int greenLED = D1;
pinMode(LED, OUTPUT);
pinMode(redLED, OUTPUT);
pinMode(greenLED, OUTPUT);
digitalWrite(LED, HIGH);
analogWrite(LED, 128);
polarized
resistor
pulse-width modulation
LED Lights in various colors
LED with Bent Leg
Bending Resistor Legs

Light Sensor (Photocell)

Photon Pin

First Leg (either one)

3.3V

Second Leg

(1) any analog I/O pin (A0, A1, A2, A3, A4, A5)

(2) GND using resistor

int light = A0;
int lightRead = analogRead(light);
// add code to do something with lightValue
if (lightRead < 250) {
    // turn on LED when room is too dark
    digitalWrite(LED, HIGH);
}
else {
    // otherwise, turn off LED
    digitalWrite(LED, LOW);
}
int lightRead = analogRead(light);
int minValue = 0;
int maxValue = 100;
int lightValue = round(map(lightRead, 0, 4095, minValue, maxValue + 1));
// add code to do something with lightValue
int checkSensor(int pin, int minValue, int maxValue) {
    int sensorRead = analogRead(pin);
    int mapValue = round(map(sensorRead, 0, 4095, minValue, maxValue + 1));
    return mapValue;
}
int lightValue = checkSensor(light, 0, 100);
// add code to do something with lightValue
int trimpotValue = checkSensor(trimpot, 0, 255);
// add code to do something with trimpotValue
voltage divider
Light Sensor (aka Photocell)
Bending Resistor Legs

Servo Motor

Photon Pin

White – Data

any I/O pin capable of PWM output

Red – Power (4.8-6V)

5V through VIN or V-USB

Black – Ground

GND

int motor = D0;
Servo servo;
void rotateServo(int angle) {
    ​servo.attach(motor);
    servo.write(angle);
    delay(500);
    servo.detach();
}
rotateServo(90);
int angle = servo.read();
gear motor
continuous rotation servo motor
pulse-width modulation
Servo Motor and Horns
Your Photon kit has a regular servo motor

Ultrasonic Sensor *

ADD-ON COMPONENT: The SparkFun Photon Kit does NOT include an ultrasonic sensor as a standard component. However, SparkFun sells the , which can be easily connected to a Photon. Your teacher may have added this sensor to your kit.

An ultrasonic sensor uses sonar to measure the distance to an object, similar to how bats and dolphins use for navigation and hunting.

An ultrasonic sensor has a transmitter (i.e., speaker) that produces high-frequency sound (beyond the range of human hearing). The sensor also has a matching receiver (i.e., microphone) that detects the echo of the high-frequency sound when it reflects back from an object. By measuring how much time it takes for the echo to arrive, you can calculate the distance between the sensor and the object.

The HC-SR04 ultrasonic sensor measures distances in a narrow cone of about 15° directly in front of the sensor. This sensor can detect obstacles located up to 400 cm away (about 13 feet). The sensor measurements are very accurate, within about 3 mm (about 0.1 inch) of the actual distance.

How to Connect Sensor

The HC-SR04 ultrasonic sensor has 4 pins for plugging into a breadboard. Each pin is labeled on the sensor's circuit board.

To connect the ultrasonic sensor to your Photon using the breadboard, you will need:

  • Ultrasonic Sensor (HC-SR04)

  • 4 jumper wires (use different colors to help identify them)

5V REQUIRED: The ultrasonic sensor requires 5V of power to operate.

  • If your Photon is being powered through the barrel jack, connect to the VIN pin.

  • If your Photon is being powered through the Micro-USB port, connect to the V-USB pin.

Here are the steps to connect the ultrasonic sensor to your Photon using the breadboard:

  1. Insert the 4 pins of the ultrasonic sensor into different terminal strip rows on the breadboard. (Different terminal strip rows have different row numbers.) It is recommended to insert the sensor on the left half of the breadboard with the transmitter and receiver facing away from the Photon.

  2. Plug one end of a jumper wire into the same terminal strip row as the sensor's VCC pin. Plug the other end of this jumper wire into either the VIN pin or V-USB pin on the Photon circuit board (or to a positive power rail on the breadboard that is connected to VIN or V-USB). If your Photon is being powered through the barrel jack, connect to the VIN pin. Otherwise, if your Photon is being powered through the Micro-USB port, connect to the V-USB pin.

  3. Plug one end of a second jumper wire into the same terminal strip row as the sensor's Trig pin. Plug the other end of this jumper wire into an I/O pin on the Photon circuit board.

  4. Plug one end of a third jumper wire into the same terminal strip row as the sensor's Echo pin. Plug the other end of this jumper wire into an I/O pin on the Photon circuit board.

  5. Plug one end of a fourth jumper wire into the same terminal strip row as the sensor's GND pin. Plug the other end of this jumper wire into a pin hole connected to GND: either plug it into a negative power rail (which is connected to GND via a different jumper wire), or plug it directly into a GND pin on the Photon circuit board.

Here's a wiring diagram showing a possible way to connect the ultrasonic sensor:

Keep in mind that your connection can look different than this example diagram:

  • Your ultrasonic sensor pins could be inserted into different row numbers. (The example connects the sensor pins to rows 23-26 on the left side of the breadboard.)

  • Your motion sensor pins could be inserted into a different column of the breadboard. (The example connects the sensor pins into column B of the terminal strip rows.)

  • Your sensor's VCC pin could connect (through a jumper wire) to either the VIN pin or V-USB pin (or to a positive power rail that's connected to one of these pins). (The example connects directly to the VIN pin.)

  • Your sensor's Trig pin could connect (through a jumper wire) to a different I/O pin. (The example connects to the D2 pin.)

  • Your sensor's Echo pin could connect (through a jumper wire) to a different I/O pin. (The example connects to the D3 pin.)

  • Your sensor's GND pin could connect (through a jumper wire) to either to a GND pin or to a negative power rail connected to a GND pin. (There are three available GND pins.)

How to Code Sensor

The basic steps to use an ultrasonic sensor in your app code are:

  1. Declare global variables to store the I/O pin numbers for the ultrasonic sensor.

  2. Set the pin modes for the sensor in the setup() function, and turn off the transmitter.

  3. Use a custom function that will measure and return the distance to the nearest object.

Global Variables

You should declare global variables to store the I/O pin numbers that the ultrasonic sensor's transmitter (Trig) and receiver (Echo) are connected to. This will make it easier to understand your code (and easier to modify the code if you were to connect the trimpot to a different pin number).

Add this code (modify if necessary) before the setup() function:

Each line of code does 3 things (in order):

  1. It declares a data type for the variable's value. In this case, int stands for integer (whole number). Photon pin numbers are always treated as int values (even though they have letters).

  2. It declares the variable's name. In this example, the variables will be called TRIG_PIN (transmitter) and ECHO_PIN (receiver). You can change the variable names, but choose names that will make sense to anyone reading the code. You will need to make sure the same variable names are listed in the custom function which measures the distance to the nearest object.

  3. It assigns a value to the variable. In this example, the variables will be equal to D2 and D3. If necessary, modify these values to match the I/O pins that your sensor pins are connected to.

Set Pin Modes & Turn Off

You need to set the pin modes for the sensor's transmitter (Trig) and receiver (Echo). Then you need turn off the sensor's transmitter until you're ready to actually take a distance measurement.

Add this code (modify if necessary) within the setup() function:

The pinMode() method requires two parameters inside its parentheses (in this order):

  1. The I/O pin number, which can be the actual pin number (such as: D2, etc.) or a variable that stores a pin number. In this example, the variables named TRIG_PIN and ECHO_PIN are listed. If necessary, change these to match the variable names for your sensor's pins.

  2. The mode value, which will be OUTPUT for the sensor's transmitter pin and INPUT for the sensor's receiver pin.

The digitalWrite() method requires two parameters inside its parentheses (in this order):

  1. The I/O pin number, which can be the actual pin number (such as: D2, etc.) or a variable that stores a pin number. In this example, the variable named TRIG_PIN is listed. If necessary, change this to match the variable name for your sensor's transmitter pin.

  2. The signal value, which can be HIGH or LOW. Your Photon uses this value to send an electrical signal through the pin: HIGH is a signal of 3.3 volts which represents "on," while LOW is a signal of 0 volts which represents "off." In this case, LOW is being used to turn off the transmitter.

Add Function to Measure Distance

You'll add a custom function named measureDistance() than can be called to measure the distance from the ultrasonic sensor to the nearest object. The function will return the distance as a float value (decimal number).

Add this measureDistance() function after the loop() function:

Possible modifications to this custom function:

  • If you used different names for the global variables representing the transmitter (TRIG_PIN) and receiver (ECHO_PIN), then be sure to modify this function to use those variable names instead.

  • If you want the function to return the distance measurement in units of centimeters (instead of inches), then modify the return statement towards the end of the function.

Call Function to Measure Distance

Each time you need a new distance measurement, you'll need to call the measureDistance() function.

To call this custom function, add this code within the loop() function (or within another custom function):

A local variable named sensorDist is declared that will have a data type of float (decimal number). This variable will be made equal to the value returned by the measureDistance() function.

You'll need add code to do something with the distance measurement stored in sensorDist. It's common to use an if statement (or an if-else statement) to perform certain actions based on whether the distance is less than (or greater than) a specific value.

For example, this code example will turn on an LED light if the distance is less than 6 inches (otherwise it will turn the LED off):

TEST ULTRASONIC SENSOR

A good way to test your ultrasonic sensor is to connect the Micro OLED display to your Photon, so you can show the value of sensorDist on the OLED screen to verify the sensor is working accurately.

For example, once you've added the other necessary code for the Micro OLED, you could add this code within the loop() function:

Ultrasonic Sensor

Photon Pin

VCC

5V through VIN or V-USB

Trig

any I/O pin

Echo

any I/O pin

GND

GND

int TRIG_PIN = D2;
int ECHO_PIN = D3;
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
digitalWrite(TRIG_PIN, LOW);
float measureDistance() {

    // HC-SR04 ultrasonic sensor
    
    unsigned long start_time, end_time, pulse_time;

    // trigger ultrasonic signal for 10 microseconds
    digitalWrite(TRIG_PIN, HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIG_PIN, LOW);

    // wait until echo received 
    while (digitalRead(ECHO_PIN) == 0);

    // measure how long echo lasts (pulse time)
    start_time = micros(); // get start time (in microseconds)
    while (digitalRead(ECHO_PIN) == 1); // wait until echo ends
    end_time = micros(); // get end time
    pulse_time = end_time - start_time; // subtract to get duration

    // pulse time of 23200 represents maximum distance for this sensor
    if (pulse_time > 23200) pulse_time = 23200;

    // calculate distance to object using pulse time
    float dist_in = pulse_time / 148.0; // inches
    float dist_cm = pulse_time / 58.0; // centimeters

    delay(60); // need 60 ms delay between ultrasonic readings
    
    return dist_in; // or can return dist_cm
}
    float sensorDist = measureDistance();
    // add code to do something with sensorDist
    
    float sensorDist = measureDistance();
    if (sensorDist < 6) {
        digitalWrite(LED, HIGH);
    } else {
        digitalWrite(LED, LOW);
    }
    float sensorDist = measureDistance();
    oled.clear(PAGE);
    oled.setFontType(2);
    oled.setCursor(0, 0);
    oled.println(sensorDist, 1); // print to 1 decimal place
    oled.display();
HC-SR04 Ultrasonic Sensor
echolocation
Ultrasonic Sensor (HC-SR04)

Soil Moisture Sensor

The soil moisture sensor in your Photon kit can be inserted into soil or similar materials (sand, etc.) to measure the amount of moisture in the material.

Soil Moisture Sensor

How to Connect Moisture Sensor

The moisture sensor is a variable resistor with two gold-plated legs that are inserted into soil. Moisture in the soil will conduct electricity from one sensor leg to the other. The amount of electricity conducted depends on the amount of soil moisture.

Attach Wires to Sensor

The soil moisture sensor in your Photo kit has a 3-pin screw terminal. You'll need to attach 3 jumper wires to the screw terminal. The back of the sensor has labels for the 3 pins: SIG, GND, VCC.

To attach jumper wires to the soil moisture sensor, you will need:

  • Soil moisture sensor with 3-pin screw terminal

  • 3 jumper wires (use different colors to help identify them; recommend red, black, and yellow)

  • Small flat-head screwdriver (obtain from teacher, if necessary)

  1. Use a small flat-head screwdriver to turn each screw counterclockwise until slightly loosened (but don't remove them). This creates openings on the top of the terminal to insert the jumper wires.

  2. Insert one end of the first jumper wire (yellow) into the terminal slot for SIG. Then use the screwdriver tighten that terminal's screw (turn clockwise) until the jumper wire is held firmly.

  3. Insert one end of the second jumper wire (black) into the terminal slot for GND. Then use the screwdriver tighten that terminal's screw (turn clockwise) until the jumper wire is held firmly.

  4. Insert one end of the third jumper wire (red) into the terminal slot for VCC. Then use the screwdriver tighten that terminal's screw (turn clockwise) until the jumper wire is held firmly.

Jumper Wires Connected to Screw Terminal

Connect to Breadboard

To connect a soil moisture sensor to your Photon using the breadboard, you will need:

  • Soil Moisture Sensor with 3 attached jumper wires

Soil Moisture Sensor

Photon Pin

SIG (Signal) – Yellow

any analog I/O pin (A0, A1, A2, A3, A4, A5)

GND (Ground) – Black

GND

VCC (Power) – Red

any I/O pin

DUAL I/O PINS: The soil moisture sensor is connected to two different I/O pins. The sensor's SIG wire is connected to an analog I/O pin that will be used as an input to read data signals from the sensor. The sensor's VCC wire is connected to another I/O pin that will be used as an output to provide power to the sensor when taking a reading.

TWIN PINS: Analog pins A2, A3, A4, and A5 are each represented by two pins on the Photon board. The duplicate pins are labeled as: SS/A2, SCK/A3, MISO/A4, MOSI/A5. If you use one of these pins, you cannot use its twin at the same time.

Here are the steps to connect the soil moisture sensor to your Photon using the breadboard:

  1. Plug the SIG jumper wire into any analog I/O pin on the Photon circuit board.

  2. Plug the GND jumper wire into a pin hole connected to GND: either plug it into a negative power rail on the breadboard (which is connected to GND via a different jumper wire), or plug it directly into a GND pin on the Photon circuit board.

  3. Plug the VCC jumper wire into any I/O pin on the Photon circuit board.

Here's a wiring diagram showing a possible way to connect a soil moisture sensor:

Keep in mind that your connection can look different than this example diagram:

  • Your moisture sensor's SIG wire could connect to a different analog I/O pin. (The example connects to the A2 pin.)

  • Your moisture sensor's GND wire could connect either to a different GND pin or to a negative power rail connected to a GND pin. (There are three available GND pins.)

  • Your moisture sensor's VCC wire could connect to a different I/O pin. (The example connects to the D6 pin.)

  • Alternatively, you could connect the sensor's wires into different terminal strip rows on a breadboard, and then use 3 additional jumper wires to connect to the Photon circuit board.

Insert Sensor into Soil

Once the moisture sensor is connected to the Photon, insert the sensor legs into the soil (or similar material) where you need to take moisture measurements.

Moisture Sensor Inserted into Soil of Potted Plant

How to Code Moisture Sensor

The basic steps to control a soil moisture sensor in your app code are:

  1. Declare global variables to store the I/O pin numbers for the moisture sensor.

  2. Set the pin mode for the sensor's power pin in the setup() function, and turn off the sensor.

  3. Use a sequence of digitalWrite() and analogRead() statements to briefly turn on the sensor and read the soil moisture.

  4. OPTIONAL: Use the map() method to convert the sensor reading to a custom range.

Global Variables

You should declare global variables to store the I/O pin numbers that the moisture sensor's SIG wire (data signal) and VCC wire (power) are connected to. This will make it easier to understand your code (and easier to modify the code if you were to connect the trimpot to a different pin number).

Add this code statement (modify if necessary) before the setup() function:

int soil = A2;
int soilPower = D6;

Each line of code does 3 things (in order):

  1. It declares a data type for the variable's value. In this case, int stands for integer (whole number). Photon pin numbers are always treated as int values (even though they have letters).

  2. It declares the variable's name. In this example, the variables will be called soil and soilPower. You can change the names, but choose names that will make sense to anyone reading the code.

  3. It assigns a value to the variable. In this example, soil will be equal to A2 and soilPower will be equal to D6. If necessary, modify these values to match the actual I/O pins that your sensor's SIG and VCC wires are connected to.

Set Pin Mode & Turn Off

You need to set the pin mode for the moisture sensor's power pin to be used as an output. Then you need turn off the power to the sensor until you're ready to actually take a sensor reading.

Add this code (modify if necessary) within the setup() function:

pinMode(soilPower, OUTPUT);
digitalWrite(soilPower, LOW);

The pinMode() method requires two parameters inside its parentheses (in this order):

  1. The I/O pin number, which can be the actual pin number (such as: D6, etc.) or a variable that stores a pin number. In this example, the variable named soiPower is listed. If necessary, change this to match the variable name for your moisture sensor's power pin.

  2. The mode value, which will always be OUTPUT for an LED light because your app will send "on" and "off" signals (or brightness signals) to the LED light.

The digitalWrite() method requires two parameters inside its parentheses (in this order):

  1. The I/O pin number, which can be the actual pin number (such as: D6, etc.) or a variable that stores a pin number. In this example, the variable named soiPower is listed. If necessary, change this to match the variable name for your moisture sensor's power pin.

  2. The signal value, which can be HIGH or LOW. Your Photon uses this value to send an electrical signal through the pin: HIGH is a signal of 3.3 volts which represents "on," while LOW is a signal of 0 volts which represents "off." In this case, LOW is being used to turn off the moisture sensor.

PIN MODE: Analog inputs do NOT need to have their pin mode set within the setup() function. Their pin mode gets automatically set when the analogRead() method is used. That's why there's no pinMode() statement for the soil pin.

WHY TURN OFF POWER?

A constant flow of electricity across the moisture sensor legs could cause them to corrode over time due to the natural salts and other minerals found in soil. The gold-plating on the sensors legs resist corrosion, but it's still better to only briefly turn on the sensor's power when taking a reading.

Read Moisture Sensor

Reading the soil moisture always requires a sequence of four steps:

  1. Turn on the sensor's power using the digitalWrite() method.

  2. Allow time for electricity to flow through the soil by using the delay() method.

  3. Read the soil moisture using the analogRead() method.

  4. Turn off the sensor's power using the digitalWrite() method.

digitalWrite(soilPower, HIGH);
delay(10);
int soilRead = analogRead(soil);
digitalWrite(soilPower, LOW);​
// add code to do something based on value of soilRead

A local variable named soilRead is declared that will have a data type of int (integer). This variable is made equal to whatever value is returned by the analogRead() method. You can change the name of this variable, but it will make sense if it's similar to the variable name used for the trimpot pin number.

The analogRead() method requires one parameter insides its parentheses:

  1. The I/O pin number, which can be the actual pin number (such as: A2, etc.) or a variable that stores a pin number. In this example, the variable named soil is listed. If necessary, change this to match the variable name for the pin number of your sensor's SIG wire.

The analogRead() method will return an integer (whole number) value ranging from 0-4095:

  • When there is less moisture detected, the reading will have a lower value.

  • When there is more moisture detected, the reading will have a higher value.

You'll need to add code to do something with the reading stored as soilRead. For example, this might be an if-else statement to perform certain actions based on whether soilRead is greater than (or less than) one or more specific values.

GATHER TEST VALUES

Depending on the specific purpose of the moisture sensor in your device, you may need to gather some test values under different conditions (such as dry vs. wet) to see what the moisture values might actually be where your device will be used. This will help you determine which values to use in your code to make decisions. For example, if the moisture sensor will be used to send notifications when the soil is either too dry or too wet, what values will be used to decide this?

For example, the code below uses a value of 500 to decide whether the soil is too dry and a value of 3500 to decide whether the soil is too wet. However, you would need to gather test data to determine whether these values should be higher or lower.

if (soilRead < 500) {
    // send notification when soil is too dry
    Particle.publish("soil", "dry");
}
else if (soilRead > 3500) {
    // send notification when soil is too wet
    Particle.publish("soil", "wet");
}

Map Value to Custom Range

In many cases, it may not be convenient to work with a value that ranges from 0-4095. Instead, it might be easier to have a value within a smaller custom range (such as: 0-10, 0-100, etc.) that makes more sense for your particular task.

The map() function can be used to convert a value from its original range (such as 0-4095) into a new range of your choice. You decide the minimum and maximum values for the new range.

For example, if the moisture sensor were being used to automatically turn a sprinkler system on and off, you might want the sensor to return a value between 0-100 as an easier way to determine the relative soil moisture.

Add this code (modify as necessary) to your app within the loop() function or a custom function:

digitalWrite(soilPower, HIGH);
delay(10);
int soilRead = analogRead(soil);
digitalWrite(soilPower, LOW);​
int minValue = 0;
int maxValue = 100;
int soilValue = round(map(soilRead, 0, 4095, minValue, maxValue + 1));
// add code to do something with soilValue

As necessary, change the values assigned to minValue and maxValue to whatever numbers you want to use for your custom range. Also, the minValue doesn't have to be zero.

Be sure to add code to do something with soilValue. For example, this might be an if-else statement to perform certain actions based on whether soilValue is greater than (or less than) one or more specific values.

NOTE: The code uses the round() method to round the mapped value to the nearest integer because the map() method returns a float (decimal value). Also, inside the map() method, the code intentionally adds 1 to the maxValue because otherwise it is very difficult to get the maximum value even if the soil moisture is very high.

CUSTOM FUNCTION TO READ MOISTURE SENSOR

You could incorporate this code into a custom function called checkSoil() that will read the soil moisture sensor and return a value mapped to a custom range:

int checkSoil() {
    digitalWrite(soilPower, HIGH);
    delay(10);
    int soilRead = analogRead(soil);
    digitalWrite(soilPower, LOW);​
    int minValue = 0;
    int maxValue = 100;
    int mapValue = round(map(soilRead, 0, 4095, minValue, maxValue + 1));
    return mapValue;
}

If necessary, change the variable names for the sensor's pins to match your variable names. You can also change the values assigned to minValue and maxValue to whatever numbers you want to use for your custom range.

The checkSoil() function will return the mapped sensor value as an integer, which your code should store in a variable of data type int.

For example, to call the checkSoil() function within the loop() function:

int soilValue = checkSoil();
// add code to do something with soilValue

C-6 Particle Cloud Code

Next, you'll modify your Smart Light device app to allow a web app to interact with your Photon through the internet.

Particle Cloud

All of your Photon's internet communications are routed through the Particle Cloud service, which offers these ways that a web app can interact with a Photon device through Particle Cloud:

  1. A web app can get the value of a Photon device variable

  2. A web app can call a custom function on a Photon device

  3. A web app can get event notifications from a Photon device

The web app that you'll be creating for your Smart Light device will perform these two tasks:

  1. The web app will display whether the LED light is currently turned on or off. The web app will do this by getting the current value of the lightStatus variable in your Photon device app.

  2. The web app will display a button that can be clicked to remotely turn the LED light on or off. The web app will do this by calling the toggleLight() function in your Photon device app.

You'll need to add some code to your Photon device app that will allow your web app to get the value of the lightStatus variable and to call the toggleLight() function.

Share Device Variable

In order for a web app to get the value of Photon device variable, your Photon device app must share the variable through Particle Cloud using the Particle.variable() method.

Share the lightStatus variable through Particle Cloud by adding this code statement within the setup() function of your Photon app:

Particle.variable("lightStatus", lightStatus);

This Particle.variable() code statement creates a "cloud variable" that stores the value of your Photon device variable. Whenever the value of the device variable changes in your Photon app, the value stored in the cloud variable will be automatically synced to match.

The Particle.variable() method requires two parameters inside its parentheses (in this order):

  1. The cloud variable name, which can be up to 12 characters in length. If possible (for simplicity), make your cloud variable name match your device variable name. However, the cloud variable is allowed to have a different name. The cloud variable name must be listed within double quotation marks. In this case, "lightStatus" will be the name of the cloud variable (which matches the device variable name).

  2. The Photon device variable name, which is the variable in your Photon app whose value will be shared in Particle Cloud. In this case, you're sharing the value of the lightStatus variable.

Share Device Function

In order for a web app to call a function that runs on your Photon device, your Photon device app must share the function through Particle Cloud using the Particle.function() method.

Share the toggleLight() function through Particle Cloud by adding this code statement within the setup() function of your Photon app:

Particle.function("toggleLight", toggleLight);

This Particle.function() code statement creates a "cloud function" that is a reference to the custom function in your Photon device app. Whenever your web app calls the cloud function, the corresponding device function in your Photon app will automatically be called.

The Particle.function() method requires two parameters inside its parentheses (in this order):

  1. The cloud function name, which can be up to 12 characters in length. If possible (for simplicity), make your cloud function name match your device function name. However, the cloud function is allowed to have a different name. The cloud function name must be listed within double quotation marks without parentheses after its name. In this case, "toggleLight" will be the name of the cloud function (which matches the device function name).

  2. The Photon device function name, which is the custom function in your Photon device app that will be shared through Particle Cloud. List the function name without parentheses after its name. In this case, you're sharing the toggleLight function in your Photon app.

Modify Device Function

A Photon device function that is shared through Particle Cloud must do the following:

  • The Photon function must accept a String parameter when the function is called.

  • The Photon function must return an integer value when the function is performed.

Currently, the toggleLight() function does not do these things – but you can easily modify the function to work with Particle Cloud with these minor changes:

  1. Change toggleLight() to toggleLight(String data). This adds a parameter inside the parentheses that will be accepted when the function is called: String is the data type for the parameter (a text string), and data is the name of a local variable that will store the parameter value (the text string). If desired, you could use a different name other than data.

  2. In front of the function name, change void to int. This indicates that the function will return an integer value (whole number), instead of no value (which is what void represents).

  3. Add the code statement return 1; inside the function at the end before the closing curly brace. This code statement will return an integer value of 1 whenever the function is performed. This is the simplest way to ensure the function returns an integer value.

Your custom function should look like this now:

int toggleLight(String data){
    if (lightStatus == "off") {
        digitalWrite(LED, HIGH);
        lightStatus = "on";
    }
    else {
        digitalWrite(LED, LOW);
        lightStatus = "off";
    }
    return 1;
}

You might notice that there aren't any code statements within the curly braces of the toggleLight() function that actually use the data parameter variable. That's actually okay – the function does have to accept a String parameter, but it doesn't have to use the parameter inside in the function.

However, depending on what a custom function is supposed to do, the text string passed into the data parameter could be used to decide what action(s) are performed within the custom function. In this case, you won't do that, but it is an option that's available.

Modify Call to Function

Once a custom function in your Photon device app has been modified to be shared through Particle Cloud, your Photon app (and your web app) must include a text string when calling the function.

In your Photon app, there's just one code statement that calls the toggleLight() function. Inside the loop() function, there is an if statement that calls the toggleLight() function when the button is pushed (buttonState == LOW):

  • Inside this if statement, change toggleLight(); to toggleLight("data");

In this case, "data" will be the text string passed into the parameter when this function is called. However, since this function doesn't actually do anything with the parameter value, this text string could be any text listed within double quotation marks – even an empty text string of "" would work.

Flash App to Device

Flash your app code to your Photon device by clicking the Flash icon in the left navigation bar.

Once your Photon has downloaded the app and restarted, the updated app will start running. You shouldn't notice any visible changes in the device's behavior, but your Photon app will now be sharing the lightStatus variable and toggleLight() function with Particle Cloud.

  • Confirm that the LED light still toggles between "on" and "off" each time the button is pressed.

Web App - Multiple Screens

You can also create a multi-screen web app that interacts with your Photon device through Particle Cloud. Your multi-screen web app will consist of an HTML file namedindex.html, a CSS file named style.css, and a JavaScript file named script.js.

Your web app will be a single-page application that dynamically shows different "screens." Your web app will only have one HTML page, but different <div> sections in the HTML will represent different screens. Your web app will only display one specific <div> screen at a time, while hiding the other <div> screens.

This section contains starter code that you can use for your HTML, CSS, and JS files. You'll need to add to the starter code (and modify certain parts).

This starter code has been designed to mimic the appearance and interaction of a native mobile app. A persistent navigation menu with icons will be displayed at the bottom of the viewport to allow the user to switch between screens to perform different tasks or view different information.

By default, this app code is designed to show 4 different screens (but you can modify the code to change the number of screens). This app code also has a <div> section that can be use to display an incoming notification from your smart device.

HTML

You can use this starter code for your HTML file named index.html:

<!DOCTYPE html>
<html>
  <head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>Smart Device Web App</title>
	<!-- Load Font Awesome for Icons -->
	<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css" integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
	<!-- Load CSS stylesheet -->
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <div id="notification">
	  <span class="closebtn" onclick="this.parentElement.style.display='none';">&times;</span>
	  <!-- HTML for Notification -->
	  <p>Notification Message</p>
			
	</div>
	<div class="screen" id="screen1">
	  <!-- HTML for Screen 1 -->
	  <h1>Screen 1</h1>

	</div>
	<div class="screen" id="screen2">
	  <!-- HTML for Screen 2 -->
	  <h1>Screen 2</h1>

	</div> 
	<div class="screen" id="screen3">
	  <!-- HTML for Screen 3 -->
	  <h1>Screen 3</h1>

	</div>
	<div class="screen" id="screen4">
	  <!-- HTML for Screen 4 -->
	  <h1>Screen 4</h1>
	
	</div>
	<div id="navigation">
	  <nav>
		<!-- Menu icons from Font Awesome -->
		<!-- Search for icons at: https://fontawesome.com/icons?d=gallery&m=free -->
		<a class="menu active" onclick="showScreen1()"><i class="fas fa-home fa-2x"></i><br>Screen 1</a>
		<a class="menu" onclick="showScreen2()"><i class="fas fa-user fa-2x"></i><br>Screen 2</a>
		<a class="menu" onclick="showScreen3()"><i class="fas fa-cog fa-2x"></i><br>Screen 3</a>
		<a class="menu" onclick="showScreen4()"><i class="fas fa-bars fa-2x"></i><br>Screen 4</a>			
	  </nav>
	</div>
	<!-- Load JavaScript files -->
	<script src="https://cdnjs.cloudflare.com/ajax/libs/particle-api-js/7.3.0/particle.min.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
	<script src="script.js"></script>
  </body>
</html>

COPY CODE: When using this IoT code guidebook, you can copy a code block simply by clicking the copy icon displayed in the upper right of the code block.

This HTML has been set up to display 4 different screens. However, you can modify the HTML to display more screens (or fewer screens).

This HTML does several things:

  1. It loads two CSS stylesheet files.

  2. It has <div> sections for a notification message and 4 different screens.

  3. It has a <nav> section to show the navigation menu for the screens.

  4. It loads three JavaScript files.

LOAD CSS STYLESHEETs

In the <head> section, there is a <link> tag to load a CSS stylesheet file named style.css that you'll use to modify the appearance of certain HTML elements in your web app.

There is also a <link> tag to load a CSS stylesheet from Font Awesome. This will allow you to display different icons using HTML code that you'll copy from Font Awesome.

<DIV> FOR NOTIFICATION

At the beginning of the <body> section, there is a <div> section with an id name of"notification" that can be used to display a popup notification message. This <div> will normally be hidden, but you can use JavaScript to display the notification.

If your web app won't need to display notifications, you can delete this <div> section (though you can just leave it and simply not use it – in case, you change your mind later).

For example, when an event notification is received from your smart device, your JavaScript can make the notification <div> appear (and can customize the message within the notification, if needed). The notification will appear as a popup at the top of the current screen (though you can change the position if desired).

<DIV> FOR EACH SCREEN

In the middle of the <body> section, there are several <div> sections to represent the different screens in your web app. Each <div> section has the same class name of screen to classify it as a screen but also has a unique id name to identify it as a specific screen: screen1, screen2, screen3, or screen4.

The starter code within each <div> simply displays a heading for the name of the screen (so you can see that clicking the navigation menu actually does switch screens). You'll remove (or revise) this heading, and add your own HTML for each screen to display text, images, buttons, etc.

<NAV> FOR SCREEN MENU

Towards the end of the <body> section, there is a <nav> section to display a navigation menu for switching between the different screens.

The <nav> contains anchor tags (<a>) for each screen. Normally, an anchor tag contains a link to a different HTML page, but in this case, the tags simply have an onclick attribute that will call a custom function in your JavaScript that will display a specific <div> screen.

Each anchor tag displays an icon from Font Awesome (using special <i> code), along with a text label. You can change the icon and the text label. In the starter code, each icon has the Font Awesome fa-2x class added, in order to display the icon at double size.

LOAD JAVASCRIPT FILES

At the end of the <body> section, there are <script> tags to load several JavaScript files into your web app:

  1. Particle API JS library: particle.min.js

  2. jQuery JS library: jquery.min.js

  3. Your web app JS file: script.js

The Particle API JS library contains methods to allow your web app to interact with your Photon device through Particle Cloud. You'll use Particle methods in your web app JS file.

The jQuery JS library contains methods that make it easy to modify the content and style of your web app by dynamically changing its HTML and CSS. You'll use jQuery methods in your web app JS file.

CSS

You can use this starter code for your CSS file named style.css:

/* Add or modify CSS for your web app */

* {
  box-sizing: border-box; /* use traditional box model sizing */
}

body {
  font-family: Helvetica, Arial, sans-serif;
  font-size: 1em;
  margin: 0;
  padding: 0;
  text-align: center;
}

/* #notification  */
#notification {
  display: none; /* hide until needed */
  position: fixed; /* fix to viewport */
  top: 0; /* place at top of viewport */
  left: 50%;
  transform: translate(-50%, 10px);
  max-width: 300px;
  width: calc(100vw - 20px);
  margin: 0 auto;
  padding: 10px 20px;
  background-color: #fbfbfb;
  border-radius: 10px;
  border: 1px solid #bbbbbb;
  box-shadow: 0px 0px 3px rgba(0, 0, 0, 0.3);
  text-align: left;
}

/* close button for notification */
.closebtn {
  margin: -15px -15px 10px 10px;
  padding: 10px;
  color: #888888;
  font-weight: bold;
  float: right;
  font-size: 1.5em;
  cursor: pointer;
  transition: 0.3s;
}

/* hover effect for close button */
.closebtn:hover {
  color: #000000;
}

/* .screen class applies to all screens */
.screen {
  max-width: 480px; /* mimic largest phone width */
  width: 100vw; /* width of viewport */
  height: calc(100vh - 4.5em); /* height of viewport minus height of #navigation menu */
  margin: 0 auto;
  padding: 20px 10px;
  overflow: auto;
  border: 1px solid #888888;
  /* can add other CSS for all screens, such as background-color, etc. */

}

/* show #screen1 when app first starts */
#screen1 {
	display: block;
}

/* hide other screens when app first starts */
#screen2, #screen3, #screen4 {
	display: none;
}

/* can add custom CSS for each specific screen */
#screen1 {

}

#screen2 {

}

#screen3 {

}

#screen4 {

}

/* #navigation menu fixed to bottom of viewport */
#navigation {
  position: fixed; /* fix to viewport */
  bottom: 0; /* place at bottom of viewport */
  left: 50%;
  transform: translate(-50%, 0);
  max-width: 480px; /* mimic largest phone width */
  width: 100vw; /* width of viewport */
  height: 4.5em;
  text-align: center;
  background-color: #ffffff;
  border: 1px solid #888888;
}

/* nav menu options */
nav > a {
	display: inline-block;
	/* for max-width and width, divide by number of screens */
	max-width: calc((480px / 4) - 4px);
	width: calc((100vw / 4) - 4px);
	margin: 0;
	padding: 0.5em 0;
	text-align: center;
	background-color: #ffffff;
	color: #888888;
	transition: 0.3s;
}

/* hover effect for nav menu options */
nav > a:hover {
	background-color: #eeeeee;
}

/* .active class indicates current screen within nav menu */
nav > a.active {
	background-color: #ffffff;
	color: #0099ff;
}

/* nav menu icon label */
nav > a > p {
	font-size: 0.75em;
	margin: 0.5em 0 0;
}

/* can add CSS for other elements, classes, or IDs */

This CSS styles certain elements, classes, and IDs within your web app. However, you can modify some of this CSS if desired.

You'll typically want to add CSS to style other HTML elements in your web app, in order to produce the desired layout and appearance for your app's user interface.

JS

You can use this starter code for your JS file named script.js:

var particle = new Particle();
var myDevice = "0000"; // Photon device ID
var myToken = "0000"; // Photon access token

// functions that hide all screens & then show a specific screen
// these functions also update navigation menu to highlight active screen
function showScreen1() {
  $(".screen").hide();
  $("#screen1").show();
  $(".menu").removeClass("active");
  $(".menu").eq(0).addClass("active"); // eq(0) = 1st menu item
}

function showScreen2() {
  $(".screen").hide();
  $("#screen2").show();
  $(".menu").removeClass("active");
  $(".menu").eq(1).addClass("active"); // eq(1) = 2nd menu item
}

function showScreen3() {
  $(".screen").hide();
  $("#screen3").show();
  $(".menu").removeClass("active");
  $(".menu").eq(2).addClass("active"); // eq(2) = 3rd menu item
}

function showScreen4() {
  $(".screen").hide();
  $("#screen4").show();
  $(".menu").removeClass("active");
  $(".menu").eq(3).addClass("active"); // eq(3) = 4th menu item
}

function showNotification() {
  // choose temporary or persistent notification
  // only use one - comment out unused option

  // temporary - closes automatically after delay (can also close manually)
  $("#notification").slideDown("fast").delay(5000).slideUp();

  // persistent - must close manually
  //$("#notification").slideDown("fast");
}

// Add other JS for your smart device web app

IMPORTANT: You must modify this JS code to insert your actual Photon device ID and access token. Otherwise, your web app will not work properly.

This JS creates a new Particle() object and assigns it to a global variable named particle. This object has built-in methods (functions) that can be used to interact with your Photon device through Particle Cloud.

This JS also declares global variables to store your Photon device ID and access token. You must modify these lines to list your actual device ID and access token, which you will need to get from your team's Particle Build account.

This JS contains functions to show a specific screen in your web app (and also highlight the current screen in the navigation menu). There is also a function to show the notification (if your web app needs to display popup notifications).

Then you'll need to add the other necessary JS for your web app. Because your HTML file loaded the Particle API JS library and jQuery JS library, you can include Particle statements and jQuery statements within your JS code.

Review the reference section on Particle Cloud to learn how to make your web app JS interact with your Photon device app.

Resources

If you want to learn more about web development or need a quick reference, consult these tutorials and references from W3Schools:

  • HTML

  • CSS

  • JavaScript

  • jQuery

Accelerometer

The triple-axis accelerometer included in your Photon kit can be used to detect changes in motion or orientation in 3 dimensions (x, y, z).

CHANGE IN MOTION (TAP)

Like the name implies, an accelerometer works by detecting acceleration – a change in motion. If a device with an accelerometer experiences a change in motion (i.e., speeding up, slowing down, or changing direction), the accelerometer can sense this change and measure the amount of acceleration in each of the 3 dimensions (x, y, z).

For example, fitness trackers use accelerometers to count steps by detecting changes in motion.

Your accelerometer is sensitive enough that it can be used to even tiny changes in motion caused by a nearby tap or bump. For example, if your Photon device is on a table, the accelerometer would be able to detect if you tapped the table with a finger.

ORIENTATION (TILT)

Even if a device with an accelerometer is not moving, the accelerometer can detect the orientation (tilt) of the device by measuring the acceleration due to Earth's gravity, which is a constant downward force acting on all objects. The accelerometer can determine if the object is parallel to the Earth's surface or if it's tilted.

For example, smartphones and tablets use accelerometers to sense the orientation of the device, in order to change the screen's orientation to match.

Your accelerometer can be used to measure the tilt (in degrees) for pitch and roll:

  • Pitch is rotation on the Y-axis, which means an object is tilted up or down.

  • Roll is rotation on the X-axis, which means an object is tilted right or left.

NOTE: An accelerometer cannot measure yaw because Earth's gravity acts in the same direction as the Z-axis, which prevents the accelerometer from measuring rotation on the Z-axis. Instead, a different sensor called a magnetometer (i.e., digital compass) could be used to measure yaw by measuring an object's orientation relative to Earth's magnetic north pole.

How to Connect Accelerometer

The MMA8452Q triple-axis accelerometer in your Photon kit has 6 pins located along its front edge (which determines its orientation for measuring pitch and roll). There are labels for each pin printed on the accelerometer circuit board. However, only 4 of the pins will need to be connected to your Photon.

To connect the accelerometer to your Photon using the breadboard, you will need:

  • Accelerometer (MMA8452Q)

  • 4 jumper wires (use different colors to help identify them)

3.3V MAXIMUM: The accelerometer operates at 3.3V of power. Connect it to the 3.3V pin on your Photon, or connect it to a positive power rail that's connected to the 3.3V pin.

Do NOT connect it to VIN or V-USB because the higher voltage could damage it.

Here are the steps to connect the accelerometer to your Photon using the breadboard:

  1. Insert the six metal pins of the accelerometer into different terminal strip rows on the breadboard. (Different terminal strip rows have different row numbers.)

  2. Plug one end of a jumper wire into the same terminal strip row as the accelerometer's 3.3V pin. Plug the other end of this jumper wire into the 3.3V pin on the Photon circuit board (or to a positive power rail on the breadboard connected to the 3.3V pin).

  3. Plug one end of a second jumper wire into the same terminal strip row as the accelerometer's SDA pin. Plug the other end of this jumper wire into the D0 pin on the Photon circuit board.

  4. Plug one end of a third jumper wire into the same terminal strip row as the accelerometer's SCL pin. Plug the other end of this jumper wire into the D1 pin on the Photon circuit board.

  5. Plug one end of a fourth jumper wire into the same terminal strip row as the accelerometer's GND pin. Plug the other end of this jumper wire into a pin hole connected to GND: either plug it into a negative power rail (which is connected to GND via a different jumper wire), or plug it directly into a GND pin on the Photon circuit board.

Here's a wiring diagram showing a possible way to connect the accelerometer (ignore the wiring for the push button):

Keep in mind that your connection can look different than this example diagram:

  • Your accelerometer pins could be inserted into different row numbers. (The example connects the accelerometer pins to rows 1-6 on the right side of the breadboard).

  • Your accelerometer pins could be inserted into a different column of the breadboard. (The example connects the accelerometer pins into column H of the terminal strip rows).

  • Your accelerometer could connect (through a jumper wire) directly to the 3.3V pin or to a positive power rail on the breadboard that's connected to the 3.3V pin.

  • Your accelerometer could connect (through a jumper wire) either directly to a GND pin or to a negative power rail that's connect to a GND pin. (There are three available GND pins.)

How to Code Accelerometer

The basic steps to control the accelerometer in your app code are:

  1. Include the SparkFun MMA8452Q library and Math library in your app.

  2. Create a MMA8452Q object assigned to a global variable called accel.

  3. Use the accel.begin() method to start the accelerometer in the setup() function. If app will detect taps, use the accel.setupTap() method to initialize the tap settings.

  4. Use custom functions to detect taps or measure tilt angles using the accelerometer.

Include Libraries

Your Photon app must include a code library that will allow you to control the accelerometer (which is an MMA8452Q accelerometer). You'll also add a Math library that will be used to calculate tilt angles.

  1. In Particle Build, click on the Libraries icon to open the Libraries menu panel.

  2. Type mma8452q into the search field. Select the result called: SparkFunMMA8452Q

  3. Click the button to "Include in Project"

  4. Select the title of your Photon app, and then click the "Confirm" button

Particle Build will automatically insert this #include statement at the beginning of your app code:

In addition, you will include a Math library that has additional mathematical functions and constants, which will be needed to calculate tilt angles. (The Math library is available in Particle Build, but it won't show up in a search of the community libraries.)

You need to manually add this #include statement (on new line after other #include statement):

Global Variable

You need to create a new object using the MMA8452Q class in the included SparkFun MMA8452Q library, and assign this object to a global variable named accel.

Add this code statement before the setup() function:

Start Accelerometer in Setup

The accel.begin() method is used to start the accelerometer, which will initialize its settings. (You do not need to set any pin modes for the accelerometer.)

Add this code statement within the setup() function to start the accelerometer:

The accel.begin() method can accept two parameters inside its parentheses (in this order):

  1. The scale range, which determines the range and precision of the acceleration detection. The options for the scale are: SCALE_2G, SCALE_4G, or SCALE_8G. A higher scale can detect larger changes in acceleration but is less precise. A lower scale is more precise. For your app, using SCALE_2G is the probably the best choice because it will be the most precise.

  2. The output data range (ODR), which determines how frequently it outputs new measurements. The ODR is set in Hz (number of times per second). The options for the ODR are: ODR_1, ODR_6, ODR_12, ODR_50, ODR_100, ODR_200, ODR_400, or ODR_800. A higher ODR is faster (more frequent), while a lower ODR is slower (less frequent). If your device is being powered by a battery, a lower ODR is more energy-efficient. For your app, using ODR_50 is probably a good choice.

Alternatively, you can exclude the parameters from the accel.begin() statement. If you do this, the accelerometer will default to using SCALE_2G and ODR_800.

SET UP TAP DETECTION

If your app will use the accelerometer to detect taps, then use the accel.setupTap() method to initialize the settings for tap detection.

If detecting taps, add this code within the setup() function (after the accel.begin() statement):

If your app will NOT be detecting taps, then this code can be excluded.

Add Function to Check Tilt

If your app will use the accelerometer to detect an object's tilt, you'll add a custom function named checkTilt() that measures tilt angles for pitch and roll using the accelerometer.

Add this checkTilt() function after the loop() function:

You'll need to add code within the function to do something with the values of pitch and roll, which indicate the direction(s) and angle(s) that the accelerometer is tilted.

Pitch is rotation on the Y-axis, which means the object is rotated up or down:

  • If the accelerometer is tilted up, the pitch will be a positive angle (between 1° to 180°).

  • If the accelerometer is tilted down, the pitch will be a negative angle (between -1° to -180°).

Roll is rotation on the X-axis, which means the object is rotated to the right or left:

  • If the accelerometer is tilted right, the roll will be a positive angle (between 1° to 180°).

  • If the accelerometer is tilted left, the roll will be a negative angle (between -1° to -180°).

When the accelerometer is perfectly level, the pitch and roll will both be equal to 0 (zero).

To check the tilt, call this function within the loop() function (or within another custom function):

Add Function to Check Tap

If your app will use the accelerometer to detect taps, you'll add a custom function named checkTap() that detects taps using the accelerometer.

Add this checkTap() function after the loop() function:

The accel.readTap() method is used to detect a tap. The method returns a value of 0 when no tap is detected. When a tap is detected, the method returns a non-zero value. The if statement condition checks whether a non-zero value was returned (indicating a tap was detected).

You'll need to add code within the curly braces of the ifstatement to do something when a tap is detected. Optionally, you can add code within the curly braces of the else statement to do something when no tap is detected.

To check for a tap, call this function within the loop() function (or within another custom function):

Accelerometer

Photon Pin

3.3V

3.3V

SDA

D0 (SDA)

SCL

D1 (SCL)

I2

(none)

I1

(none)

GND

GND

// This #include statement was automatically added by the Particle IDE.
#include <SparkFunMMA8452Q.h>
#include <math.h>
MMA8452Q accel;
accel.begin(SCALE_2G, ODR_50);
    // set up tap detection
    byte threshold = 1; // 2 * 0.063g = 0.063g
    byte pulseTimeLimit = 255; // 0.625 * 255 = 159ms (max)
    byte pulseLatency = 64; // 1.25 * 64 = 640ms
    accel.setupTap(threshold, threshold, threshold, pulseTimeLimit, pulseLatency);
void checkTilt() {
    if (accel.available() == true) { 
        accel.read();
        float aX = float(accel.x);
        float aY = float(accel.y);
        float aZ = float(accel.z);
        int pitch = atan2(-aX, aZ) * 180 / M_PI; // rotation on Y axis
        int roll = atan2(-aY, aZ) * 180 / M_PI; // rotation on X axis        
        /*
        If accelerometer is level, pitch and roll will both be 0
        Pitch: Tilted Up = 1 to 180, Tilted Down = -1 to -180
        Roll: Tilted Right = 1 to 180, Tilted Left = -1 to -180
        */     
        // add code to do something with pitch and roll
        
    }
}
checkTilt();
void checkTap() {
    if (accel.readTap() != 0) {
        // add code to do something if tap detected

    }
    else {
        // optional: add code to something if no tap detected
        
    }
}
checkTap();
Accelerometer
Orientation of 3 Axes on Accelerometer
Libraries Icon
Orientation of 3 Axes on Accelerometer

Micro OLED Display

The Micro OLED display included in your Photon kit is a monochrome (single-color) screen that is 64 pixels in width and 48 pixels in height. It can be used to display text, simple graphics, or a combination. You can even create simple animations by drawing an object, leaving it on the screen briefly, erasing it, and repeating these steps with the object drawn at a new position on the screen.

Micro OLED Display

Although the Micro OLED display is small, it can be useful for displaying information. Since the display is so small, design your information to be "glanceable" – a person should be able to very quickly and easily read and understand the information.

How to Connect Micro OLED

To connect the Micro OLED display to your Photon using the breadboard, you will need:

  • Micro OLED display

  • 7 jumper wires (use different colors to help identify them)

The Micro OLED has pins located along the top edge of the display. There are labels for each pin printed on the underside of the Micro OLED circuit board.

If the pins along the top edge were numbered left to right as 1-8, the wiring connections would be:

OLED Pin

Photon Pin

Pin 1 – CS

A2

Pin 2 – RST

D6

Pin 3 – D/C

D5

Pin 4 – SDO

(None)

Pin 5 – SCK

A3

Pin 6 – SDI

A5

Pin 7 – 3V3

3.3V

Pin 8 – GND

GND

3.3V MAXIMUM: The Micro OLED display operates at 3.3V of power. Connect it to the 3.3V pin on your Photon, or connect it to a positive power rail that's connected to the 3.3V pin.

Do NOT connect it to VIN or V-USB because the higher voltage could damage the display.

TWIN PINS: Analog pins A2, A3, A4, and A5 are each represented by two pins on the Photon board. The duplicate pins are labeled as: SS/A2, SCK/A3, MISO/A4, MOSI/A5.

However, the Micro OLED has to connect to only one A2 pin – not both. The same goes for connecting the Micro OLED to the A3 and A5 pins.

The only limitation is that once you connect the Micro OLED, you will not be able to have a different part (such as an LED, etc.) connected to the other A2, A3, or A5 pins.

Here are the steps to connect the Micro OLED to your Photon using the breadboard:

  1. Insert the 8 pins of the Micro OLED into different terminal strip rows on the breadboard. (Different terminal strip rows have different row numbers.)

  2. Plug one end of a jumper wire into the same terminal strip row as the first OLED pin (CS). Plug the other end of this jumper wire into its corresponding pin on the Photon circuit board.

  3. Repeat step 2 with the other jumper wires until each OLED pin is connected to its correct Photon pin. NOTE: The fourth OLED pin (SDO) will not be connected to anything.

Here's a wiring diagram showing a possible way to connect a servo motor (ignore the wiring for the three push buttons):

Keep in mind that your connection can look different than this example diagram:

  • Your Micro OLED pins could be inserted into different row numbers on the breadboard. (The example connects the OLED pins to rows 1-8 on the right side of the breadboard.)

  • Your Micro OLED pins could be inserted into a different column of the breadboard. (The example connects the OLED pins into column F of the terminal strip rows.)

  • Your Micro OLED could connect (through jumper wires) to the other A2, A3, and A5 pins located on the lower left side of the Photon circuit board.

  • Your Micro OLED 3V3 pin could connect (through a jumper wire) either directly to the 3.3V pin or to a positive power rail connected to the 3.3V pin.

  • Your Micro OLED GND pin could connect (through a jumper wire) either directly to a GND pin or to a negative power rail connected to a GND pin. (There are three available GND pins.)

How to Code Micro OLED

The basic steps to control the Micro OLED display in your app code are:

  1. Include the SparkFun Micro OLED library in your app.

  2. Define the I/O pin numbers for certain Micro OLED pins.

  3. Create a MicroOLED object assigned to a global variable called oled.

  4. Use the oled.begin() method to start the display in the setup() function.

  5. Use various oled methods to display text or simple graphics on the screen.

Include Library

Your Photon app must include a code library that will allow you to control the Micro OLED display.

Libraries Icon
  1. In Particle Build, click on the Libraries icon to open the Libraries menu panel.

  2. Type oled into the search field. Select the result called: SparkFunMicroOLED

  3. Click the button to "Include in Project"

  4. Select the title of your Photon app, and then click the "Confirm" button

Particle Build will automatically insert this #include statement at the beginning of your app code:

// This #include statement was automatically added by the Particle IDE.
#include <SparkFunMicroOLED.h>

Global Variables

You need to define the I/O pin numbers for certain Micro OLED pins. This is similar to declaring global variables (except defined values are not allowed to change).

You will also need to create an object using the MicroOLED class in the included library, and assign this object to a global variable.

Add this code before the setup() function:

#define PIN_OLED_RST D6
#define PIN_OLED_DC  D5
#define PIN_OLED_CS  A2
MicroOLED oled(MODE_SPI, PIN_OLED_RST, PIN_OLED_DC, PIN_OLED_CS);

The first three lines of code define the I/O pin numbers for three specific OLED pins.

The fourth line of code creates a new object using the MicroOLED class, and assigns the object to a global variable named oled.

Start OLED in Setup

The oled.begin() method is used to start the Micro OLED display.

Add this code statement within the setup() function to start the OLED display:

oled.begin();

The oled.begin() method will initialize the settings (including pin modes) for the Micro OLED and turn it on.

Display Text

Displaying text on the Micro OLED screen requires a sequence of five steps:

  1. Clear the screen using the oled.clear() method.

  2. Set the font type using the oled.setFontType() method.

  3. Set the cursor position using the oled.setCursor() method.

  4. Print text to the screen using the oled.print() and/or oled.println() methods.

  5. Display the printed text using the oled.display() method.

For example:

oled.clear(PAGE);
oled.setFontType(0);
oled.setCursor(0,0);
oled.println("Hello");
oled.display();

CREATE CUSTOM FUNCTION: Rather than listing all your OLED code statements within the loop() function, it may be better to create a custom function that contains all the code to display your text or graphics. Then call the custom function within the loop() function.

1. CLEAR SCREEN

To clear the screen before adding text or graphics:

oled.clear(PAGE);

2. SET FONT TYPE

The SparkFun Micro OLED library includes 4 available font types (numbered 0-3), which differ in font size and in which characters can be displayed:

Font Type

Font Size

Characters Allowed

Used For

0

5×7 pixels (10 columns by 6 rows)

any

General

1

8×16 pixels (6 columns by 3 rows)

any character on keyboard

General

2

10×16 pixels (5 columns by 3 rows)

only numbers and period

Numbers

3

12×48 pixels (5 columns by 1 row)

only numbers and colon

Numbers or Time

By default, the Micro OLED will be set to font type 0 by the oled.begin() method.

You can use the oled.setFontType() method to set the font type by including the font type number within the parentheses:

oled.setFontType(0);

You can use a mix of different font types by setting a new font type before printing a new line of text.

For example:

oled.setFontType(0);
oled.println("Hello");
oled.setFontType(1);
oled.println("World");

3. SET CURSOR POSITION

The cursor position represents the starting position for printing text to the screen. The cursor can be set to any (x,y) position on the screen. The OLED screen is 64 pixels wide by 48 pixels tall:

  • The x positions are numbered left to right as 0-63

  • The y positions are numbered top to bottom as 0-47

For example, to have your text start at the top-left corner of the screen:

oled.setCursor(0,0);

As you print text to the screen, the OLED display will automatically move the cursor position, so the next text printed to the screen will start at the next available screen position.

However, if desired, you can adjust the text layout by setting a new cursor position before printing a line of text, so the new text will start at a specific position on the screen.

For example:

oled.setCursor(20,10);
oled.println("Hello");
oled.setCursor(20,30);
oled.println("World");

4. PRINT TEXT

The oled.print() and oled.println() methods can be used to print text (or variable values) to the screen. Text that is longer than the screen column width will automatically wrap to the next line.

Print Text Within Quotation Marks

To print text directly, include the text inside the method's parentheses by listing the text within double quotation marks:

oled.println("Hello");

Print Value of Variable

To print the value stored in a variable, include the variable name inside the method's parentheses.:

oled.println(myName);

In this case, myName is a variable name (presumably a person's name). Change this to the name of your variable, which could store a text string or number.

Print Decimal Value to Certain Number of Digits

If a variable stores a decimal number (data type is float or double), you have the option of indicating how many digits after the decimal point to show when printing the variable's value:

oled.println(roomTemp, 1);

In this case, roomTemp is a variable name that stores a decimal value (presumably a temperature sensor measurement). Its value will be displayed to 1 digit after the decimal point. So if the actual variable value were 70.1584275, it would be printed on the screen as: 70.2 (the last digit is automatically rounded up if necessary).

PRINT vs. PRINTLN

There are two different print methods that can display text on the Micro OLED screen:

  • oled.print() will print text to the screen, but the cursor will remain on the same line. The next text printed to the screen will start where the last text ended.

  • oled.println() will print text to the screen, and then move the cursor to the start of a new line. The next text printed to the screen will start on the new line.

The oled.print() command is useful for combining text and variable values on the same line.

For example, if you had a variable named hour that stored the hour of the current time and another variable named minutes that stored the minutes, you could combine these together on the screen:

oled.print("Time ");
oled.print(hour);
oled.print(":");
oled.println(minutes);

Notice that the last code statement used the oled.println() method to move the cursor to a new line for any text that might be printed after the time.

Print Blank Line

To add a blank line, just use the oled.println() method without anything inside its parentheses:

oled.println();

5. DISPLAY SCREEN

Any text or graphics will NOT be shown until the OLED is instructed to display the screen:

oled.display();

GLANCEABLE: Because the Micro OLED display is small, be sure your text and graphics will be "glanceable" – a person should be able to quickly and easily understand the information.

Display Graphics

Displaying simple graphics on the Micro OLED screen requires a sequence of three steps:

  1. Clear the screen using the oled.clear() method.

  2. Draw graphics (dots, lines, rectangles, circles) on the screen using various methods.

  3. Display the graphics using the oled.display() method.

For example:

oled.clear(PAGE);
oled.circleFill(32, 24, 10);
oled.display();

Rather than listing all these code statements within the loop() function, you may want to create a custom function that contains all the code to display your graphics. Then you can call this custom function within the loop() function.

The following drawing methods are available:

  • oled.pixel() can be used to draw a dot

  • oled.line(), oled.lineH(), and oled.lineV() can be used to draw a line

  • oled.rect() and oled.rectFill() can be used to draw a rectangle

  • oled.circle() and oled.circleFill() can be used to draw a circle

Each drawing method requires parameters for the (x, y) pixel position of a point (or two points if drawing a line). The OLED screen is 64 pixels wide by 48 pixels tall:

  • The x pixel positions are numbered left to right as 0-63

  • The y pixel positions are numbered top to bottom as 0-47

DRAW DOT

The oled.pixel() method can be used to draw a dot (pixel) at a specific point:

oled.pixel(x, y);

For example, to draw a dot at the center of the screen:

oled.pixel(32, 24);

DRAW LINE

The oled.line() method can be used to draw a line from one point (x1, y1) to another point (x2, y2):

oled.line(x1, y1, x2, y2);

For example, to draw a line from the top-left corner (0,0) to the bottom-right corner (63, 47):

oled.line(0, 0, 63, 47);

DRAW HORIZONTAL LINE

The oled.lineH() method can be used to draw a horizontal line that starts from a specific point (representing the left end of the line) and has a specified width:

oled.lineH(x, y, width);

For example, to draw a horizontal line that starts at (12, 24) and has a width of 40 pixels:

oled.lineH(12, 24, 40);

DRAW VERTICAL LINE

The oled.lineV() method can be used to draw a vertical line that starts from a specific point (representing the top end of the line) and has a specified height:

oled.lineV(x, y, height);

For example, to draw a vertical line that starts at (32, 9) and has a height of 30 pixels:

oled.lineH(32, 9, 30);

DRAW OUTLINE OF RECTANGLE

The oled.rect() method can be used to draw an outline of a rectangle that starts from a specific point (representing the top-left corner of the rectangle) and has a specified width and height:

oled.rect(x, y, width, height);

For example, to draw an outline of a rectangle with its top-left corner at (12, 14) with a width of 40 pixels and a height of 20 pixels:

oled.rect(12, 14, 40, 20);

DRAW FILLED RECTANGLE

The oled.rectFill() method can be used to draw a solid (filled) rectangle that starts from a specific point (representing the top-left corner of the rectangle) and has a specified width and height:

oled.rectFill(x, y, width, height);

For example, to draw a filled rectangle with its top-left corner at (12, 14) with a width of 40 pixels and a height of 20 pixels:

oled.rectFill(12, 14, 40, 20);

DRAW OUTLINE OF CIRCLE

The oled.circle() method can be used to draw an outline of a circle that has its center at specific point and has a specified radius:

oled.circle(x, y, radius);

For example, to draw an outline of a circle with its center at (32, 24) and a radius of 20 pixels:

oled.circle(32, 24, 20);

DRAW FILLED CIRCLE

The oled.circleFill() method can be used to draw a solid (filled) circle that has its center at specific point and has a specified radius:

oled.circleFill(x, y, radius);

For example, to draw a filled circle with its center at (32, 24) and a radius of 20 pixels:

oled.circleFill(32, 24, 20);

DRAW WITH BLACK (ERASING)

By default, all the drawing methods will draw using "white" pixels (which are actually light blue on your Micro OLED screen). However, you can modify each method to draw using black pixels instead, which represents erasing.

Any of the drawing methods can be modified to draw using black pixels by adding BLACK, NORM as the last two parameters inside the method's parentheses.

For example, to draw a black dot:

oled.pixel(x, y, BLACK, NORM);

For example, to draw a black line:

oled.line(x1, y1, x2, y2, BLACK, NORM);

For example, to draw solid (filled) black circle:

oled.circleFill(x, y, radius, BLACK, NORM);

The black pixels will only be visible if drawn on top of a white shape, so the black pixels are erasing white pixels.

For example, this code draws a white filled circle with its center at (32, 24) and a radius of 20 pixels, and then draws a black filled circle that also has its center at (32, 24) but with a radius of 10 pixels:

oled.circleFill(32, 24, 20);
oled.circleFill(32, 24, 10, BLACK, NORM);

By drawing the black circle after the white circle, the black circle will erase part of the white circle.

You can also create more complex patterns by drawing a series of white and black shapes, such as:

oled.circleFill(32, 24, 20);
oled.circleFill(32, 24, 15, BLACK, NORM);
oled.circleFill(32, 24, 10);
oled.circleFill(32, 24, 5, BLACK, NORM);

This example code draws 4 filled circles that have the same center point but a different radius:

  1. First, a white filled circle with a radius of 20 pixels is drawn.

  2. Then, a black filled circle with a radius of 15 pixels erases part of the white circle.

  3. Then, a new white filled circle with a radius of 10 pixels is drawn that fills part of the black circle.

  4. Finally, a new black filled circle with a radius of 5 pixels erases part of the second white circle.

The overall pattern ends up looking like a "target" symbol:

Drawing with Sequence of White and Black Pixels

SIMPLE ANIMATIONS

You can also create simple animations by drawing something (with white pixels), leaving it on the screen briefly, erasing it (with black pixels), and then changing its position on the screen. A for loop can be used to repeat the "animation" for a certain number of times.

For example, here is code for a simple animation that makes a circle "bounce" back and forth on the screen. The code inside each for loop draws and displays a white filled circle, leaves the circle on the screen for a brief delay(), and then erases the circle (by drawing and displaying a black filled circle of the same size at the same position).

void bouncingCircle() {
    oled.clear(PAGE);  
    // move circle from left to right
    for (int x = 10; x < 54; x++) {
        oled.circleFill(x, 24, 10);
        oled.display();
        delay(20);
        oled.circleFill(x, 24, 10, BLACK, NORM);
        oled.display();
    }
    // move circle from right to left
    for (int x = 53; x > 9; x--) {
        oled.circleFill(x, 24, 10);
        oled.display();
        delay(20);
        oled.circleFill(x, 24, 10, BLACK, NORM);
        oled.display();
    }
}

The first for loop increases the x-position of the circle's center from 10 to 53, which slowly moves the circle across the screen from left to right. The second for loop decreases the x-position of the circle's center from 53 to 10, which moves the circle from the right back to the left.

Display Text + Graphics

You can also combine text and graphics on the OLED screen at the same time. For example:

oled.clear(PAGE);
oled.setFontType(0);
oled.setCursor(18,0);
oled.println("Hello");
oled.circleFill(32, 24, 10);
oled.setCursor(18,41);
oled.println("World");
oled.display();

The Micro OLED display is only 64 pixels in width by 48 pixels in height. Use this limited screen space effectively by designing your text and graphics to be "glanceable" – a person should be able to very quickly and easily read and understand the information.

ASCII character