The ESP8266 control board with Soldered Header Pins

Reprogramming a $30 WiFi Switch with CoogleIOT

Being a little obsessed with home automation, and a guy on a budget, is hard. Turns out smart switches, lights, etc. start to add up really fast and once you start it doesn’t seem like you ever have enough!

One of the first big problems I had when trying to automate my home was the desire to have smart multi-plug/power strip switches. In fact my very first project was a 16 port Raspberry Pi powered smart power strip for my aquaponics and fish systems. Back then, even a modest number of individually controlled smart plugs in a strip cost $60+ dollars each!

This lead to me basically building a bunch of my own smart multi-plug switches using ESP8266 boards flashed with my CoogleIOT (specifically my “coogle-switch” project), variously sized 10A relay modules, and some sort of AC-to-DC transformer circuit that would fit in a 3D printed case.

A ESP8266 powered 2 port smart switch
An example of a 2 port smart-switch with a 3D printed case (hard wired into a pair of sockets not shown in photo)

Today the landscape is pretty dramatically changed. Now you can buy 4-switch smart power strips for under $30 dollars if you hit a good sale. Recently I stumbled across this one in particular, which at the time was on an Amazon lightning sale for only $20 bucks (it’s $30 last time I checked regular price):

Here’s the problem — as more and more companies have come into the scene to make smart devices, more and more security issues have cropped up (even your dishwasher isn’t safe anymore). These devices want you to download some sketchy-looking app to your iPhone and give it your WiFi password… yeah, I love running bot nets too.

So what is a smart home enthusiast on a budget to do? Well as it turns out, a large number of these cheap smart devices are using really standard hardware inside of them (in this case an ESP8266 microprocessor to provide the brains and WiFi connectivity), so all we have to do is figure out a way to re-flash it with something more secure. In my case, I use CoogleIOT as the basis for all my firmwares (and even have a specific firmware to control smart switches), so I wanted to use that.

So how do we hack this smart switch to do our bidding? Well first we need to get one and take it apart. This particular device was an easy disassemble — just a few screws hidden behind the sticker, and a few more under the anti-skid pads. Once inside, we get to check out the guts:

The ESP8266 Control board inside of the Smart Switch
The guts of the Smart Switch, specifically the main brains of the operation

Inside I found an ESP8266 chip (the blue board) soldered to another module that also provided a push-button switch, a few LEDs arranged in a ring, and some power regulation components. We know that the ESP8266 chip runs on 3.3V, and the voltage regulator on the board was an L1117 chip which only works with DC so we can safely assume the transformer that converts the 110V AC input when you plug it in is being converted to some sort of DC voltage before it gets to this control board. The board itself was only attached to the rest of the hardware by a simple 6-pin jumper plug as well. Th relay PCB board contained 4 relays and basically looked like it was the exact same circuitry as your standard 4 relay module board you can buy on e-bay:

A standard DIY 4-relay module board

Since I had a lot of experience building my own smart switches it was able to quickly draw a few educated guesses and conclusions:

  • The hardware was divided into two circuit boards. The thin long circuit board was basically exactly the same as a standard 4-relay module board, with an additional transformer circuit built in to convert the AC voltage from the outlet into what was (likely) 5V DC and also provide that AC voltage to the 4 individual power ports
  • This DC voltage was being fed to the second control board, which contained the brains of the operation. If the DC voltage was 5V coming in then I assumed the L1117 chip brought that down to the 3.3V necessary for the ESP8266 chip on the control board.
  • Since the connection between the two boards was 6 leads, and I knew typically each relay is going to need its own signal wire, I surmised that two of the leads must be 5V DC and the rest were 3.3V signal lines controlled by the ESP8266 to turn each relay on and off

These assumptions were pretty easy to verify with a voltmeter and a few jumper wires.

  • With the smart strip taken apart, plug it in the wall. (WARNING: this means you have potentially life-threatening voltage exposed as live leads and you CAN electrocute yourself if you touch them. We are not responsible if you hurt yourself and you must proceed at your own risk).
  • Using a voltmeter, I started poking around at the 6 contacts connecting the two control boards. Sure enough, I identified the first two leads as DC power (+5V), and the rest didn’t have anything going on.
  • Using a jumper wire, I took the DC power +5V and shorted it against one of the other four leads and the result was that one of the relays activated! I now was certain I was on the right track.

Okay, so now we can unplug the smart switch and deal strictly with the control board that has the ESP8266 on it. Based on my tests, I was pretty certain all the ESP8266 was doing was giving each relay it’s own GPIO pin and turning that pin HIGH when it needed to turn on the outlet in question. That means if I can figure out a way to re-flash the ESP8266 chip it should be relatively easy to make my firmware do the same thing!

But the question is, how do we reflash the firmware?

To answer that first we need to have a decent understanding of the minimum requirements needed when trying to flash an ESP8266. Now days, a lot of ESP8266 development boards out there have made life easy on us developers. NodeMCU boards for example provide built in serial / programming logic and on board voltage regulation. But we need to do without in this case, which means we should treat this particular flashing job just  like if we were trying to flash an ESP8266-01 module.

ESP8266-01
An ESP8266-01 development board

This was one of the very first modules available to makers, and programming it wasn’t very straightforward. To do so you needed to do a few things:

  • Hook up the TX/RX serial leads to a serial port (FTDI Programmer)
  • Hook up 3.3V power, and short it across the CH_PD (enable chip) and RST leads (reset)
  • Short GPIO0 to ground when powering up the chip to enable programming mode

Since I like playing with these ESP8266-01 boards I had actually already CNC’d myself a Jig to program them. Basically it just allowed me to plug an ESP8266-01 into it, provided two buttons two reset/pull GPIO0 to ground for programming, and plug in a FTDI programmer board so I could communicate with it from my computer. Just for kicks, I added an LED to the GPIO2 pin as well so I could flash a simple test “blink” script to make sure everything was really working properly.

Note: My FTDI programmer allows me to choose between 3V and 5V when it comes to providing power. Make sure you use 3V — if you use 5V power with the circuit below you’re going to fry the ESP8266 chip!

Here’s what my schematic is for my programming jig. There are a few different variations of this available online, but this one worked for me just fine:

ESP8266-01 Programming Jig
My ESP8266-01 programming jig schematic

Okay, so now we have a schematic and a way to flash the chip, but how do we flash THIS chip that is sitting on a control board we know nothing about? Well, there are two options in this case. Let’s take a closer look at the board:

The ESP8266 Module
The ESP8266 module on the smart switch control board

It is pretty obvious that the ESP8266 in this case is really just a version of some stand-alone module that just got plugged right into another PCB designed for it and soldered down. That’s great news, because maybe we can find the data sheet that describes how the pins of the surface-mounted ESP8266 chip map to the leads around the edge (more on that later). But more importantly for now, we are hoping that the five pins we need to flash the chip are available in the breakouts:

  • A Ground pin for the module
  • A VCC input (3.3V) for the module
  • GPIO0 so we can bring it to ground to enable programming
  • TX and RX pins so we can transmit the new firmware

Assuming these leads are available as part of the breakouts, we still need to physically connect them to our programming circuit. Here there are a few options:

  • Hope the designer of the circuit provided an easy way to program it (look for unsoldered header blocks, test pads, etc)
  • Create some sort of jig that we can place to connect the breakouts
  • Solder leads directly to the breakouts, and remove them later once we’re done

Of those options, two of them are probably in most cases more trouble than they are worth. Unless you plan on doing more than 5 or 10 of these, you’re really either going to have to solder leads directly or hope the designer provided a programming method (making a jig to do it less than 5 times is a waste of time IMHO)

Looking back at the control board, we’ve got something really promising on the edge:

A close up of an unsoldered header of the ESP8266 control board

Hmm, a 5 pin unsoldered connection — exactly the right number of pins we’d need to program it — and since it’s unsoldered we know it isn’t needed for the standard functions of the board and could be how the ESP was programmed after it was installed into the PCB! Too bad there aren’t any useful labels on the silkscreen (it’s always wonderful when you find the silkscreen labeled “TX” and “RX”), but it’s a start.

Okay, so let’s recap, what do we know and what don’t we know?

  • We know it’s an ESP8266 chip, and very likely some sort of mass-produced module that was just added to the circuit designed for it
  • We know it exposes a lot of leads of the chip as a breakout, and since it’s likely mass-produced it most certainly will include the 5 pins we need to program it (that’d be a stupid mass produced module if you couldn’t program it!)
  • We have a unsoldered 5 lead header on the control board
  • We don’t know how the pins of the ESP8266 chip itself map to the breakouts of the module
  • We don’t know if the 5 pins we need to program it map to the unsoldered header, or in what order

Time for a little investigation work! Since we believe this is just a mass-produced module, it’d be fantastic if we could find a datasheet for it that describes the pinouts and technical details. The first thing you should try is look for any model markings or indication on the chip itself (this one had none), but barring that, ESP8266-dedicated forums on Facebook or the ESP8266 community forum are great places to post pictures like this and get suggestions on the module. After a little digging, I found a candidate that looked like it could be the board I needed based on the form factor of the module –  the WT8266-S1 WiFi Module.

The WT8266-S1 module, looks like the right form factor at least!

Here’s the datasheet for it if you’d like to check it out yourself, but here’s the good bits we needed – the pinout.

Pinout of the WT8266-S1

Okay now we’re getting somewhere! We have a pinout, now we need to pull our voltmeter back out and see which if any of these pins are connected to the unsoldered header we found, and if so what we think they represent (if we assume this module is indeed a WT8266-S1). One by one I tested the resistance between each pin and the header, looking for readings that had little or no resistance to identify connections.

Counting on the header from right to left (rightmost being pin 1):

  1. VCC
  2. IO0
  3. GND
  4. TX
  5. RX

Wow, so either we are absolutely correct that this is an WT8266-S1 module and that this header is exactly the programming port we need, or that’s one heck of a coincidence! There’s really only one way to find out — time to solder header pins on and hook it up to my programming jig!

The ESP8266 control board with Soldered Header Pins
The control board with soldered header pins

Now comes the exciting part — can we actually flash it? Time to wire it up to your programming circuit (or in my case, just stick jumper wires in the appropriate header pins of my ESP8266-01 programming jig I already had):

Hooking up the control board to my ESP8266-01 programming jig
The smart switch control board hooked up to my ESP8266-01 programming jig

From here, we need to get on our computer and start trying to figure out if we can talk to the ESP8266. Because we need to treat this like an ESP8266-01, we’re going to need to make sure before we attempt any communication we first reset the device with GPIO0 pulled to ground. For my jig you can see I have two push buttons (one for GPIO0 to ground, one for reset) I can use.

Rather than trying to jump right to flashing a firmware, let’s see if we can probe out some basic information about the module first. If we can we know we’re on the right track, and it’ll also tell us some important details we are going to need to know anyway (like the size of the flash memory chip). For this, we’re going to use the Espressif Bootloader Utility, esptool.py to query the chip and see if we can get a response:

$ esptool.py --port /dev/cu.usbserial-A90JXYQ7 flash_id
esptool.py v2.3.1
options {
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
Uploading stub...
Running stub...
Stub running...
Manufacturer: 0e
Device: 4015
Detected flash size: 2MB
Hard resetting via RTS pin...

Here I am using the esptool.py utility to get data about the flash chip. In this example /dev/cu.usbserial-A90JXYQ7 is the device my FTDI programmer comes in as on my Macbook, yours will be different depending on device and operating system.

The result: SUCCESS!

As we can see from the output (make sure you pull GPIO0 to ground right before running this command) we were able to successfully connect to the ESP8266 chip and detected the flash size as 2 Megabytes — plenty of space to run a CoogleIOT firmware!

All of this work, and we’re still not done though! We’ve determined we can communicate with the chip and flash new firmware — but now we need to figure out how to actually program the chip to control the various things we want to control. Remember:

  • We determined early on there are four signal wires connecting to four relays, so we are most likely looking for 4 GPIO pins to set HIGH on the ESP8266 to map to each of those relays to turn them on/off
  • The push button on the control board must map somehow to the ESP8266 as well as an input pin
  • The LED ring, based on the original instructions, is controlled by the ESP8266 somehow as well. The instructions state if you hold the button down for a few seconds the LEDs will pulse.
  • The WT8266-S1 module itself has a built in LED that must also map to a GPIO pin

My first attempts to figure out what pins controlled things proved frustrating. Trying to use a voltmeter to trace the connections wasn’t very successful and was very error-prone. I also wasn’t really interested in the push-button or LED ring controls (maybe later). So I personally decided the best thing to do was to just repeatedly flash the new firmware on to the chip, testing each GPIO pin one at a time to see if I could get the relays to turn on and off.

Lucky for you my dear reader, after trying all of the pins one by one in a very slow and annoying process I was able to determine exactly what pins controlled which relays and you can just skip to the good part:

  • GPIO 0 – This might be some sort of control for the LED ring, it was the only pin that affected it at all in my tests
  • GPIO 1 – Nothing / Could be the Push button Input
  • GPIO 2 – Nothing / Could be the Push button Input
  • GPIO 3 – Nothing / Could be the Push button Input
  • GPIO 4 – Controls the on board LED of the ESP module
  • GPIO 5 – Switch 4
  • GPIO 12 – Switch 1
  • GPIO 13 – Nothing / Could be the Push button Input
  • GPIO 14 – Switch 2
  • GPIO 15 – Switch 3

So my CoogleIOT powered firmware can be configured to control 4 switches, using GPIOs 12, 14, 15, and 5. This is done in the coogle-switch code base by editing config.h as follows:

#ifndef COOGLESWITCH_H
#define COOGLESWITCH_H
#define NUM_SWITCHES 4
#define TOPIC_ID "test-power"
#define SWITCH_BASE_TOPIC ""

// List of pins, in order, that we will be switching on/off

static int switches[NUM_SWITCHES] = {
  12, 14, 15, 5
};

#endif

With this new firmware flashed using the same method you’d flash any firmware (Arduino IDE, Eclipse Sloeber, INO, whatever), we should be all set! My firmware using MQTT for communication and this particular code base maps an MQTT topic to a specific pin to turn on and off. So when I publish a ‘1’ to (in this case) the ‘/test-power/switch/1’ topic, it should set GPIO12 to HIGH and turn on my relay — and it did (as did the other relays).

We’re done, since CoogleIOT has built in over-the-air firmware updating we can disconnect our control board, reinstall it in the case and screw everything back together — if we want to do any updates in the future we can just upload a new firmware.

Awesome! We have successfully hacked our cheap WiFI/ESP8266 smart switch and turned it into a high quality and secure smart switch! From here the sky’s the limit. Since I already did all of the hard work for you, you will be able to save yourself a ton of time and just solder a header on and get flashing — but hopefully you enjoyed reading about how to figure out how to do it as well.

In fact, if you are feeling hacky, I’d love someone to do the legwork on figuring out how to control the LED ring and which GPIO pin accepts the push button signal. If you figure it out, share with your fellow makers in the comments!

8 comments

  1. If you want to figure out the rest of this thing hit me up and bring it over to i3detroit. I live basically next door and we’ve been up to some pretty significant IoT things with ESP devices that you might be interested in. I’d love to collaborate on IoT or other electronics stuff if you’ve got projects you might want a hand with.

  2. > If you figure it out, share with your fellow makers in the comments!
    I don’t have one of these to reverse engineer but it looks very simple. Here are my thoughts…

    The LED ring is probably a chain of WS2812’s (also known as Neopixels) — RGB LEDs with a built-in controller that can be daisy-chained and controlled individually but with a single pin (GPIO0 in your case). They’re very cheap and common as they’re mass manufactured and used in art installations and gaming PC lights (similar rings are $2 from ebay). There are many libraries available for the ESP8266 to control them, just google “esp8266 neopixel” and pick one.

    Also, you could find the push button input by holding down the button and testing continuity between GND and the four pins, or by writing a program that sets them to inputs with pullups enabled and displays their states (on the LED ring perhaps). It might be useful to do things such as switching off all the sockets or entering configuration/AP mode.

    Anyway, great project! We should have some kind of database for all these commercial ESP8266-based IoT things, with pin mappings and firmware replacements so anyone can reflash them without having to reverse engineer and do what someone else has already done.

    1. Hmmm… I was completely wrong with the assumption they were WS2812’s. Looking closely at the photos I can see they’re just normal, single-color LEDs arranged in what seems to be a charlieplexing matrix.

      Charlieplexing works by exploiting the fact that they’re polarized and that you can switch any GPIO pin between input and output modes, and is achieved by connecting groups of complementary LEDs between pins. According to Wikipedia, driving eight (up to twelve) LEDs this way would require 4 pins — you found one and labeled four of the other pins “nothing”. Assuming one of these “unused” pins is used for the button, you have 3 pins remaining plus GPIO0. What a coincidence!

      You only have to figure out what’s the button pin (with the continuity trick) and how the LEDs are connected: the easiest way to do this is writing some code that pulls one random pin to 3.3V, another random pin to ground and sets the other two to inputs (without pullup). As the board only has 8 LEDs but there are 12 possible combinations, you may or may not get one to light up. If you do, however, write down the LED’s location and the pin state combination.

      You then build a lookup table with the combinations you annotated and use that in the firmware to map LED states to pin states. If you want to light multiple LEDs at once or adjust brightness, you rapidly cycle through them and the all-LEDs-off state (all pins set to inputs) like you would do with standard multiplexing or software PWM. It’s much harder than just downloading a WS2812 library but it’s fun…

  3. Rather than repeatedly flashing the chip to find out the relay connections, wouldn’t it have been easier to remove the espodule and put 3.3volt on each of the connector pins that normally connect to the I/o pins?

    1. Perhaps, but I was having trouble at the time distinguishing between issues I was having with my firmware uploads and physical hardware issues. So when I finally got everything stabilized, was able to get debugging info over the serial connection, etc. I opted to not touch anything and just use a software approach until I had it all sorted out.

      Coming from a C programming background perhaps I was just comfortable with the constant recompiling workflow 🙂

Comments are closed.