Hacking the new ITEAD Studio - Sonoff S31

Last month I received an e-mail from ITEAD Studios on their new 16A Sonoff S31 US standard smart socket with energy monitoring feature. Of course that was just one of those “got-to-have” things, so I order a couple. I had also read that it may be a little difficult to hack; flashing it is the same as any other Sonoff products but breaking into it and hooking it up is a little more difficult.

The Sonoff S31 has a compact design so that two can be plug into a single wall receptacle. The 4MB flash allows for OTA programming and the 16 amp relay can carry a heaver load. Although the Chipsea Cse7766 energy monitoring chip is a neat feather on the eWeLink app. After flashing the S31 for the Blynk app the functionality of the Cse7766 becomes useless… unless someone can figure out all the formulas. With the S31s compact design, 4MB flash, 16A relay, and cost of only $17.00… about $2.00 more than the Sonoff S20 made it a much better option.

Below are instructions on hacking the Sonoff S31 and two versions firmware. Either version can be flashed on the Sonoff S31. For the Sonoff S20 only the non-OTA version should be used. Because the S31 is a little difficult to open up, solder pins and reassemble for each time you want to flash it, the OTA version seems like a more practical way to go. I didn’t try the OTA version on the S20 so I don’t know if it will work or not.

The Blynk app is set up with a vertical button in switch mode on “V1” and an LED widget on “V10” that I used to make sure the buttons and relay were all synchronized during testing.

Note: The Sonoff S31 only comes in U.S standard at this time.


Sonoff S31 - OTA verson

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

  ITEAD Sonoff S31 - OTA version for the Blynk app.
 *************************************************************/

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

#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>

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

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

// Your WiFi credentials.
// Set password to "" for open networks.
const char* ssid     = "ssid";
const char* password = "passward";
char auth[] = "blynk authorization"; // Sonoff S31 "4M(3M 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() {
  Serial.begin(115200);
  Serial.println("Booting");

  Blynk.begin(auth, ssid, password);
  while (Blynk.connect() == false) {
    Serial.println("Connection Failed! Rebooting...");
    delay(5000);
    ESP.restart();
  }

  // ============ OTA =============
  ArduinoOTA.onStart([]() {
    Serial.println("Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  // ============ OTA end =============

  pinMode(buttonPin, INPUT);  // on/off button
  pinMode(relayPin, OUTPUT);  // relay
  pinMode(ledPin, OUTPUT);    // led
  digitalWrite(ledPin, LOW);  // always on
}

void loop() {
  ArduinoOTA.handle();
  Blynk.run();
  pushButton();
  ledStatus();

}

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();
}

Sonoff S31 and S20 - Non-OTA version

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

  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>

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

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

//char auth[] = "blynk authorization"; // Sonoff S31 "4M(3M SPIFFS)"
char auth[] = "blynk authorization"; // 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() {
  Serial.begin(115200);
  delay(10);

  Blynk.begin(auth, ssid, password);
  while (Blynk.connect() == false) {
    //Wait until connected
    //Serial.print("x");
  }

  pinMode(buttonPin, INPUT);  // on/off button
  pinMode(relayPin, OUTPUT);  // relay
  pinMode(ledPin, OUTPUT);    // led
  digitalWrite(ledPin, LOW);  // always on
} // end - setup()

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

}

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()
14 Likes

Excellent!! Thanks for sharing this project. Hopefully I will be able to source an Australian version of the Sonoff S31 soon and have a play :face_with_raised_eyebrow:
Regards

Wow , Nice project and thanks for sharing with community :wink:

must try, just ordered some…

now you need a bulb…sonoff B1

https://www.igorkromin.net/index.php/2017/10/08/hacking-the-sonoff-b1-wifi-led-bulb-to-run-custom-firmware/

could be cool to control it with blynk rgb

There’s a solution to every problem… I am sure it could be done…

Just got a S20 EU v1.3

uploading the standard sketch, uncommented serialprint

I can successful program it with the settings in your picture

But when itst booting , there is no flashing leds or connecting to my wifi, and I have used correct wifi settings.

the console only shows

tail 8
chksum 0xef
csum 0xef

any ideas what could be wrong

got it solved…

apparently the newer Sonoffs use a different flash chip (PN25F08B) and it is then recommended to use these 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

Had to flash it a few times before it worked

Glad you fixed it.
If you’re having to flash the device multiple times then it’s often a good idea to reduce the upload speed.

Although it makes no difference in this case, there is no reason to have the SPIFFS set to 512K. It just uses-up half of your available memory for no reason.
What this is doing is telling the Arduino IDE to partition the available memory on the Sonoff so that half of it is available for your program, and half of it is allocated as SPIFFS for storing data that isn’t lost when your Sonoff is rebooted. As the sketch doesn’t write any data to this SPIFFS partition, this is totally wasted space.
The better option is to choose to have the smallest possible amount of space allocated to SPIFFS (normally 64K), or to edit the Boards file to allow 100% of the available space to be used for your program and zero for SPIFFS.

As I said, it doesn’t make any difference with the standard code, but it would be an issue if you were wanting to do OTA (which is VERY handy, as you can change your code without having to rip the S20 apart every time). The way that OTA works is that a copy of the new code is uploaded to memory alongside the existing code, before the old code is replaced. This means that if your new code is roughly the same size as your old code then at least 50% of the memory needs to be available to temporarily store the OTA image. This isn’t likely to be the case if you’ve already used-up 50% of the Sonoff memory by setting it aside for SPIFFS that isn’t being used.

Pete.

1 Like

thx for this explanation, learning alot :slight_smile:

1 Like

Also meant to add that I like to use the Ticker library to do a bit more with the LED on the S20 and Sonoff Basic.
Ticker is a non-blocking routine that can be used to make the LED flash at different rates to tell you different things, without interfering with your other code.

I use Blynk in a very different way to most people. My devices do t run any Blynk specific code. They just connect to WiFi and then use MQTT to pas data and commands back and forth to my Rasperberry Pi, which runs software called Node-Red that then integrates with Blynk, Amazon Alexa etc.

So in my scenario, the S20 does two things when it starts-up. It connects to Wi-Fi then it connects to the MQTT server. I use two different LED flashing sequences to tell me what it’s doing. If it keeps flashing quickly then I know it’s not connected to my Wi-Fi successfully. If it’s flashing slowly then it’s trying to connect to my MQTT server. If it’s not flashing at all then it’s successfully connected and ready to go.

I’ve never tried using the Ticker library with conventional Blynk code - as I said, this isn’t what I do - but it could conceivably be added into here:

Blynk.begin(auth, ssid, password);
  while (Blynk.connect() == false) {
    //Wait until connected
    //Serial.print("x");
  }

to give some visual feedback about what’s happening without having to rip the Sonoff apart, connect-up your FTDI and view the serial output of little ‘x’s being printed across the screen.

Pete.

To the best of my knowledge, the S31 is only available in the U.S. version and has a 4MB flash and the Chipsea Cse7766 energy monitoring chip. The Cse7766 is most likely the reason for the 4MB flash. I believe all the others without the Cse7766 chip including the S20 only have a 1MB flash.

@steelgoose… It’s been a while and I just got the same socket. Was wondering if you found a way to read energy consumption from it ?

2 Likes

Espurna and Tasmota apparently both support reading the Cse7766 chip but I’m only looking for a library or separate Cse7766 code to integrate with my own Arduino sketches. Does anyone know where to find such?

Older topic :wink:

We tend to work with Blynk stuff here… but perhaps you can try Google? Lots of info, data sheets, etc.

For example, that chip uses a serial protocol, and possible PWM, so no need for a library, just work out some code to read and interpret as others appear to have… or at least investigated…

Yeah, I’m hoping to forgo all that work myself if someone else has already figured it out and is willing to share it. I think the Tasmota code is my best bet but seeing as Pavel asked, I was curious if there was further development.

Home Assistant User Interface

An excellent video on S31 I think it should be posted here

Here is a simple solution for Blynk to read Energy consumption from S31
Because Tasmota is sending two MQTT messages with all the Variables needed

MQT: tele/SNF-Washer/STATE
MQT: tele/SNF-Washer/SENSOR

We separate the Variables using Node-Red,then we redirect them to Blynk

and Here is the Result

2 Likes

Because I am not a programmer and I have a limited knowledge about MQTT and Node-Red today I must say learning MQTT is a must . (MQTT 5 is coming soon)
I also found many interesting topics in this forum that was not easy for me to understand in the past.

Blynk - MQTT Bridge - Use Blynk app for non-Blynk devices

we can achieve same result to read Energy consumption from S31 using this technique.

1 Like