Sonoff S20 remote powerplugs with timer

After Steelgoose’s great guide to program a Sonoff S31/S20 and included sketch, See it here: Hacking the new ITEAD Studio - Sonoff S31

I decided to try it out too, but with intention to have extending features.

  • I wanted to control several plugs in one page
  • be able to set timers

I bought 2 pcs S20 EU versions, and after several errors and googling I found out that it uses a newer flash chip version (PN25F08B) which needs different flash settings.

The pins was not labeled on these devices but its like this picture:

When programming it with arduino, do not have the S20 connected to 230v, its dangerous when its open and you can get electrocuted !!! and it already gets 3v power from the programmer so external power is not needed.

To get the S20 in flash mode, hold the red switch button down while powering it on with the programmer.

Use these arduino flash settings:

  • Generic ESP8266 module
  • Flash Mode: DOUT
  • Flash Frequency: 40MHz
  • CPU Frequency: 80MHz
  • Flash Size: 1M (512K SPIFFS)
  • Debug Port: Disabled
  • Debug Level: None
  • Reset Method: ck
  • Upload Speed: 115200

My sketch is a mix of Steelgoose’s and of a previous relay project I did.

Its kinda messy and someone with more experience could definitely make it more refined, but it works.

It requires a “Realtime clock widget” and “eventor widget” but only once since they are reused for every extra S20 powerplug, as long each plug uses same virtual pins.


the sketch which can be used for each S20 powerplug.

/*************************************************************

  ITEAD Sonoff S31 and S20 for the Blynk app.
 *************************************************************/

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>
#include <TimeLib.h>
#include <WidgetRTC.h>

int buttonPin = 0;              // Sonoff On/Off button
int relayPin = 12;              // Sonoff relay
int ledPin = 13;                // Sonoff green LED - always on
int relayStatus = 0;
int buttonState = LOW;          // variable for reading the pushbutton status
int lastButtonState = HIGH;     // previous state of the button
int relayState = LOW;
int ledState = LOW;

long lastTime = 0;             // the last time the output pin was toggled
long debounce = 200;           // the debounce time, increase if the output flickers


SimpleTimer timer;
WidgetRTC rtc;

char Date[16];
char Time[16];
int manual=0;

long startsecondswd;            // weekday start time in seconds
long stopsecondswd;             // weekday stop  time in seconds
long nowseconds;                // time now in seconds


// V1 is virtualbutton
// v2 test button for timer
// V10 is virtualLed
// V11 is Dateprint
// V12 is wifi signal
// v13 auto-manual
// V14 is virtual time-date picker




// Your WiFi credentials.
// Set password to "" for open networks.
const char* ssid     = "wifi";
const char* password = "password";

//char auth[] = "blynk authorization"; // Sonoff S31 "4M(3M SPIFFS)"
char auth[] = ""; // Sonoff S20 "1M(512k SPIFFS)"

WidgetLED led1(V10); // Widget Relay LED

BLYNK_WRITE(V1) { // Widget relay button
  relayStatus = param.asInt();
  if (relayStatus == 1) {
    relayState = HIGH;
  }
  else {
    relayState = LOW;
  }
} // end - BLYNK_WRITE(V1)


void setup() {
  WiFi.mode(WIFI_STA);
  Serial.begin(115200);
  delay(10);

  Blynk.begin(auth, ssid, password);
  while (Blynk.connect() == false) {
    //Wait until connected
    Serial.print("trying to connect waiting");
  }
  rtc.begin();
  pinMode(buttonPin, INPUT);  // on/off button
  pinMode(relayPin, OUTPUT);  // relay
  pinMode(ledPin, OUTPUT);    // led
  digitalWrite(ledPin, LOW);  // always on
  
  //Setting automaticmode to on(1)
  Blynk.virtualWrite(V13, 1);
  timer.setInterval(100000L, sendWifi);
  timer.setInterval(60000L, syncRelay);
  timer.setInterval(1000,showCurrentTime);
} // end - setup()


BLYNK_WRITE(V13)
{
  if (param.asInt()==1) 
  {
    manual=1;
  } 
  else 
  {
    manual=0;
  }
}



BLYNK_WRITE(V14)//datepicker 
{  
    if (manual==1)
      { 
      
      sprintf(Date, "%02d/%02d/%04d",  day(), month(), year());
      sprintf(Time, "%02d:%02d:%02d", hour(), minute(), second());
    
      TimeInputParam t(param);
      Serial.println(Time);
      Serial.println(Date);
    
      int dayadjustment = -1;  
      if(weekday() == 1){
        dayadjustment =  6; // needed for Sunday, Time library is day 1 and Blynk is day 7
      }
      if(t.isWeekdaySelected(weekday() + dayadjustment)){ //Time library starts week on Sunday, Blynk on Monday
            
      nowseconds = ((hour() * 3600) + (minute() * 60) + second());
      startsecondswd = (t.getStartHour() * 3600) + (t.getStartMinute() * 60);
      Serial.println(startsecondswd);  // used for debugging
      if(nowseconds >= startsecondswd){    
        
        if(nowseconds <= startsecondswd + 90){    // 90s on 60s timer ensures 1 trigger command is sent
          Blynk.virtualWrite(V1, 1);
          // code here to switch the relay ON
        }      
      }
      else
      {
      }
      stopsecondswd = (t.getStopHour() * 3600) + (t.getStopMinute() * 60);
      Serial.println(stopsecondswd);  // used for debugging
      if(nowseconds >= stopsecondswd){
        Blynk.virtualWrite(V1, 0);
        
        if(nowseconds <= stopsecondswd + 90){   // 90s on 60s timer ensures 1 trigger command is sent
          
         Blynk.virtualWrite(V1, 0);
          // code here to switch the relay OFF
        }              
      }
      else{
        if(nowseconds >= startsecondswd){  
          Blynk.virtualWrite(V1, 1);
          
         
        }          
      }
      }
      else
      {
       // nothing to do today, check again in 30 SECONDS time    
      }
      }
}



void pushButton() {
  buttonState = digitalRead(buttonPin);

  if (buttonState == HIGH && lastButtonState == LOW && millis() - lastTime > debounce) {
    if (relayState == HIGH) {
      relayState = LOW;
      Blynk.virtualWrite(V1, 0);
    }
    else {
      relayState = HIGH;
      Blynk.virtualWrite(V1, 1);
    }

    lastTime = millis();
  }

  digitalWrite(relayPin, relayState); // Relay open/close - digital pin 12
  lastButtonState = buttonState;
} //end - pushButton()

void ledStatus() { // Widget LED - relay status
  ledState = digitalRead(relayPin);
  if (ledState == HIGH)
    led1.on();
  else
    led1.off();
} // end - ledStatus()


void syncRelay()
{
  Blynk.syncAll();
  
  Serial.println("sync relay");
}


void showCurrentTime()
{
  String CurrentDate = String(day()) + '-' + monthShortStr(month()) + '-' + year();
  String CurrentTime = String(hour()) + ':' + minute() + ':' + second();
  String formattedDate = CurrentDate + String(" | ") + CurrentTime;
  Blynk.virtualWrite(V11,formattedDate);
}



void sendWifi() 
{
  Blynk.virtualWrite(12, map(WiFi.RSSI(), -105, -40, 0, 100) );
}


void loop() {
  Blynk.run();
  pushButton();
  ledStatus();
  timer.run();

}
1 Like