├── LICENSE ├── README.md ├── d.lua ├── i.lua └── init.lua /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 NodeUSB 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nodemcu-ide 2 | Browser based Lua IDE for ESP8266 SoC based boards 3 | 4 | ![ide-window](https://cloud.githubusercontent.com/assets/5788310/6428719/91a59ce4-bf79-11e4-9949-1dbce870ff43.png) 5 | 6 | ### Why? 7 | I wrote the IDE while working on sensors for NodeUSB. I was testing 5 different ESP8266 boards at the same time, I do not like to connect to UART RX/TX and ground pins everytime I need to update source code, also, I'd like to use different PCs and Macs to update Lua code. One more reason, if I bring back the temperature sensors from outside the house to upload the new code, it will read the temperature inside the house, which can be 50 degrees celsius higher than outside(Yes! We got -25 this winter in Toronto). 8 | 9 | ### How to get started (NodeUSB users go to step 6) 10 | 1. You need NodeMCU firmware with node.compile() (2015-02-13 and late) 11 | 12 | 2. If you do not have it, download the firmware from: 13 | https://github.com/nodemcu/nodemcu-firmware/tree/master/pre_build 14 | 15 | 3. Flash the ESP8266 using nodemcu-flasher: 16 | https://github.com/nodemcu/nodemcu-flasher 17 | 18 | 4. Upload the init.lua to ESP8266: 19 | https://github.com/NodeUSB/nodemcu-ide/blob/master/init.lua 20 | 21 | 5. Run init.lua, it will download all the files and compile the codes 22 | 23 | 6. Go to: http://i.nodeusb.com 24 | 25 | ### Tips 26 | * Only works if ESP8266 is in the same network 27 | * ESP8266 is very memory constrained, use 'Save&Compile' before run Lua codes will use less heap 28 | * 'Run Selection' only good for few lines of code, if no response, 'Save&Compile' then 'Run Script' 29 | * Read large file is slow, can takes 10-30 seconds, be patient 30 | * Reboot ESP8266 if no response, or power cycle it 31 | * Remember, 'Save&Compile' is your best friend 32 | * Due to very limited heap size,I have to use lots of hacks to reduce the heap used,for example,it is very difficult to upload large block of codes to ESP8266 using http post, if I use multi chucks, the i.lua in ESP8266 will use more memory, I ended up to let IDE upload to my server's memcache first, then i.lua download from my server, so if you think there is a better solution, do let me know. 33 | * Due to the reason above, i.lua is not secure, you can POST lua codes and it will run them, please keep that in mind. 34 | -------------------------------------------------------------------------------- /d.lua: -------------------------------------------------------------------------------- 1 | local moduleName = ... 2 | local M = {} 3 | _G[moduleName] = M 4 | 5 | host="i.nodeusb.com" 6 | 7 | function M.g(p,f,a) 8 | local strPost = "GET /"..p.."f="..f.." HTTP/1.0\r\nHost: "..host.."\r\n\r\n" 9 | local sk=net.createConnection(net.TCP, 0) 10 | 11 | local s=0 12 | 13 | if a==nil then 14 | file.remove(f) 15 | end 16 | file.open(f,"a") 17 | 18 | sk:on("connection", function(sck) sk:send(strPost) end) 19 | 20 | sk:on("receive", function(sck, res) 21 | local pos=string.find(res,"%c%c%c") 22 | --print(pos) 23 | if pos~=nil then 24 | s=1 25 | pos=pos+4 26 | else 27 | pos=0 28 | end 29 | if s==1 then 30 | file.write(res:sub(pos)) 31 | end 32 | res=nil 33 | collectgarbage() 34 | end) 35 | 36 | sk:dns(host,function(conn,ip) sk:connect(80,ip) end) 37 | tmr.alarm(5,2000,0,function() sk:close() sk=nil strPost = nil file.close() collectgarbage() end) 38 | end 39 | 40 | function M.r(ip,mac) 41 | local strPost = "GET /a?ip="..ip.."&mac="..mac.." HTTP/1.0\r\nHost: "..host.."\r\n\r\n" 42 | local sk=net.createConnection(net.TCP, 0) 43 | 44 | sk:on("connection", function(sck) sk:send(strPost) end) 45 | sk:on("receive", function(sck, res) print(res) res=nil collectgarbage() end) 46 | sk:dns(host,function(conn,ip) sk:connect(80,ip) print(ip) collectgarbage() end) 47 | tmr.alarm(5,2000,0,function() sk:close() sk=nil strPost = nil collectgarbage() end) 48 | end 49 | 50 | return M 51 | -------------------------------------------------------------------------------- /i.lua: -------------------------------------------------------------------------------- 1 | srv=net.createServer(net.TCP) 2 | srv:listen(80,function(conn) 3 | local okHeader= "HTTP/1.0 200 OK\r\nAccess-Control-Allow-Origin:*\r\n\r\n" 4 | local DataToGet = 0 5 | local sending=false 6 | 7 | function s_output(str) 8 | if(conn~=nil) then 9 | if(sending) then 10 | conn:send(str) 11 | else 12 | sending=true 13 | conn:send(okHeader..str) 14 | end 15 | end 16 | end 17 | 18 | node.output(s_output, 1) 19 | 20 | conn:on("receive",function(conn,payload) 21 | local pos=string.find(payload,"%c%-%-%-") 22 | 23 | if pos==nil and fstart==nil then 24 | print("ERR") 25 | return 26 | end 27 | 28 | node.input(string.sub(payload,pos+4)) 29 | end) 30 | 31 | conn:on("sent",function(conn) 32 | sending=false 33 | node.output(nil) 34 | conn:close() 35 | end) 36 | end) 37 | print("free:", node.heap()) 38 | -------------------------------------------------------------------------------- /init.lua: -------------------------------------------------------------------------------- 1 | 2 | host="i.nodeusb.com" 3 | function getFile(p,f) 4 | local strPost = "GET /"..p.."f="..f.." HTTP/1.0\r\nHost: "..host.."\r\n\r\n" 5 | local sk=net.createConnection(net.TCP, 0) 6 | 7 | local s=0 8 | file.remove(f) 9 | file.open(f,"a") 10 | 11 | sk:on("connection", function(sck) sk:send(strPost) end) 12 | 13 | sk:on("receive", function(sck, res) 14 | local pos=string.find(res,"%c%c%c") 15 | if pos~=nil then 16 | s=1 17 | pos=pos+4 18 | else 19 | pos=0 20 | end 21 | if s==1 then 22 | file.write(res:sub(pos)) 23 | end 24 | res=nil 25 | collectgarbage() 26 | end) 27 | 28 | sk:dns(host,function(conn,ip) sk:connect(80,ip) end) 29 | tmr.alarm(5,2000,0,function() sk:close() sk=nil strPost = nil file.close() collectgarbage() end) 30 | end 31 | 32 | tmr.alarm(0,3000,1,function() 33 | 34 | ip = wifi.sta.getip() 35 | if(ip==nil) then 36 | print("Offline") 37 | else 38 | print('downloading\r\nd.lua') 39 | tmr.stop(0) 40 | 41 | getFile('e?','d.lua') 42 | 43 | tmr.alarm(1,4000,0,function() collectgarbage() node.compile('d.lua') print('i.lua') getFile('e?','i.lua') collectgarbage() end) 44 | tmr.alarm(2,8000,0,function() collectgarbage() node.compile('i.lua') print('init.lua') getFile('e?','init.lua') collectgarbage() tmr.alarm(3,5000,0,function() print("Done,reboot") node.restart() end) end) 45 | 46 | collectgarbage() 47 | end 48 | 49 | end) 50 | --------------------------------------------------------------------------------