Programming the Sonoff TH16 version 2.1

An Eccentric Anomaly: Ed Davies's Blog

Sonoff make a range of Wi-Fi-connected devices for various monitoring and switching applications based around ESP8266 processors. As I wasn't happy with the performance of the thermostat in the fridge in the house I'm renting I got a few of their TH16 switches with the idea of using one of them to switch the fridge on and off without freezing the food in the salad compartment.

A few sources indicate that supplying power to these devices while flashing programs in them is tricky. tl;dr, I found that a surprisingly high voltage, about 3.9 volts or higher, was needed to load software in the version 2.1 devices I received. I'll explain the process by which I got to this conclusion in some detail as there may be some useful hints for others along the way.

The Sonoff devices are designed to be controlled via an app and their website which is not something I'm entirely happy with but Sonoff, to their credit, are pretty open about the workings of these things which allows people to reprogram them easily enough.

Two sources I found particularly useful were a blog post by Xose Pérez and the pages of this Github Wiki.

However, the units I got were version 2.1 which is slightly different from those described above. Externally they appear the same but the board layout has changed a bit.

Here's the device with its case off. Click for larger views.

Note the absence of the fuse which was present on the boards Xose Pérez looked at. In the UK, with fused plugs, this isn't a big deal but might be a bit concerning elsewhere. Anywhere, some care would need to be taken if one of these boxes is incorporated in fixed wiring.

A slightly closer look at the internal serial port obviously set up to allow users to reprogram the devices while hidden from “normal” users who don't open the box:

The version label says:

Sonoff TH10/16
Ver 2.1

and the J2 pins are labelled, top to bottom:


EXP-LOG is a bit intriguing but the rest are self explanatory. Here's the bottom of the board, EXP-LOG disappears under the writing for R20. It looks like it connects to R20 and a pin on the top of the microcontroller but it's hard to be sure.

Connecting one up to the mains and, carefully, checking the voltages on Vcc and E-TX verified that they were indeed around 3.3 volts. I added 6-pin headers to each of the boards because that's what I had to hand, with the extra pin hanging off into the board cutout next to the Vcc pad.

I re-jumpered my USB BUB II (originally set for 5 V Vcc and 3.3 V data lines for a couple of JeeNodes I played with a few years ago) for 3.3 V Vcc and tried with that. I wasn't at all surprised that this didn't work so immediately tried powering it from my bench power supply.

Ignore the Arduino NG that happens to be bolted to the prototyping board (though it will make a small cameo appearance later).

An advantage of using the power supply to power the Sonoff is that it could be switched on and off easily without disturbing the rather rickety jumper wiring. For each attempt at communication it's necessary to set the Sonoff back into programming mode by turning off the power, holding down its push button and turning it on. Even plugging in a USB connector can be awkward with one hand if the angle is difficult.

Again, it didn't work but there were signs of communication. With the serial monitor in the Arduino IDE I got intelligible text from the device. Weirdly, it decoded when I set the IDE to either of 74880 baud or 38400 baud - still haven't worked that one out.

Any attempt to send commands to the device resulted in an error: “A fatal error occurred: Timed out waiting for packet header”.

I wondered if, in resolding the jumpers on that USB BUB II I'd damaged something so it wasn't doing output anymore. With that Arduino NG to hand it was fairly easy to write a little sketch for it which logged edges on one of its GPIO pins to its serial output and see that, indeed, the USB BUB was outputting data changes of some sort.

I'd set the current limit on the power supply at around 500 mA and, as you can see in the picture, the actual draw was a lot less than this: about 36 mA. It was a bit higher, around 70 mA, while the button was held down. I didn't imagine that 500 mA was really a likely draw but I did wonder if somehow the current limit was preventing short spikes of power being drawn so I wound the limit up to 2 A.

Indeed, things worked a tiny bit better. IIRC, the Arduino IDE was identifying the device occasionally. This supported the notion that the power supply was, indeed, the problem.

On the assumption that the problem was the Sonoff taking short spikes of high current I decided to add a capacitor. Because the wiring setup was already messy enough and I wanted to get the capacitor reasonably close to the device it would be supplying I made up a bit of strip board to adapt the output of the USB BUB to the Sonoff's serial port.

The first thing out of the junk bin was a 10 μF 6.3 V electrolytic. That didn't help. Sleeping on it, I wondered if that was surprising and maybe a proper decoupling capacitor (with lower effective series resistance/inductance) might be more useful so I added one of those (labelled “104” - is that 10 nF?) in parallel.

Nope, that didn't help either.

Testing using the Arduino IDE was rather clumsy, what with recompilation of a dummy sketch for each attempt. Also, it was possible that there was some problem with the IDE on my system such that communication was messing up even though the hardware was mostly working OK.

The Arduino IDE uses esptool under the covers somehow to talk to ESP32s and ESP8266s. I'd previously used a version of that mindlessly following a script to reflash my VAir monitors with updated firmware so I at least had a vague understanding of how to use it. Consequently I installed the version in the Ubuntu repositories:

$ apt show esptool
Package: esptool
Version: 2.5.1+dfsg-3
Priority: extra
Section: universe/electronics
Origin: Ubuntu
Maintainer: Ubuntu Developers <>
Original-Maintainer: Milan Kupcevic <>
Installed-Size: 200 kB
Depends: python3, python3-serial, python3-pyaes, python3-ecdsa
Download-Size: 48.9 kB
APT-Manual-Installed: yes
APT-Sources: disco/universe amd64 Packages
Description: create and flash firmware files to ESP8266 and ESP32 chips
 Communicate with the ROM bootloader in Espressif ESP8266 and ESP32 chips to
 fash firmware files, create firmware images or read OTP ROM or flash memory
 content such is manufacturer or device IDs.

Looking at the man page, the simplest command it seemed to have was read_mac which reads the Wi-Fi MAC address of the device. Trying that:

$ esptool --port /dev/ttyUSB0 read_mac v2.5.1
Serial port /dev/ttyUSB0
Detecting chip type... ESP8266

A fatal error occurred: Timed out waiting for packet header

Well, that was at least consistent with what the Arduino IDE was showing and indicated that communication of some sort was happening.

More on a hunch than anything I started gently turning up the voltage of the power supply. Around 3.75 volts it started sometimes doing:

$ esptool --port /dev/ttyUSB0 read_mac v2.5.1
Serial port /dev/ttyUSB0
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
MAC: cc:50:e3:22:cb:67
Enabling default SPI flash mode...

A fatal error occurred: Timed out waiting for packet header

…so it was at least getting a bit further, if only on about 1 in 5 attempts.

Another click of the voltage knob to 3.89 V got:

$ esptool --port /dev/ttyUSB0 read_mac v2.5.1
Serial port /dev/ttyUSB0
Detecting chip type... ESP8266
Chip is ESP8266EX
Features: WiFi
MAC: cc:50:e3:22:cb:67
Enabling default SPI flash mode...
MAC: cc:50:e3:22:cb:67
Hard resetting via RTS pin...

…about half the time.

At 3.95 volts it started working most of the time, though even at that voltage there were occasional misses. On another board I have to go up to 4.22 volts to get it to work reasonably reliably.

At these higher voltages it's possible to program the boards OK with the Arduino IDE most of the time. About 1 time in 4 the programming operation fails but it usually works OK on a retry.

I don't know why this high voltage is needed. Perhaps there's a protection component in the Vcc line to the serial port which drops the voltage a bit at the relatively high currents taken by the microprocessor. Perhaps it's even intended to take 5 V though, as mentioned above, it has 3.3 volts on it in normal operation.

Whatever, I can now program these devices and am no longer throwing away tomatoes which have gone mushy through being frozen and thawed.