Replacing the ITEAD Sonoff firmware

About a week ago I received a ITEAD Sonoff, which is a nifty little device, for the surprisingly low price of only $4.85 (currently typing, normal price $6).

sonoff_wifi_wireless_smart_switch_4__1

There are two versions, one with and one without RF, I went for the one without, because I will only be using it over WiFi.

Why the Sonoff?

The Sonoff isn’t the first of its kind on the market, so why this, and not one of the other?

The choice of this all comes down to how much control you want to have over your items, and how much you want others to just take care of it for you. As default the Sonoff comes pre-loaded with firmware, and can be controlled from a smartphone from the app for it. This is pretty much the same deal with other devices on the market, but with the Sonoff you are able to take it a step further.

Inside the Sonoff, there is an ESP8266 hidden, and this takes care of everything, and any one spending just a few minutes on this blog, have most likely found this IC mentioned at least once already. Not only does it have a chip easy to program, ITEAD was also nice enough to break the pins out, needed for flashing it. And this is exactly what I am about to do!

Lets flash!

Before ordering the Sonoff, I had been doing a bit of reading on how to flash it, and found it very confusing, but I ordered it, and hoped it would all make sense when I could actually look at it, sadly, it was just as confusing after getting it. So instead I closed all the pages, and decided to give it a shot myself, and it turned out to be simpler than I thought.

2016-05-22 14.13.54

 

Before doing anything, disconnect the Sonoff from mains.

First thing you need to do, is to solder a header to the 1×5 row of holes.

These go to the TX and RX pins on the ESP8266, and are also used to provide 3v3 and GND to run the circuit.

Then it should look something like on the picture above.

The connection closest to the button at the top, is 3v3, underneth TX, then RX and last GND. The last connection is not one we are going to use for this.

To attach the programmer, first make sure it is set to 3V3, then connect it as following:

Programmer Sonoff (counting from top to bottom)
3V3 1
TX 2 (RX)
RX 3 (TX)
GND 4
5

Then hold the button down on the Sonoff, and attach the programmer to your computer. Holding the button down while applying power to the ESP8266 will bring it into flash mode, which will allow you to put new firmware onto it.

My choice was to put NodeMCU onto it, which went without a hitch.

Pin functions

After having put another firmware onto the ESP8266, we would probably want to be able to control the relay again, and for that we need the pin number.

Function GPIO NodeMCU
Button 0 3
Relay 12 6
Green LED 13 7
Spare (pin 5) 14 5

The LED on the board is actually a red/green bi-color led, but the red side is only connected to the RF module, which in my version isn’t mounted.

My code

After putting NodeMCU on mine, I modified some of my old code to match the pins on the Sonoff. This code will make it connect to a MQTT borker, turn the relay on and off, flash the led on activity, and allow the button on the Sonoff to act as a toggle switch for the relay too.

-- Timers
-- 0 = WiFi status + mqtt connect
-- 1 = MQTT offline
-- 2 = Free
-- 3 = Free
-- 4 = Free
-- 5 = MQTT activity
-- 6 = Button debounce

mqttBroker = "192.168.1.30"
mqttUser = "none"
mqttPass = "none"

deviceID="bugzapper"
roomID="1"

wifi.setmode(wifi.STATION)
wifi.sta.config ("SSID", "PASSKEY")


-- Pin which the relay is connected to
relayPin = 6
gpio.mode(relayPin, gpio.OUTPUT)
gpio.write(relayPin, gpio.LOW)


-- Connected to switch with internal pullup enabled
buttonPin = 3
buttonDebounce = 250
gpio.mode(buttonPin, gpio.INPUT, gpio.PULLUP)


-- MQTT led
mqttLed=7
gpio.mode(mqttLed, gpio.OUTPUT)
gpio.write(mqttLed, gpio.HIGH)

-- Make a short flash with the led on MQTT activity
function mqttAct()
	if (gpio.read(mqttLed) == 1) then gpio.write(mqttLed, gpio.HIGH) end
	gpio.write(mqttLed, gpio.LOW)
	tmr.alarm(5, 50, 0, function() gpio.write(mqttLed, gpio.HIGH) end)
end

m = mqtt.Client("Sonoff-" .. deviceID, 180, mqttUser, mqttPass)
m:lwt("/lwt", "Sonoff " .. deviceID, 0, 0)
m:on("offline", function(con)
	ip = wifi.sta.getip()
	print ("MQTT reconnecting to " .. mqttBroker .. " from " .. ip)
    tmr.alarm(1, 10000, 0, function()
		node.restart();
	end)
end)


-- Pin to toggle the status
buttondebounced = 0
gpio.trig(buttonPin, "down",function (level)
	if (buttondebounced == 0) then
		buttondebounced = 1
		tmr.alarm(6, buttonDebounce, 0, function() buttondebounced = 0; end)
	 
		--Change the state
		if (gpio.read(relayPin) == 1) then
			gpio.write(relayPin, gpio.LOW)
			print("Was on, turning off")
		else
			gpio.write(relayPin, gpio.HIGH)
			print("Was off, turning on")
		end
		
		mqttAct()
		mqtt_update()
	end
end)


-- Update status to MQTT
function mqtt_update()
	if (gpio.read(relayPin) == 0) then
		m:publish("/home/".. roomID .."/" .. deviceID .. "/state","OFF",0,0)
	else
		m:publish("/home/".. roomID .."/" .. deviceID .. "/state","ON",0,0)
	end
end
 
-- On publish message receive event
m:on("message", function(conn, topic, data)
	mqttAct()
    print("Recieved:" .. topic .. ":" .. data)
		if (data=="ON") then
		print("Enabling Output")
		gpio.write(relayPin, gpio.HIGH)
	elseif (data=="OFF") then
		print("Disabling Output")
		gpio.write(relayPin, gpio.LOW)
    else
		print("Invalid command (" .. data .. ")")
    end
	mqtt_update()
end)


-- Subscribe to MQTT
function mqtt_sub()
	mqttAct()
	m:subscribe("/home/".. roomID .."/" .. deviceID,0, function(conn)
		print("MQTT subscribed to /home/".. roomID .."/" .. deviceID)
    end)
end

tmr.alarm(0, 1000, 1, function()
	if wifi.sta.status() == 5 and wifi.sta.getip() ~= nil then	
		tmr.stop(0)
		m:connect(mqttBroker, 1883, 0, function(conn)
			gpio.write(mqttLed, gpio.HIGH)
			print("MQTT connected to:" .. mqttBroker)
			mqtt_sub() -- run the subscription function
		end)
	end
 end)

29 comments

  • hi Mikey

    how to flash new firmware? (which software / bin file). i try esp8266flashloader (win32) and nodecmu lasted version unluck.
    please advise.

    thank you
    prasong p

  • Which tool did you use to flash the ESP? I’ve been trying with one of the windows tools but failled miserably. There are also some parameters that should be chosen and I didn’t really know what they should be. Nice work! Your website looks very neat too 🙂

  • Hello! You try other firmware? Maybe EspEasy from esp8266.nu ?

  • why need to reflash the firmware ?

    • Because I wanted to integrate them into my own home automation system, so instead of having to use multiple systems and rely on them being online, I only need one now.

  • How did you flash the actual code? I’ve managed to use the utility to flash NodeMCU successfully but I can’t figure out how to upload the actual code? I’m so confused!

    Arduino IDE throws an error message because it doesn’t like the — in the 1st line of code.
    “error: expected unqualified-id before ‘–‘ token”

    • You don’t use the Arduino IDE to upload LUA code to NodeMCU, you use LuaUploader

      • Thanks @Mikey.
        I’ve uploaded the code but now when I click list files and then load from ESP I get the following:
        SENT: l = file.list()
        SENT: for k,v in pairs(l) do
        SENT: print(“name:”..k..”, size:”..v)
        SENT: end

        SENT: — Print File Content —
        SENT: filename = ‘Sonoff-MQTT.lua’
        SENT: file.open(filename,’r’)
        SENT: txt = ”
        SENT: repeat
        SENT: line = file.readline()
        SENT: if (line~=nil) then txt = txt .. line end
        SENT: until line == nil
        SENT: file.close()
        SENT: print(txt)

        Does that mean that nothing has happened?

        • It says there is a file named “Sonoff-MQTT.lua” stored on it. If you want it to start it when it boots, you need to call it “init.lua”, but best practice is to make a simple file which counts down 3-5 seconds, then runs the actual script. This is done because it can be very tricky to get it out of a boot loop if it crashes as soon as it tries to run the script.

          • Thanks very much for that. I didn’t know about the “init.lua”. It might be worth updating the article to include this info for noobies such as myself.

            I’ve now created two files on my Sonoff. Sonoff-MQTT.lua and init.lua. The latter has just the following “tmr.alarm(0,5000,1,function() dofile(‘Sonoff-MQTT.lua’) end)”. Is this the correct syntax? If yes, how do I test the results? Do I connect the Sonoff to the mains or is there a safer way to power it without using mains power (just in case lol)?

          • It actually does tell you when NodeMCU is starting up, if you watch the output from it. Because it then says it can’t find init.lua

            My init.lua got a bit more in it

            countdown = 3
            tmr.alarm(0,1000,1,function()
            print(countdown)
            countdown = countdown-1
            if countdown<1 then
            tmr.stop(0)
            countdown = nil
            local s,err
            if file.open("run.lc") then
            file.close()
            s,err = pcall(function() dofile("run.lc") end)
            else
            s,err = pcall(function() dofile("run.lua") end)
            end
            if not s then print(err) end
            end
            end)

            This makes sure the code is non blocking, and also gives a bit response to work with when booting it up.

            I am not sure what you mean if you connect it to mains or not. During flashing the new code to it, you have had it powered up through USB I assume? And powering it through that you can test to see if the relay is activated when you expect it to. Even if it did not do as you expect, it still should not be more dangerous to connect it to mains, you haven't changed anything on the hardware, just the code running on it. Just never have it connected to your computer and mains at the same time!

  • So I’ve basically copied and modified your init.lua as follows:

    countdown = 3
    tmr.alarm(0,1000,1,function()
    print(countdown)
    countdown = countdown-1
    if countdown<1 then
    tmr.stop(0)
    countdown = nil
    local s,err
    if file.open("Sonoff-MQTT.lc") then
    file.close()
    s,err = pcall(function() dofile("Sonoff-MQTT.lc") end)
    else
    s,err = pcall(function() dofile("Sonoff-MQTT.lua") end)
    end
    if not s then print(err) end
    end
    end)

    It's connected to my computer via the USB-to-TTL device and I seem to be able to upload code to it but I'm not convinced that it's actually "saving" anything. Basically, I created the init.lua and Sonoff-MQTT.lua files and uploaded them. I got confirmation in the "output" window showing "SENT: xxxx" but when I cleared the output and cleared the code in the editor then pressed "Load from ESP" I got this:
    SENT: — Print File Content —
    SENT: filename = 'init.lua'
    SENT: file.open(filename,'r')
    SENT: txt = ''
    SENT: repeat
    SENT: line = file.readline()
    SENT: if (line~=nil) then txt = txt .. line end
    SENT: until line == nil
    SENT: file.close()
    SENT: print(txt)

    and nothing happened. Shouldn't it have populated the editor with the content of init.lua saved in the Sonoff?

    Also, I'm having to press-and-hold before while connecting the Sonoff to the USB port otherwise nothing works. I take it this is still required to upload the lua files after flashing NodeMCU right?

    • After having flashed it with NodeMCU you should no longer be needing to hold anything. Holding the button only sets the ESP8266 to go into the mode where you can flash it with new firmware. After NodeMCU has been loaded onto it, it should just be allowed to start normally, then it will take care of storing the LUA script.

  • I don’t know what to do now. Is my Sonoff fried? I can still flash it with the NodeMCU flashing tool you linked to so I think that’s a good sign right?

    It gets to the end and says:

    Note:Program flash success.
    Note:Serial port disconnected.

    There’s also a green tick next to NODEMCU TEAM at the bottom left hand side of the window.

    • Strange things can happen when flashing NodeMCU, try flashing an older version, then the newest again afterwards. Flashing the same version on top of itself have caused strange problems for me before.

      And so far I haven’t managed to kill a ESP8266 chip, so I doubt you have too.

  • So…I tried another firmware “nodemcu_integer_0.9.5_20150318.bin” and this time connecting and attempting to list files returns gibberish

    ??ZtGE Ht?lE
    ?$ZtfE?H??ld
    ?$Z4fD?E??ldK,Z4dd?E??`d,KK)h?$hfp?Ehp?HEMHv???ECh?t4EM??$p?EC4t?hdM$?dhO??lhjI??$vDQR|$`p?I$l??E
    ??dxWXI$l??EG??$xV$,H??hl??EX??,??$pfEK???hfSH?$pfDK???hfREq?pddK??$hdrEM?t$dj?=$h$rDM?t$$j?=$?$pdMH|?$h?<?;?dl?ddMH`??;E
    ??xdLH?l?U
    H?$xdl?0??UGHI$|$lH0??TGE ?|$lEPd?ZtGE H|?lE

    LOL

    What firmware did you use?

  • hola quiero que mi sonoff funciones como pulso seco, sin corriente para poder abrir un porton de garage tipo pulsador quisiera que funcione, es posible???

  • Hello Mikey! Have you tried to recude power consumption of the sonoff switch in the software?

    • Hello, I am not sure what you mean. The power consumption of the sonoff itself, or the device attached to it?

      The sonoff itself draw between 1 and 2 watts with the relay energized. This version of the sonoff can’t measure what the device attached to it draw, for that you need the sonoff pow. I don’t have one of those yet, but I got one coming in the mail. 🙂

  • Hi, I am interested in using the ESP8266 to control mains appliances, but I don’t understand why a smart phone can’t talk directly (via the wifi network, to the ESP8266. Why do I need a MQTT Broker, which I guess would run on a PC or Raspberry Pi.

    • Hello, the ESP8266 can also easily be controlled directly from a smartphone, or anything else being able to connect to a web server.

      To use an ESP8266 directly, you could instead set up a web server on the ESP8266, and have your phone call that. The reason I use MQTT is because it got less overhead than opening a web page, and it also makes it easier for me to work in OpenHAB.

  • Maybe it’s worth mentioning that flashing to NodeMCU requires setting baudrate 115200.

Leave a Reply