-- Copyright 2016 jankop@volny.cz, MIT license, http://opensource.org/licenses/MIT _,BoRe=node.bootreason() print("** sonoffrun ",BoRe) rtcmem.write32(0,0) GPIO0 = 3 -- button GPIO12 = 6 -- relay (active high) GPIO13 = 7 -- GREEN LED (active low) t1=250000 t2=t1 ot=0 code="sonoff" mode="APO" chan=6 on ="color: green; border: 3px #fff outset;" off="color: red; border: 3px #fff outset;" noact="color: black; border: 7px #fff outset;" gpio.mode(GPIO0,gpio.INT) gpio.mode(GPIO12,gpio.OUTPUT) gpio.mode(GPIO13,gpio.OUTPUT) function ron() led=0 OnButt=on OffButt=noact rtcmem.write32(1,1) gpio.write(GPIO13,led) gpio.write(GPIO12,rtcmem.read32(1)) end function roff() led=1 OnButt=noact OffButt=off rtcmem.write32(1,0) gpio.write(GPIO13,led) gpio.write(GPIO12,rtcmem.read32(1)) end function WaitIP() wifi.sta.connect() tmr.alarm(1,1000,1, function() if wifi.sta.getip()==nil then print("Wait for Ip...") led=(led<1 and 1 or led>0 and 0) gpio.write(GPIO13,led) tmr.alarm(2,50,0, function() led=(led<1 and 1 or led>0 and 0) gpio.write(GPIO13,led) end) else tmr.stop(1) print("IP is : ",wifi.sta.getip()) end end) end if rtcmem.read32(1)==1 and BoRe~=0 then ron() else roff() end if file.exists("code.inf") then file.open("code.inf","r") pcode=file.readline() pmode=file.readline() pchan=file.readline() file.close() if pcode~=nil then code=string.sub(pcode,1,#pcode-1) end if pmode~=nil then mode=string.sub(pmode,1,#pmode-1) end if pchan~=nil then chan=(string.sub(pchan,1,#pchan-1)) end end if mode=="APO" then wifi.setmode(wifi.SOFTAP) cfg={} cfg.channel=chan --cfg.auth=wifi.WPA_WPA2_PSK cfg.auth=wifi.WPA_PSK cfg.ssid="APO"..node.chipid() cfg.pwd= "esp"..node.chipid() wifi.ap.config(cfg) dhcp_config ={} dhcp_config.start = "192.168.4.2" wifi.ap.dhcp.config(dhcp_config) print(wifi.ap.dhcp.start()) else wifi.setmode(wifi.STATION) WaitIP() end -- start server srv=net.createServer(net.TCP,60) srv:listen(80, function(conn) at=tmr.now() t1=t2 t2=at-ot ot=at if t1<300000 and t2<300000 then return end conn:on("receive", function(client,payload) --send data to client function Send() lenght= #buff buff = 'HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n'.. 'Content-Length: '.. lenght ..'\r\n'.. 'Cache-Control: no-cache\r\n'.. 'Pragma: no-cache\r\n'.. 'Connection: keep-alive\r\n\r\n'..buff client:send(string.sub(buff,1, (#buff > 1460) and 1460 or #buff), function() if #buff>1460 then client:send(string.sub(buff,1461,(#buff > 2920) and 2920 or #buff), function() buff=nil collectgarbage() end) end end) end -- prepare code page for client function SendCode() buff= '\ \ \ \ SONOFF - Factory\
\
\

Sonoff ID:'..node.chipid()..'
\

\

\
' Send() end -- prepare main page for client function SendData() buff= '\ \ \ \ SONOFF - Factory\
\
\

Sonoff ID:'..node.chipid()..'
\ \ \

\
\ node.bootreason: '..BoRe..'
\ node.heap : '..node.heap()..'
' Send() end -- prepare message "FILE NOT FOUND" for client function Send404() buff= '\ \ \ 404\

404 - Page not found


' Send() end -- parser of POST parameters function ParseData() function cgidecode(str) return (str:gsub('+', ' '):gsub("%%(%x%x)", function(xx) return string.char(tonumber(xx, 16)) end)) end function parsecgi(str, keys, ignore_invalid) keyfound = {} for pair in str:gmatch"[^&]+" do key, val = pair:match"([^=]*)=(.*)" if not key then print("1.IQS") end default = keys[key] if default == nil then if not ignore_invalid then print("2.IQS") end else if type(default) == "table" then default[#default+1] = cgidecode(val) elseif keyfound[key] then print("3.IQS") else keyfound[key] = true keys[key] = cgidecode(val) end end end return keys end str=string.match(payload,"POST / HTTP/%d%.%d\r\n.+\r\n\r\n(.+=.+)") keys={count = 5, start = 1, R1ON="", R1OFF="", CODE="", REFRESH="", SUBMIT=""} parsecgi(str, keys, false) str=nil if (passIP==actIP and passPort==actPort) then if keys.R1ON=="ON" then ron() end if keys.R1OFF=="OFF" then roff() end end if keys.SUBMIT=="SUBMIT" then if keys.CODE==code then passIP,passPort=conn:getpeer() elseif keys.CODE==code.."res" then srv:close() rtcmem.write32(0,0) dofile("RESTART!") elseif keys.CODE==code.."set" then srv:close() rtcmem.write32(0,2) dofile("RESTART!") elseif keys.CODE==code.."tel" then srv:close() rtcmem.write32(0,3) dofile("RESTART!") elseif keys.CODE==code.."off" then passIP,passPort=conn:getpeer() roff() elseif keys.CODE==code.."on" then passIP,passPort=conn:getpeer() ron() end end keys=nil end -- serve complet POST request with parameters actIP,actPort=conn:getpeer() if string.find(payload,"POST / HTTP/%d%.%d\r\n.+\r\n\r\n(.+=.+)")~=nil then oldIP=nil ParseData() if passIP==actIP and passPort==actPort then SendData() else SendCode() end -- serve POST request without parameters elseif string.find(payload,"POST / HTTP/%d%.%d\r\n.*Content%-Length:%s*%d+.*\r\n\r\n$")~=nil then DataLenght=tonumber(string.match(payload,"Content%-Length:%s*(%d+)")) oldPayload=payload oldIP=actIP oldPort=actPort -- serve separate POST parameters elseif (#payload==DataLenght) and (oldIP==actIP) and (oldPort==actPort) then payload=oldPayload..payload oldIP=nil ParseData() if (passIP==actIP and passPort==actPort) then SendData() else SendCode() end -- serve GET request elseif string.find(payload,"GET / HTTP/%d%.%d\r\n.+\r\n\r\n$")~=nil then oldIP=nil if (passIP==actIP and passPort==actPort) then SendData() else SendCode() end -- serve error "FILE NOT FOUND" else Send404() end payload=nil end) end) --button control function borz() gpio.trig(GPIO0) timpres=1 tmr.alarm(0,200,1, function() timpres=timpres+1 if timpres==15 then pwm.setup(GPIO13, 3, 500) pwm.start(GPIO13) end if timpres==30 then pwm.setup(GPIO13, 10, 500) pwm.start(GPIO13) end if gpio.read(GPIO0)==0 then return end tmr.stop(0) if timpres<15 then gpio.trig(GPIO0, "down",function() borz() end) if rtcmem.read32(1)==1 then roff() else ron() end elseif timpres<30 then roff() srv:close() rtcmem.write32(0,2)--sonoff SET dofile("RESTART!") else roff() srv:close() rtcmem.write32(0,3)--sonoff TEL dofile("RESTART!") end end) end gpio.trig(GPIO0, "down", function() borz() end) tmr.alarm(3,10000,1, function() if wifi.sta.getip()==nil and mode~="APO" then WaitIP() end if node.heap()<10000 then srv:close() rtcmem.write32(0,0) dofile("RESTART!") end end)