I've been gradually building out a workshop in a small room in my basement. However, there's only one light switch, one light, and one outlet in the entire room, and the outlet is controlled by the light switch! That means flipping the switch turns everything off, but I want to keep the air filter and clock powered even when I'm not present. Solution: IoT! With the Particle Cloud, it's all dirt simple and really took very little time to set up.
DisclaimerI am not going to cover wiring of the A/C outlets as I am far from being electrically certified to do it. DO THIS AT YOUR OWN RISK. THERE IS A RISK OF FIRE, PROPERTY LOSS, PERSONAL HARM, DEATH, OR WORSE!
The ProblemThe room in question is the "utility room" of the house. It's somewhat small and houses the blower and furnace for the home HVAC. That means all the ductwork in the house runs into and out of this room. With only a single light socket in the ceiling, the lighting is very poor since it gets blocked by the ductwork. Due to this, the room has largely gone unused -- until I decided I wanted a small shop for my new woodworking hobby. Woodworking requires a lot of light to see things like light pencil marks and marking gauge lines.
The Solution Part 1 - Ceiling SocketI started with the most obvious, yet hardest "zone" -- the ceiling light socket. For this one, I had to convert the light socket to the standard outlet receptacle, which wasn't difficult. Three of the four ceiling lights I installed were within reach of this new outlet. The hard part was of this zone was wiring up 2x2 outlets (4 outlets in 2 "gangs" into a 4-gang electrical box and switched using the SainSmart 4-relay board and Spark Core (re-used from an old project). The relay and Spark Core occupied the other 2 gangs of the 4-gang box. Once constructed, I plugged the relay box into the outlet that was the former light socket. The other plug on the new outlet is used by the USB power supply for the Spark Core.
Aside from the mains wiring to the relays, the relay inputs are connected to the Photon with simple jumper cables. The jumpers are wired as below. Since I only have 3 lights, D1 is not in use in my case.
- Relay GND -> Photon GND
- Relay IN1 -> Photon D1
- Relay IN2 -> Photon D2
- Relay IN3 -> Photon D3
- Relay IN4 -> Photon D4
- Relay VCC -> Photon VIN
// Limit ourselves to 3 relays since we only have 3 lights
int maxRelay = 3;
// Turn off all relays
STARTUP({
for(int d=2; d<6; d++) {
pinMode(d, OUTPUT);
digitalWrite(d, HIGH);
}
});
// Handler function to listen for cloud publishes
void subHandler(const char *event, const char *data) {
String d = String(data);
// If the * key was pressed, turn everything on
if(d.equals("*")) {
for(int i=1; i<=maxRelay+1; i++)
digitalWrite(i, LOW);
return;
// If the # key was pressed, turn everything off
} else if(d.equals("#")) {
for(int i=1; i<=maxRelay+1; i++)
digitalWrite(i, HIGH);
return;
}
// Numeric key presses
// We cheat a little here and simply keep track of the
// state of the relays by toggling them with !digitalRead(pin).
// Quick and dirty -- just like my workshop!
// If the 3 key was pressed ...
if(d.equals("3"))
digitalWrite(D2, !digitalRead(D2));
// If the 4 key was pressed ...
else if(d.equals("4"))
digitalWrite(D3, !digitalRead(D3));
// If the 5 key was pressed ...
else if(d.equals("5"))
digitalWrite(D4, !digitalRead(D4));
}
// Setup function
void setup() {
// Turn off all the relays (again just to be sure)
for(int d=2; d<6; d++) {
pinMode(d, OUTPUT);
digitalWrite(d, HIGH);
}
// Subscribe to cloud publishes for "some-event"
Particle.subscribe("some-event", subHandler, MY_DEVICES);
}
// Loop function
void loop() {
// Nothing to do here
}
The Solution Part 2 - Wall OutletThere was one ceiling light that was not within reach of the ceiling outlet and relay box, so this one was plugged into a power strip (that was plugged into the wall outlet). I also have a tree lamp between my two benches (glorified folding tables) for closer and better spot lighting. I used the ControlEverything 2-relay board powered by a Photon to switch these two lights. This one was much easier for a couple of reasons -- there were only 2 relays instead of 4, and there were no jumpers or any other extra wiring needed since it's all contained on one board!
// Include the NCDRelay library to control the relays
#include "NCD2Relay.h"
NCD2Relay relay;
// Handler function to listen for cloud publishes
void subHandler(const char *event, const char *data) {
String d = String(data);
// If the * key was pressed, turn everything on
if(d.equals("*")) {
relay.turnOnAllRelays();
return;
// If the # key was pressed, turn everything off
} else if(d.equals("#")) {
relay.turnOffAllRelays();
return;
}
// Numeric key presses
// This is similar to the way the relay board is used
// in the code above. It simply toggles the relay.
// The library used here keeps track of the state for us.
// If the 1 key was pressed ...
if(d.equals("1"))
relay.toggleRelay(1);
// If the 2 key was pressed ...
else if(d.equals("2"))
relay.toggleRelay(2);
}
// Setup function
void setup() {
// Initialize the relay board
relay.setAddress(0, 0, 0);
// Subscribe to cloud publishes for "some-event"
Particle.subscribe("some-event", subHandler, MY_DEVICES);
}
// Loop function
void loop() {
// Nothing to do here
}
The Solution Part 3 - Keypad SwitchI could have easily decided to control all lights on all relays with a single button -- on or off. However, I wanted to control them individually (you know, to save a negligible amount of electricity if I didn't need them all on). In my case, keys 1 through 5 on the keypad map to the 5 lights. The * turns on all lights and # turns off all lights. I eventually plan on using the 0 key as a sort of "night light" mode to turn off all lights except one set (the "3" lights).
"Wiring" the keypad is simple. Orient the Photon on the breadboard so that the USB connector is facing to your right. Plug the keypad directly into the breadboard so that the first pin (the one nearest/under the 1 key) is in the same breadboard column as Photon pin D0. That's it. Done! Easy!
// Include the keypad library from Adafruit
#include "Keypad.h"
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
// Our keypad map -- pretty straightforward
char keys[ROWS][COLS] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'*','0','#'}
};
// Map pins to rows and columns
byte rowPins[ROWS] = {D3, D2, D1, D0}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {D6, D5, D4}; //connect to the column pinouts of the keypad
// Initialize the keypad library with all our mappings from above
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
// The setup function
void setup() {
// Nothing to do here
}
// The loop function
void loop() {
// Making this its own function might be a little
// overkill, but c'mon a "doKey" function -- get it?
// It's personal preference, but I like breaking
// functions out like this. It compartmentalizes the
// code a little better.
doKey();
}
// The doKey (heh) function
void doKey() {
// Grab the key that was pressed (if any)
char key = keypad.getKey();
// If a key was pressed, publish it!
if(key)
doPub(& key);
}
// The doPub function -- publishes key presses to the cloud
void doPub(const char * key) {
// Publish the key press to the "some-event" channel
Particle.publish("some-event", String(key).substring(0,1), 60, PRIVATE);
}
ConclusionI love love LOVE this setup and use it almost every day (woodworking is a great break from technology). It leverages the power of IoT in a simple, intuitive, and useful way to overcome an obstacle that would have been difficult or limiting otherwise. There's also plenty of room to expand the system with many more devices, relays, and lights. I really can't wait to try something like this out when the next gen Particle mesh products are released!
Comments