February 1st, 2017

The objective is to add an ITEAD Sonoff WiFi switch with NodeMCU firmware to the list of devices controlled with the home automation software Domoticz. This is the logical conclusion of two previous blogs:

The Michael Andresen (captain-slow.dk) script, sonoff_01.lua, previously uploaded to the switch has to be replaced. Here is the modified version, called sonoff_02.lua.

-- Replacement NodeMCU firmware for ITEA Sonoff -- By Mikey (Michael Andresen) at captain-slow.dk -- URL: http://captain-slow.dk/2016/05/22/replacing-the-itead-sonoff-firmware/ -- Sonoff_02.lua -- Modified to use Sonoff in Domoticz. -- MQTT Client Gateway must be installed in Domoticz Hardware, and -- Publish Topic must be set to "out" which corresponds to Flat -- URL: http://sigmdel.ca/michel/ -- This file does not need to be edited -- user defined parameters are in config.lua ---------------------------------------------------------------- dofile('config.lua') deviceID = 'sonoff_'..DomoticzIdx topicToDomoticz = "domoticz/in" topicFromDomoticz = "domoticz/out" messageToDomoticz = '{ "idx" : %s, "nvalue" : %d }' -- Sonoff connections -- Function GPIO NodeMCU -- Button 0 3 -- Relay 12 6 -- Green LED 13 7 -- Spare (pin 5) 14 5 -- NodeMCU index of pin attached to the relay -- HIGH closes relay, LOW opens relay relayPin = 6 -- NodeMCU index of pin attached to button (with internal pullup enabled) -- Normally open = 0, closed = 1 buttonPin = 3 -- NodeMCU index of pin attached to green LED -- LOW drives LED ON, HIGH drives LED OFF mqttLed = 7 -- Timers -- 0 = WiFi status + mqtt connect -- 1 = MQTT offline -- 2 = Free -- 3 = Free -- 4 = Free -- 5 = MQTT activity -- 6 = Button debounce -- Setup WiFi wifi.setmode(wifi.STATION) wifi.sta.config (SSID, PSK) -- Pin which the relay is connected to gpio.mode(relayPin, gpio.OUTPUT) gpio.write(relayPin, gpio.LOW) -- Connected to switch with internal pullup enabled buttonDebounce = 250 gpio.mode(buttonPin, gpio.INPUT, gpio.PULLUP) -- MQTT led -- LOW drives LED ON, HIGH drives LED OFFp gpio.mode(mqttLed, gpio.OUTPUT) gpio.write(mqttLed, gpio.HIGH) -- Blink the green led to indicate 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 -- Setup and connect MQTT client m = mqtt.Client(deviceID, 180, mqttUser, mqttPass) m:lwt("/lwt", 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 n = 0 else n = 1 end msg = string.format(messageToDomoticz, DomoticzIdx, n) print(topicToDomoticz..msg) m:publish(topicToDomoticz, msg, 0, 0) end -- On publish message receive event m:on("message", function(conn, topic, data) --mqttAct() --print("Received:" .. topic .. ":" .. data) t = cjson.decode(data) --for k,v in pairs(t) do -- print(k,v) --end --print("idx: "..t["idx"]) --print("nvalue: "..t["nvalue"]) if tostring(t["idx"]) == DomoticzIdx then nval = t["nvalue"] if nval == nil then nval = 0 end print(topicFromDomoticz..'{ "idx" : '..DomoticzIdx..', "nvalue" : '..nval..' }') mqttAct() if (nval==1) then print("Turning relay ON") gpio.write(relayPin, gpio.HIGH) elseif (nval==0) then print("Turning realy OFF") gpio.write(relayPin, gpio.LOW) else print("Invalid nvalue: "..nval) end -- do not call mqtt_update, this is from Domoticz - it is updated end end ) -- Subscribe to MQTT function mqtt_sub() mqttAct() m:subscribe(topicFromDomoticz, 0, function(conn) print("MQTT subscribed to ".. topicFromDomoticz) 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)

Here is the configuration script config.lua which is called at the very start of sonoff_02.lua. This file contains the only elements that need to be changed to take care of the local context.

-- User defined parameters SSID = "yourWiFiSSid" PSK = "yourWiFiPassword" mqttBroker = "192.168.1.30" mqttUser = "" mqttPass = "" DomoticzIdx = "12"

The very short Lua script init.lua is automatically executed whenever the ESP8266 is powered up or reset.

dofile('sonoff_02.lua')
All it does is call on the main script.

Initially, do not upload this last script. Instead modify the parameters in config.lua and upload it. Then upload and execute sonoff_02.lua.

michel@hp:~/Documents/test$ nodemcu-uploader upload init.lua michel@hp:~/Documents/test$ nodemcu-uploader upload sonoff_02.lua michel@hp:~/Documents/test$ nodemcu-uploader exec sonoff_02.lua
Test with Domoticz that it can control the relay of the Sonoff and use the tactile switch on the Sonoff to test that the state of the virtual switch in Domoticz is correctly updated as the relay is toggled manually.

When satisfied with the results, upload init.lua. Then cycle the Sonoff power off and on and check that the switch still works correctly.