This post was written by chriswhite.
Last time, I gave an intro to the Photon IoT development board, but didn’t have enough time to get into the details of the project I was making. This week I’ll get into the details.
Despite my outward skepticism about the Internet of Things, I somehow end up as an early adopter for many IoT products. I have the Phillips Hue lights, a Nest thermostat, a Netatmo weather station. Oh, and I had a Lockitron. The Lockitron was (and is, in its upcoming third full revision) an Internet and Bluetooth connected door lock that promised leaving your keys at home. The promise wasn’t really met due to battery life issues (and other problems), but, when it worked, it really was convenient.
After a few incidents leaving my keys in the house and having the Lockitron fail (climbing in the bathroom window is getting harder the older I get), I thought maybe I need to fix something. In true tech loon fashion, my first thought wasn’t, “Get a normal door lock like a rational person”, it was, “Buy another internet connected thing for another door.” The garage door.
However, I wasn’t too keen on getting another marginal device, especially one with a cloud service managed by a garage door company. I gave up on the idea. When the Photon dev kit came along, I started thinking about what it would take to build an internet-enabled garage door opener myself.
It turns out, not much. The basic requirements are relatively simple. You need to be able to activate the garage door switch and you need to be able to detect whether the door is open or closed. Well, you also need something to connect those sensors and switches to the Internet and provide easy access to their status (see Part 1: Zero to IoT in Five Minutes).
For the activation part, you need to emulate a switch. Most garage door openers have a press-fit terminal block available to connect additional wall-switches, like the one in the picture.
To take the place of a switch, you can use a relay or a FET. I chose a relay because I had one handy (from the Arduino Tinkerkit). However, there are plenty of similar options available. Essentially, you need a way to drive an output (the switch) with more current than your processor can deliver. I power my relay with the +5V USB from the Photon and attached the signal pin to a microprocessor digital output to control via software. Note that although the Photon is 3.3V (instead of Arduino’s 5V), this relay switches with a 3.3V input logic level.
To sense door state you have a few options. I went back and forth between optical sensors, proximity sensors, and magnetic sensors before settling on an old standby: magnetic window alarm sensors. These are basically reed switches that open or close depending on their proximity to a permanent magnet. Placed strategically on the garage door (or in my case on the closing mechanism), this will give you an easy status indicator on a digital input.
One sensor will give you a “fully closed/partially open” status. Two sensors (one at each extreme of travel) would give you “fully closed/fully open”.
A simple compact 5V USB phone charger can easily power the Photon, and an additional LED on a digital out can make it easy to see status if you like. Here’s the whole thing wired up:
In a more friendly “Fritzed” view:
Note that I’ve used the Arduino dual-relay module in place of the single relay module in the Fritzed image, simply because I couldn’t find a matching single relay part. The wiring is the same.
With all of that wired up, we can look at the code that runs on the Photon. I recommend not hooking everything up to the garage door at first and just completing the circuit on the bench. You can check the relay closure with a multi-meter continuity setting and the magnetic sensor is easy to open and close by hand.
// Basic internet controlled garage door opener
// This is where your LED is plugged in.
// The other side goes to a resistor connected to GND.
int led = D0;
int relay = D6; // Relay logic pin
int doorDetector = D1; // Reed switch input
int holdTime = 500; // 500ms button press time (relay closed time)
int doorOpen = 0; // Door status variable
// As with Arduino, the Photon has a setup function
// that is called at startup.
void setup() {
pinMode(led,OUTPUT);
pinMode(relay,OUTPUT);
pinMode(doorDetector, INPUT_PULLDOWN);
// Declare function to trigger garage door relay
Spark.function("trigger", triggerRelay);
// Declare status variable to check door open status
Spark.variable("doorOpen", &doorOpen, INT);
}
// Again mirroring the Arduino method,
// this loop function is called repeatedly by the system code
void loop() {
doorOpen = digitalRead(doorDetector);
if (doorOpen == HIGH)
digitalWrite(led, HIGH);
else
digitalWrite(led, LOW);
}
void relayOn() {
digitalWrite(relay, HIGH);
}
void relayOff() {
digitalWrite(relay,LOW);
}
// Function exposed to Photon cloud API to open/close the door.
// Executes a momentary closing of the relay, simulating a button press.
int triggerRelay(String command) {
relayOn();
digitalWrite(led, HIGH);
delay(holdTime);
relayOff();
digitalWrite(led, LOW);
}
As discussed last time, Photon device code is written in Wiring, the same C++ dialect used for Arduino. Since Arduino is new to me, there are a few important parts of a Photon program that I want to highlight.
First, the two main parts of many Arduino programs: setup() and loop(). The setup() function gets called by the system when your program starts. It’s the place where you configure the pins you are using (inputs/outputs, pullup/pulldown, etc.). For Photon, it is also the place where you designate those functions and variables that you want to access from the cloud:
// Declare function to trigger garage door relay
Spark.function("trigger", triggerRelay);
// Declare status variable to check door open status
Spark.variable("doorOpen", &doorOpen, INT);
Here we’ve said we’re going to have a function called triggerRelay() that will be accessible through the cloud API as “trigger”. Similarly, we’ve linked the integer variable doorOpen to a cloud accessible variable called, well, “doorOpen”. We’ll see how to get at those from the Internet in a second.
The loop() function gets called forever by the system, essentially think of it as while (1) { loop(); }. It’s where you should put anything you want to happen forever, like check the status of inputs. Here we’ve used it to update the “doorOpen” variable with the status of the reed switch input.
The remaining portion of the code is the actual door open functionality, triggerRelay(). This is a function called from the cloud API to open or close the garage door:
int triggerRelay(String command) {
relayOn();
digitalWrite(led, HIGH);
delay(holdTime);
relayOff();
digitalWrite(led, LOW);
}
It closes the relay, activates the status LED, waits the desired holdTime (here, .5s), and the opens the relay. To the garage door opener, it looks like someone held down the button for half a second.
Accessing your device from the Internet is possible through a variety of means. I recommend going through Particle.io’s “Getting Started” documentation. I’m going to assume you’ve done that and already have your Photon associated with your account and that it has a token ID.
The easiest way to access your device is through the command line (which requires node.js installed on your system, see here for details). First we can get the list of our devices with “particle list”:
Phonon:~ C$ particle list
garage_project [TOKENID] (Photon) is online
Variables:
doorOpen (int32)
Functions:
int trigger(String args)
This gives us all the devices associated with our account and the endpoints (functions and variables) it provides. (I’ve obscured my Token ID, yours will be a long numeric string).
So, to check on the door open status:
Phonon:~ C$ particle get TOKENID doorOpen
0
This “0” indicates my door is not open. If it had returned “1”, that would indicate the door is open. I moved the magnet near the reed switch and repeating to be sure that the sensor worked properly.
To actually open or close the door:
Phonon:~ C$ particle call TOKENID trigger
When you do this, you should hear the relay close, and if you have a voltmeter attached, it should indicate a closed-circuit. After a half second, you should hear the relay open and the meter should indicate an open-circuit.
That’s it! If you connect everything as described to the real garage door (making sure to place the reed-switch and magnet at the extreme close position so you get a true “door open” indication), you have an internet-accessible garage door with status indication that you built yourself.
I haven’t talked about the other ways to access Photon based projects remotely, from the Web and from your own custom iOS applications. I’ll leave that for next time.