This project is an ESP8266-based "home automation" server that can control multiple RF-controlled electrical outlets on 315MHz and 434MHz. Using two receivers and two transmitters (one pair for each frequency), it can control most commonly available remote controlled outlets. There are a ton of resources on the web for how to interface with this type of outlet. I simply extended the concept to work with both of the common frequencies and added a web interface.
The basic idea is to use 315 MHz and 434 MHz receivers to record on/off signals from all the remotes and store enough info in the flash memory on the microcontroller to be able to play those signals back using the corresponding transmitter. The user interface consists of a handful of simple web pages served up by the ESP8266. This interface allows you to specify a name and location for each remote unit. It also allows you control any or all of the units at one time.
Over the years, my wife and I have collected several different RF-controlled outlets for use on indoor and outdoor Christmas decorations. Some of these were 315 MHz and some 434 MHz. A few were inter-operable and/or re-programmable but some were hard-coded to a fixed signal. As a result, we had to juggle several different remotes. (Don't know about you, but if I have N remotes in hand, it will ALWAYS take me N tries to find the one I need!) Last Christmas, I decided to solve this issue by building a universal RF Outlet Remote Control Server. In early 2015 I started collecting the parts I needed. Then I got sidetracked and didn't get back to this project until early November. Whoops! What had been plenty of time suddenly wasn't!
Step 1: What You'll Need
The parts I used were a combination of things I had on hand and suitable items from my favorite vendors. If you want to reproduce this project, you'll end up using a slightly different set of components. That is why this Instructable is a guideline and not step-by-step directions.
ESP8266-12 (Adafruit Huzzah)
315 MHz Receiver (Sparkfun)
315 MHz Transmitter (Sparkfun)
434 MHz Receiver (Sparkfun)
434 MHz Transmitter (Sparkfun)
Project box (SeeedStudio)
Some 90 degree male header (for the programming header on the ESP8266)
Protoboard / Stripboard (Radio Shack Universal Component board)
Breadboard-friendly micro-USB female connector (Adafruit's breakout board)
Four NPN transistors (2N2222 or equivalent)
Two tactile pushbuttons
Drinking straw (The rigid kind used in water bottles)
Assorted rubber grommets (I have a box of assorted sizes I got at Harbor Freight. Very handy)
5V wall-wart with micro-USB male connector (at least 300mA)
Assorted wires & screws
FDTI cable or friend for uploading code to the ESP8266
Step 2: Wiring It Up
The exact layout of your board will probably be different from mine since I used a "Universal Component Board" from Radio Shack. This board was actually a very nice fit for this project since the symmetrical layout of the buses allowed me to put the ESP8266 in the middle and the two receiver/transmitter pairs on either side. You can accomplish the same thing with a stripboard but will need to cut some traces. Also in middle of the board were the micro-USB connector and the two tactile buttons. These breakout the two GPIOs that are used for programming the ESP8266.
The 315 MHz receiver and transmitter are on one side of the ESP8266 and the 434 MHz units are on the other side. Each receiver and transmitter gets their power routed through a transistor so they can be turned off when not in use.
There are barely enough GPIO pins on the ESP8266-12 board to handle the transistors, RF modules and pushbuttons. But "barely enough" is also known as "enough", so press on...
GPIO Pin Assignments
15 - Base of transistor for the 315 MHz Receiver 2 - Data out pin of the 315 MHz Receiver (requires voltage divider) 0 - Tactile pushbutton 4 - Data in pin of the 315 MHz Transmitter 5 - Base of transistor for the 315 MHz Transmitter
13 - Base of transistor for the 434 MHz Receiver 12 - Data out pin of the 434 MHz Receiver (requires voltage divider) 14 - Data in pin of the 434 MHz Transmitter 16 - Base of transistor for the 434 MHz Transmitter RST - Tactile pushbutton
The two receivers have a 5V digital output. Since the ESP is not 5V-tolerant, you have to cut this down to size with a voltage divider to avoid damaging the uC. The two transmitters have digital inputs that are nominally 5V but work fine with 3.3V so they can be driven directly from the GPIO pins.
Adafruit's Huzzah board has two small buttons, one tied to GPIO0 and the other to Reset. You have to press both of these in order to upload new code to the board. Because I find these pushbuttons too small to use comfortably, I added pushbuttons to GPIO0 and the RST button to make life less frustrating. I simply connected a button to each of these pins and the other side of the buttons to GND. Then I positioned the buttons at the end of the circuit board where I could reach them easily.
The ESP8266 Huzzah accepts a range of input voltages on Vbat and feeds it through an on-board 3.3V regulator. Since the RF units accept 5V, I decided to use a 5V wall-wart to provide power to the board. This came in via a micro-USB connector and was routed to the ESP and the RF units. (Careful! - You can't feed 5V to the GPIO pins on the ESP but that is easily addressed with voltage dividers.)
To reduce power consumption and RF interference, I didn't want to leave the RF units on continuously so I controlled power to them using four transistors.
Are The Transistors Necessary?
Maybe not. I couldn't find a datasheet for the RF units that definitively gave a max current draw. According to my measurements I made with my DMM, those boards draw from 8 - 12 mA. This is very close to the limit of what the ESP8266 GPIO pins can source so I elected to turn them on and off with NPN transistors. Could I have gotten away with driving the RF units directly from the ESP? I wasn't certain so I elected to err on the side of caution.
Okay... time to 'fess up. I'm a software guy and am a newbie with hardware. So my circuit design may be completely messed up. To control power to the four RF units, I connected each of them directly to the 5V bus. Then I routed their ground connections through the collector pin of a NPN transistor and connected the emitter of those transistors to ground. When the uC supplies a signal to the base, it allows power to flow through the RF unit, then through the transistor and to ground. Is there a better way to do this? Should I have used PNP transistors? Put the transistors on the 5V side instead of the ground side? Feel free to comment on ways I could have done this part better.
Step 3: Antennae (or Antennas, If You Prefer)
The recommended antenna length for 315 MHz is 24 cm and for 434 MHz it is 17 cm (approximately). I cut some insulated wire to those lengths and put some heat shrink on one end of each. Then I soldered each wire so it was connected to antenna inputs of the the appropriate receiver/transmitter pair.
At first I thought that I would be able to just stuff the two wires in the project box and not worry about how they were routed. That was what I saw in the remote control units I disassembled so I figured it would work for me too. Boy, was I wrong! The transmit range when I did it that was horrible - less than a meter. The receiver range wasn't much better.
A little experimentation led me to realize that the range improved dramatically when the antenna were held straight up. In that configuration, I was able to reach receivers stationed throughout my house and in the front yard. Since I didn't want to have to run to the base station and hold the wires up while I tried to turn lights on and off, I decided I needed some sort of antenna mast.
As a test to make sure it worked as expected, I took a flimsy fast-food drinking straw and ran both antenna wires up through it. Then I taped the straw to the top of the box, using enough tape to make it stand (kinda) vertical. It was ugly but worked as expected.
A straw seemed to work well enough but I wanted something a little sturdier than the flimsy one used in the prototype. While I was out shopping, I saw a box of replacement straws for water bottles. These were much more rigid and just the right length so I grabbed a box of five.
To attach the mast to the box, I drilled a hole in the plastic top and inserted a small rubber grommet. This hole was just slightly too large for the straw but a little bit of heat-shrink tubing made it fit just right. Then I put another grommet at the bottom of the straw to provide friction with the circuit board. A couple of notches in the bottom grommet and the straw to run the antennae through, and everything was golden. The grommets hold the straw in place through friction and the antenna wires had a nice mast to run up.
Unfortunately, the wires wouldn't stand straight up in the mast and had a tendency to droop. Fortunately, I had some smaller grommets that were just the right size to fit *inside* the straw er... mast. These gave the wires just enough friction to keep them taut.
In the pictures, you'll see that the antenna wires look like they are the same length. That is because I used heat shrink to attach two extensions that I uses to pull the wires up through the mast. These aren't electrically connected to the antennae.
Step 4: Software
Software. I love it. Been doing it professionally for over 30 years. Real-time. Flight control. Simulations. Business apps. Scientific apps. I love 'em all. That being said, for my home projects, I spend a lot more of my effort on the hardware than the software. This is a hobby and what I do to unwind after writing software all day. The software for this project could be more complete, more robust and prettier but that isn't how I'm looking to spend my time on a home project.
I hadn't written any HTML in over ten years and wanted to try out HTML5. To avoid the back and forth of writing, compiling and uploading to the ESP8266, I first prototyped all the web pages on my laptop using the SimpleHTTP python module as a server. This gave me very fast turn-around while I knocked the HTML rust off.
From the pictures, you can see that the main page is a list of known devices and buttons to select/deselect and turn them on or off. There are also buttons that take you to pages to define a new device or edit an existing one.
To define a new device, you use the "Record 315" button or the "Record 434" button. Hopefully you know what frequency your unit uses but if not, you just try one and then the other. If you choose the wrong one first, it won't see a signal, so no harm done.
The Development Environment
The code for this project is written in C++ using Arduino libraries and compiled and uploaded using the Arduino command-line interface.
As a C++ developer by day, that is my preferred language at home. I first got into hobbyist-level embedded systems two years ago with the platform that people either love or hate - the Arduino Uno. Like every other professional programmer that has used the Arduino IDE for more than five minutes, I quickly looked for another solution. After trying the available Makefiles and the Eclipse plug-in, I ended up using Kate and a python script to invoke the Arduino command-line interface. That allowed me to ditch their IDE altogether and made me much happier.
Before there is Yet Another Pointless Debate about whether Arduino is a suitable ecosystem to work with, let me point out that there are three very nice things about working with that toolset :
- The wealth of open-source libraries for interfacing with different hardware components
- The ability to integrate non-Arduino boards (like the ESP8266) into their build system
- A hardware abstraction layer that lets you program (more or less) independently of the specific micro-controller you are using.
Yes, I know that a lot of very vocal people out there look on the Arduino ecosystem with disdain and assert that anyone that doesn't program directly to the hardware-specific interface and write every library from scratch is not a Real Programmer. I disagree but since that topic has been beat to death long ago, debates can be sent to /dev/null.
All my initial prototyping was performed on an Arduino Uno connected to my laptop and using Serial to read commands from the keyboard and print results to the screen. This allowed me to focus on the how to read, store & replay the RF commands without getting bogged down by problems with WiFi and the web interface.
*Pro Tip* - From the very start, I wrote the core logic as a set of stand-alone classes completely independent of whatever user interface was being used by the test driver. While I was prototyping, I read commands from the keyboard, parsed them, invoked the proper methods from my library code and displayed results to the screen. When I moved to a web-based interface on the ESP8266, the library slid right in since it has no dependencies on the UI. Configuration parameters like GPIO pin assignments are passed as constructor parameters to the top-level library class. In the main source file (the .ino in Arduino-land), there are a series of #ifdefs that configure these correctly based on the board type I'm compiling for.
When a command is received, the software turns on the appropriate RF hardware (315 Receiver, 315 transmitter, 434 receiver or 434 transmitter) using the transistor tied to each of those units. It waits a small amount of time to ensure that the hardware is powered up and then either sends a command or listens for an incoming command.
None. This is not exposed outside my local network so I got lazy in the interest of spending time with my family. Honestly, if you decide to bust through my firewall and the only thing you can find to do is turn my Christmas lights on and off repeatedly, well... you may not be ready for Anonymous quite yet.
Next holiday season, I may add a MAC whitelist and some rudimentary user credentials. I also thought about adding some logic that locks you out for a while if you try to issue more than N commands in an hour. For now, it is unplugged, so it is fairly secure.
As I mentioned, being able to re-use existing libraries is a huge productivity boost. For this project, there are two libraries in particular that I made use of.
RCSwitch - Arduino libary for remote control outlet switches
This library (http://code.google.com/p/rc-switch/) makes it very simple to interface with the RF receivers and transmitters. I did end up modifying it rather heavily to fit my particular needs but it was a great starting point and showed me the answers I needed to get things working.
ESP8266WebServer - Dead simple web-server
This code from Ivan Grokhotkov is a good starting point for writing a simple webserver.
If I have seen further, it is by standing on the shoulders of giants. -- Isaac Newton
That quote is a bit pretentious for such a mundane project but I think it is important to acknowledge the work of other folks that made writing this software much simpler than it would have been otherwise. Thanks.
Step 5: Lessons Learned and Things to Do
Overall, I am really pretty happy with this project. It did its job quite well this holiday season and gave me an excuse to try out some bits and pieces I'd never played with before. But tinkerers are never fully satisfied and there are still some things that I want to improve or learn how to do better.
- As I mentioned earlier, there are some limitations to the ESP8266 regarding the size of individual files and the number of simultaneous connections. I suspect that these problems may have solutions that are well-known to many of you. I'll want to do more research on that prior to using this board in another project.
- I'm just starting to get into etching my own circuit boards and wonder if an etched board might be less noisy and have a better signal than the proto-board I used. RF is another thing on my list of things to learn more about.
- Speaking of RF, there has to be a better way to route the antennas. Having the antenna mast standing straight up gave me the best signal but isn't aesthetically pleasing.
- I want to spiff up the CSS to make the pages a little less plain.
Thanks for reading to the end. I hope you enjoyed seeing what I have been working on recently.