12/2017

A simple Wi-Fi http server for
Sonoff Basic and Arduino


Sonoff Basic device Sonoff Basic device


//********************** Sonoff Basic ****************************
// HTTP server - controller V1.6 / 2018-03-18 for SONOFF Basic as server
// Copyright 2018 Pavel Janko, www.fancon.cz
// MIT license, http://opensource.org/licenses/MIT
// Wi-Fi Protected Setup with PBC ready,
// mDNS responder for connect by name,
// POST or GET method selector,
// HTTP BASIC authentication,
// supports simply OTA from browser.
//
// Tested with ARDUINO ESP8266 2.4.1, IDE 1.8.5
// Sonoff Basic has 1MB flash memory only !
// For flashing disconnect the AC power! Power Sonoff only from
// the USB to Serial converter for your safety !
// Uploading a new application to the Sonoff cancel original firmware !
// Set Generic ESP8266 or ESP8285 by chip types and 1MB flash memory.
// It can also be a classic esp8266 (with at least 1MB of memory for OTA).
// After flash restart the device.
//
// To connect to an access point, hold down the Sonoff button for about
// three seconds (green LED is lit permanently) and activate WPS
// (Wi-Fi Protected Setup) with PBC (Push Button Configuration) on your
// Access point.
//
// For mDNS install Bonjour to your Windows - https://support.apple.com/bonjour
// or Avahi for your Linux - https://www.avahi.org/
// mDNS name is defined as "sonoff" below here. Just enter http://sonoff.local
// into the browser. But in my case, mDNS is sometimes
// slower than a direct IP address.
//
// For web authentication set #define WWWAUTHENTI true and
// your WWWUSERNAME and WWWPASSWORD below only.
//
// For OTA activation set OTAUSER, OTAPASSWORD and then in operation
// write to browser address row http://sonoff.local/firmware or direct IP address
// and upload your *.bin
// file.
//
//   |---------------|-----------|--------------------|
//   |  Button       | GREEN LED |       Action       |
//   |---------------|-----------|--------------------|
//   |short press    |relay state|change relay state  |
//   |long press > 3s|  change   |wait for WPS from AP|
//   |      --       | flashing  |after restart       |
//   |      --       |short flash|client got page     |
//   |before power on|    --     |flash mode only     |
//   |---------------|-----------|--------------------|
//
#include <Ticker.h>
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>
#define WWWAUTHENTI      false     // Set true for web authentication
#define WWWUSERNAME     "admin"    // Set www user name
#define WWWPASSWORD     "admin"    // Set www user password
#define OTAUSER         "admin"    // Set OTA user
#define OTAPASSWORD     "admin"    // Set OTA password
#define OTAPATH         "/firmware"// Set path for update
#define MDNSNAME        "sonoff"   // Set local mDNS name
#define HTTPMETHOD      "POST"     // Set "GET" or "POST" method
#define BUTTONPIN       0          // GPIO0  button pin
#define RELAYPIN        12         // GPIO12 relay pin
#define LEDPIN          13         // GPIO13 GREEN LED (active low)
#define BUTTONTIME      0.25
#define WIFIDOGTIME     5
#define SERVERPORT      80
#define BUTTONON        "color: green; border: 3px #fff outset;"
#define BUTTONOFF       "color: red; border: 3px #fff outset;"
#define BUTTONNOACT     "color: black; border: 7px #fff outset;"
bool    LedState        = true;    // LED off
bool    RelayState      = false;   // Relay off
bool    ButtonFlag      = false;
bool    WifiDogFlag     = false;
bool    RafHo           = false;
char    ButtonCount     = 0;
String  OnButt          = BUTTONNOACT;
String  OffButt         = BUTTONOFF;
String  HowDelka;
String  buff;
ESP8266WebServer HttpServer(SERVERPORT);
ESP8266HTTPUpdateServer httpUpdater;
Ticker ButtonTick;           // Preparing for periodic button reading
Ticker WifiDogTick;          // preparing for test WiFi connection
//-----------------------------------------------------------------
void setup(void) {
  WiFi.begin();
  /* set ports */
  pinMode(RELAYPIN, OUTPUT);
  pinMode(LEDPIN, OUTPUT);
  pinMode(BUTTONPIN, INPUT);
  RelaySet(RelayState);
  /* wait for WiFi connect */
  while (WiFi.status() != WL_CONNECTED) {
    GetButton();
    delay(250);
    LedSet(!LedState);
  }
  LedSet(true);
  ButtonTick.attach(BUTTONTIME, ButtonFlagSet);
  WifiDogTick.attach(WIFIDOGTIME, WifiDogFlagSet);
  httpUpdater.setup(&HttpServer, OTAPATH, OTAUSER, OTAPASSWORD);
  MDNS.begin(MDNSNAME);
  HttpServer.on("/", HTTP_GET, ModifySendPage);
  HttpServer.on("/", HTTP_POST, ModifySendPage);
  HttpServer.onNotFound(handleNotFound);
  HttpServer.begin();
}
//-----------------------------------------------------------------
void loop(void) {
  HttpServer.handleClient();       // Listen for HTTP requests from clients
  if (ButtonFlag) GetButton();     // Periodic serve button
  if (WifiDogFlag) WifiTest();     // Periodic test WiFi connection
}//-----------------------------------------------------------------
void SendPage() {
  LedSet(!LedState);
  buff  = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n";
  buff += "<html><head>\n";
  buff += "<style type=\"text/css\">\n";
  buff += "html {font-family: sans-serif;color: brown;background:#ffe4c4}\n";
  buff += ".submit {width: 10%; height:5vw; font-size: 100%; font-weight: bold; border-radius: 4vw;}\n";
  buff += "@media (max-width: 1281px) {\n";
  buff += "html {font-size: 3vw; font-family: sans-serif;color: brown;background:#ffe4c4}\n";
  buff += ".submit {width: 40%; height:20vw; font-size: 100%; font-weight: bold; border-radius: 15vw;}}\n";
  buff += "</style>\n";
  buff += "<meta content=\"text/html; charset=utf-8\">\n";
  buff += "<title>SONOFF - Basic</title></head><body>\n";
  buff += "<center>\n";
  buff += "<form action=\"/\" method=\"" + String(HTTPMETHOD) + "\">\n";
  buff += "<h1>Sonoff ID : " + String(ESP.getChipId()) + "<br>\n";
  buff += "<input type=\"submit\" name=\"R1ON\" class=\"submit\" value=\"ON\" style=\"" + OnButt + "\">\n";
  buff += "<input type=\"submit\" name=\"R1OFF\" class=\"submit\" value=\"OFF\" style=\"" + OffButt + "\">\n";
  buff += "</h1></form></center></body></html>\n";
  HttpServer.send(200, "text/html", buff);
  delay(20);
  LedSet(!LedState);
}
/* Send HTTP status 404 Not Found */
void handleNotFound() {
  HttpServer.send(404, "text/plain", "404: Not found");
}
/* Read button on GPIO0*/
void GetButton(void) {
  /* short press butoon to change state of LED */
  if (digitalRead(BUTTONPIN) == false ) ++ButtonCount;
  if (digitalRead(BUTTONPIN) == true && ButtonCount > 1 && ButtonCount < 12 )RelaySet(!RelayState);
  /* long press button - WPS mode */
  if (ButtonCount > 12) {
    bool Before = LedState;
    RelaySet(false);        // Relay OFF
    LedSet(!Before);        // LED change
    ButtonTick.detach();    // Stop Tickers
    WifiDogTick.detach();
    while (!digitalRead(BUTTONPIN))yield();
    delay(100);
    StartWpsWaiting();
  }
  if (digitalRead(BUTTONPIN) == true ) ButtonCount = 0;
  ButtonFlag = false;
}
/* Service Wi-Fi Protected Setup with Push Button Configuration */
void StartWpsWaiting(void) {
  WiFi.persistent(false);
  WiFi.mode(WIFI_STA);
  bool    RafHo = false;
  String  HowDelka = "";
  /* Wait for access point WPS */
  do {
    RafHo = WiFi.beginWPSConfig();
    //Serial.print("*");
    HowDelka = WiFi.SSID();
  }
  while (RafHo == false || HowDelka.length() == 0);
  delay(500);
  ESP.restart();
}
/* change state of relay */
void ModifySendPage(void) {
  if (WWWAUTHENTI == true) {
    /* request for www user/password from client */
    if (!HttpServer.authenticate(WWWUSERNAME, WWWPASSWORD))
      return HttpServer.requestAuthentication();
  }
  if (HttpServer.arg("R1ON") == "ON")RelaySet(true);
  if (HttpServer.arg("R1OFF") == "OFF")RelaySet(false);
  SendPage();
}
/* set relay */
void RelaySet(bool SetRelayState) {
  if (SetRelayState == true) {
    OnButt  = BUTTONON;
    OffButt = BUTTONNOACT;
  }
  if (SetRelayState == false) {
    OnButt = BUTTONNOACT;
    OffButt  = BUTTONOFF;
  }
  RelayState = SetRelayState;
  digitalWrite(RELAYPIN, RelayState);
  LedSet(!SetRelayState);
}
/* set green LED */
void LedSet(bool SetLedState) {
  LedState = SetLedState;     // set green LED
  digitalWrite(LEDPIN, LedState);
}
/* If disconnected WiFi then restart */
void WifiTest(void) {
  if (WiFi.status() != WL_CONNECTED) {
    ESP.restart();
  }
  WifiDogFlag = false;
}
void ButtonFlagSet(void) {
  ButtonFlag = true;
}
void WifiDogFlagSet(void) {
  WifiDogFlag = true;
}

Here is Arduino sketch