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);
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("");
 
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
 
  if (MDNS.begin("esp8266")) {
    Serial.println("MDNS responder started");
  }
 
  server.on("/", handleRoot);
  server.on("/enable", []() {
    turnOn();
    server.send(200, "text/plain", "Relay enabled");
  });
  server.on("/disable", []() {
    turnOff();
    server.send(200, "text/plain", "Relay disabled");
  });
  server.on("/toggle", []() {
    toggleRelay();
    if ( relayOn )
      server.send(200, "text/plain", "Relay enabled");
    else
      server.send(200, "text/plain", "Relay disabled");
  });
 
  server.onNotFound(handleNotFound);
 
  server.begin();
  Serial.println("HTTP server started");
}
 
void loop(void) {
  server.handleClient();
}
 
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!