A couple of weeks ago a friend introduced me to a dirt cheap wifi enabled mains switch. I’ve been creating my own wifi switches for a few years now but at $5 it is not worth it anymore for me to spend time adding electronic modules to make one.

The original device comes loaded with a firmware that can be used with a specific piece of software.  Now  I don’t know about you, but I rather run my own stack of software on it because I do have some trust issues, specially when I have no idea who’s behind the software development.


Fortunately there are several tutorials that you can explain everything you need to know to upload a custom firmware. This was the one that I used. TL;DR: solder a 5 pin 0.1in header to access the UART port and use one of those usb->uart converters.



My requirements were pretty simple: A tiny webserver should be up and running  ( connecting to my home network ) exposing two or three endpoints ( enable, disable, status ). This is the result:



#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
const char* ssid = ".....";
const char* password = ".....";
ESP8266WebServer server(80);
const int led = 13;
bool relayOn = false;
void handleRoot() {
  digitalWrite(led, 1);
  server.send(200, "text/plain", "hello from Sonoff\nRelay status:" + ( relayOn ? String("ON") : String("OFF") ) );
  digitalWrite(led, 0);
void handleNotFound() {
  digitalWrite(led, 1);
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  server.send(404, "text/plain", message);
  digitalWrite(led, 0);
void setup(void) {
  pinMode(led, OUTPUT);
  pinMode(12, OUTPUT);
  digitalWrite(led, 0);
  WiFi.begin(ssid, password);
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
  Serial.print("Connected to ");
  Serial.print("IP address: ");
  if (MDNS.begin("esp8266")) {
    Serial.println("MDNS responder started");
  server.on("/", handleRoot);
  server.on("/enable", []() {
    server.send(200, "text/plain", "Relay enabled");
  server.on("/disable", []() {
    server.send(200, "text/plain", "Relay disabled");
  server.on("/toggle", []() {
    if ( relayOn )
      server.send(200, "text/plain", "Relay enabled");
      server.send(200, "text/plain", "Relay disabled");
  Serial.println("HTTP server started");
void loop(void) {
void turnOn() {
  digitalWrite(12, HIGH);
  relayOn = true;
void turnOff() {
  digitalWrite(12, LOW);
  relayOn = false;
void toggleRelay() {
  if ( relayOn ) {
    digitalWrite(12, LOW);
    relayOn = false;
  }  else {
    digitalWrite(12, HIGH);
    relayOn = true;



There’s a GPIO pin that you can use for things like 1wire protocol devices ( e.g. ds18b20 temperature sensor, or a DHT22/11 ). I’m planing to add that to this simple sketch. In the meantime feel free to check out the repository . All of the updated will be there.


PS: Yes, I know the code is ugly, but that was not the point. Feel free to change it and improve it!

The Micropython binaries for ESP8266 got released last week and I decided to give it a try. As an “Hello World” application, I wanted to try the wireless capabilities and control a few relays. Nothing fancy, but I was just for testing purposes.


Without further due, this is the snippet of code that I used to bring a HTTP servers that was capable of reading GET variables and parse the PATH:


import machine
import socket
import ure
RELAYS = [machine.Pin(i, machine.Pin.OUT) for i in (12, 13, 14, 15)]
def getPinStatus():
  return RELAYS
def setPin(pin, value):
  return "PIN %s set to %s" % (pin, value)
def parseURL(url):
  parameters = {}
  path = ure.search("(.*?)(\?|$)", url) 
  while True:
    vars = ure.search("(([a-z0-9]+)=([a-z0-8.]*))&amp;amp;?", url)
    if vars:
      parameters[vars.group(2)] = vars.group(3)
      url = url.replace(vars.group(0), '')
  return path.group(1), parameters
def buildResponse(response):
  return '''HTTP/1.0 200 OK\r\nContent-type: text/html\r\nContent-length: %d\r\n\r\n%s''' % (len(response), response)
addr = socket.getaddrinfo('', 80)[0][-1]
s = socket.socket()
print('listening on', addr)
while True:
    cl, addr = s.accept()
    print('client connected from', addr)
    request = str(cl.recv(1024))
    print("REQUEST: ", request)
    obj = ure.search("GET (.*?) HTTP\/1\.1", request)
    if not obj:
      cl.send(buildResponse("INVALID REQUEST"))
      path, parameters = parseURL(obj.group(1))
      if path.startswith("/getPinStatus"):
        cl.send(buildResponse("RELAY STATUS:\n%s" % "\n".join([str(x.value()) for x in getPinStatus()])))
      elif path.startswith("/setPinStatus"):
        pin = parameters.get("pin", None)
        value= parameters.get("value", None)
        cl.send(buildResponse("SET RELAY:\n%s" % setPin(pin, value)))
        cl.send(buildResponse("UNREGISTERED ACTION\r\nPATH: %s\r\nPARAMETERS: %s" % (path, parameters)))


You can get the gist here


The code will give you two different endpoints:

  • /getPinStatus -> Check if the relays are on or off
  • /setPinStatus -> Enable/disable pins. you need to pass a pin number (0 to 3) and a state (0 to disable, 1 to enable the relay). E.g.

The code is not pretty, and probably full of bugs, but the basic functionality is there.  All you have to do is to connect to a Wifi network ( or create your own access point), add the relays to GPIO 12, 13, 14 and 15 and you’re done. You have plenty of other tutorials to teach you how to connect things to your esp8266.

The code was based on the official example that you can find here


As always, feel free to suggest improvements 🙂



EDIT: Thank you Chris for identifying an issue with the regular expression!

This is going to be a quick one.

Remember ZSUN Wifi Card reader? It seems that there’s a new device that does the same thing. In fact it does look like a clone:




I just bought one of these from a Chinese supplier. It costed $7.5 USD and it does exactly the same. Using NMAP to scan for open ports I get the same results. So it was not surprising when I got access to it using the very same password “zsun1188”.

Screen Shot 2016-04-21 at 20.40.08


In order for you to flash the existing firmware you need to edit /etc/producttype and replace the A50 for SD100.  The rest of the process should be pretty straight forward.


Enjoy your dirt cheap new router 🙂

I was one of the guys that got the Zsun fever 🙂

I’m not going to get into details. For those you can check the Warsaw Hackerspace’s website. Those guys did an awesome job compiling information related to this tiny yet powerful device.

Originally it comes with a custom firmware that provides you with an access point that can be used to share files ( it has a microsd slot ). By flashing OpenWRT it allows you to unleash all it power and use it to several different things (access point, range extender, file server using different protocols, IoT, Tor server,  you name it), but since you can only access it via wifi ( there’s a physical ethernet port that you can use if you don’t mind tearing apart the case and solder an ethernet jack)  it can be very easy to lose access to the devices.

I’ve seen some people talking about a trick using the sd card slot during boot to force a software reset but it didn’t work for me, so I just decided to do something different.


The approach is easy. Create a script  that is loaded on boot and checks for a file on the memory card. If it’s there, then it issues a firstboot command to reset everything. This is similar to the update process of several gadgets and it’s easy to implement.


1º Flash the OpenWRT firmware ( check the hackerspace link )

2º Open the web interface. Enable the SD card automount feature and mount it on /mnt/sda1 (this should be the default). Enable enable SSH.

3º Log on using SSH. Create a file called restore inside /etc/init.d/ and dump the following contents there:


#!/bin/sh /etc/rc.common
# Copyright (C) 2009-2012 OpenWrt.org
start() {
  if [ -f "/mnt/sda1/restore" ]
    echo "y" | /sbin/firstboot
    rm /mnt/sda1/restore
    echo "Rebooting to apply changes"
stop() {
  echo "Stop action not used."
reload() {
  echo "Reload action not used."
shutdown() {
  echo "Shutdown action not used."


4º Save the file and change the permissions to 755 ( chmod 0755 /etc/init.d/restore )

5º Enable the script on boot. To do so execute the following command: /etc/init.d/restore enable

And that’s it. If for any reason you mess up the wireless interface and lose access to the device, all you have to do is create a blank file inside the SD card called restore and the next time you boot the device it will detect this and force the reset.

Warsaw Hackerspace: https://wiki.hackerspace.pl/projects:zsun-wifi-card-reader


A couple of months ago a new development board based on the popular esp8266 was created.

It seems like a compact version of the popular nodemcu board that includes an RGB led and an LDR. It is called esp8266 witty ( you’ll find them for just a couple of dollars on ebay or aliexpress) and the idea was to split the UART interface into a dedicated board that can be attached to the esp8266 whenever you need to program it or access the serial interface to read data (clever design guys).

The board comes with a custom firmware flashed which I honestly didn’t try to explore because I’m used to nodemcu firmware. Connection was established using the ESPlorer at 115200bps. After connecting this is what we can see:

Welcome screen ESPlorer esp8266 witty version

Flashing the nodemcu firmware is straightforward just like any with any nodemcu dev board… keep the flash button pressed while pressing reset and use the esp tool to flash the firmware:

esptool flashing esp8266

And there you go, nodemcu firmware is now running:

nodemcu firmware flashed by esptool.py

On a side note, the baud rate changed from 115200 to 74880. This is an unusual value for it, but if it doesn’t work for you, just play with the values until you find what works for you.

I couldn’t find a lot of documentation regarding this module and how to access the LDR and the RGB led. Fortunately it was very easy to find out.

The esp8266 modules have a single pin with analog reading capabilities ( pin 0 ) and that was it. For the digital pins controlling the led channels all I had to do was a simple for loop to iterate over all the digital pins and find out which ones were triggering the blue, read and green channels. It ended up being pin 6, 7 and 8.

The following lua snippet will output green under good light conditions and red under low light:

-- Output pins:
-- 6: Green
-- 7: Blue
-- 8: Red
-- Input pins:
-- 0: LDR
function clearOutput()
  for i=6,8 do
    gpio.mode(i, gpio.OUTPUT)
    gpio.write(i, gpio.LOW)
tmr.alarm(1, 1000, 1, function()
  -- Output LOW on all channels
  ldr_value = adc.read(0)
  print(string.format("Current LDR value: %d", ldr_value))
   if ldr_value > 600 then
     gpio.write(6, gpio.HIGH)
     gpio.write(8, gpio.LOW)
     gpio.write(6, gpio.LOW)
     gpio.write(8, gpio.HIGH)
end )

Have fun! 🙂

Useful links:
esptool.py – https://github.com/themadinventor/esptool
nodemcu firmware binaries – https://github.com/nodemcu/nodemcu-firmware/releases
ESPlorer – http://esp8266.ru/esplorer/