Re: wireless coding firmware..
Posted: Thu May 28, 2015 11:22 am
hasty indeed, but for a reason:
1. a language / platform should be intuitive
2. copy&paste is the 21st century style of programming !
(of course the linux-faithful will disagree..)
nodeMCU is fine.. even regular expressions.. problem is that with wifi we immediately are tempted with web client/server stuff involving large strings and 150 lines nodeMCU code already crash with a 300 byte string :-/
I guess a complete rework of all string functions would be needed.. so they all work on streams, best with some kind of "stored procedures" to parse a long string in one pass. Not my playground.
By now i agree with Terrys socket approach. Socket communication might be the only way to install (large) lua script onto the ESP. With 24 days no update Terry has either finished his work or abandoned it.
When i have learned socket communication i will rewrite my ESPLoad.
With the ESP in client mode a simple php script might feed the ESP line by line with a lua file hosted on the server.
With the ESP in server mode, a simple javascript page in the client browser might do the communication.
Originally i never intended to write such a system myself. This thread was rather meant to collect some ideas..
I think this is my latest version of ESPLoad:
It seems, conn:on("receive", function(client,request)
already contains the entire string in "request" and not a stream :-(
Directly saving it to the filesystem and then stream reading/parsing it allowed me to form-upload files of size 500 bytes, ha ha :-/
Maybe someone will like that compact POST-parser:
I guess the current version of ESPLoad could be optimized with http://www.esp8266.com/viewtopic.php?f=19&t=1940
But as i wrote in the first lines, this is not my way.
Ah yes: make.bat
i have ordered 1+3 https://www.kickstarter.com/projects/706167548/dominoio-an-open-hardware-wifi-platform-for-things
I still like the ESP-201, but only for simple sensor logging. And i guess, only 1 ADC will not be enough for me. So i guess i will have to bundle whatever wifi-SoC with a good old Arduino Mini anyway.
Ideas welcome :-)
1. a language / platform should be intuitive
2. copy&paste is the 21st century style of programming !
(of course the linux-faithful will disagree..)
nodeMCU is fine.. even regular expressions.. problem is that with wifi we immediately are tempted with web client/server stuff involving large strings and 150 lines nodeMCU code already crash with a 300 byte string :-/
I guess a complete rework of all string functions would be needed.. so they all work on streams, best with some kind of "stored procedures" to parse a long string in one pass. Not my playground.
By now i agree with Terrys socket approach. Socket communication might be the only way to install (large) lua script onto the ESP. With 24 days no update Terry has either finished his work or abandoned it.
When i have learned socket communication i will rewrite my ESPLoad.
With the ESP in client mode a simple php script might feed the ESP line by line with a lua file hosted on the server.
With the ESP in server mode, a simple javascript page in the client browser might do the communication.
Originally i never intended to write such a system myself. This thread was rather meant to collect some ideas..
I think this is my latest version of ESPLoad:
Code: Select all
--install.lu
print("install ESPLoad")
function Finish()
if sFile then
print("size: " .. (iSeek-iStart))
if string.match(sFile, "\.lua") then
print("compiling..")
node.compile(sFile)
end
end
iStart = iSeek
end
file.open("install.lua","r")
iSeek=0
iStart=0
sFile = nil
s=file.readline()
while s ~= nil do
iSeek = iSeek + string.len(s)
sFileNew = string.match(s, "file:([%w.]+)")
if sFileNew then
print(sFileNew)
file.close()
file.remove(sFileNew)
file.open("install.lua","r")
file.seek("set",iSeek)
Finish()
sFile = sFileNew
end
if sFile then
file.close()
file.open(sFile,"a+")
file.write(s)
file.close()
file.open("install.lua","r")
file.seek("set",iSeek)
collectgarbage()
end
s=file.readline()
end
file.close()
--file.remove("install.lua")
Finish()
print("install finished :-)")
--[[
file:y.htm
Content-Type: text/html; charset=UTF-8
<html><body><form method=post enctype="multipart/form-data">
error: <input name=err value='_err'/><br/>
<h2>access point:</h2>
SSID: <input name=ssid value='_ssid'/><br/>
pwd: <input name=pwd value='_pwd'/><br/>
upload:<br/>
<textarea style="font-size:8pt;" cols=80 rows=10 name=upload>_upload</textarea>
<h2>fetch lua:</h2>
ip: <input name=host value='_host'/><br/>
domain: <input name=domain value='_domain'/><br/>
path: <input name=path value='_path'/><br/>
reboot: <input type=number size=4 name=update value='_update'/> minutes<br/>
<input type=submit value='submit'/>
</form></body></html>
--file:start.lua
print(collectgarbage("count").." kB used")
s = {ssid="", pwd="", host="", domain="", path="", err="no data",update=0,upload=""}
if (file.open("s.txt","r")) then
local sF = file.read()
file.close()
for k, v in string.gmatch(sF, "([%w.]+)=([%S ]*)") do
s[k] = v
--print(k .. ": " .. v)
end
end
if s.err == "" then
if (tonumber(s.update)>0) then
tmr.alarm (0, tonumber(s.update)*60000, 1, function()
print("checking for update")
end)
end
dofile("client.lua")
else
require("server")
--dofile("server.lua")
end
--file:server.lua
function M(s)
print(s .. ": " .. collectgarbage("count").." kB used")
end
function SaveX(sErr)
if (sErr) then
print (sErr)
s.err = sErr
end
file.remove("s.txt")
file.open("s.txt","w+")
for k, v in pairs(s) do
file.writeline(k .. "=" .. v)
end
file.close()
collectgarbage()
end
wifi.setmode(wifi.SOFTAP)
wifi.ap.config({ssid="node_"..node.chipid(), pwd=""})
srv=net.createServer(net.TCP)
print(wifi.sta.getip())
function _read()
l = file.readline()
if l then
iSeek = iSeek + string.len(l)
end
return l
end
srv:listen(1985,function(conn)
conn:on("receive", function(client,request)
M("1985..")
client:send("HTTP/1.x 200 OK\n")
file.remove("t")
file.open("t","w+")
file.write(request)
file.close()
request = ""
collectgarbage()
file.open("t","r")
iSeek = 0
boundary = nil
local l = _read()
repeat
--print(iSeek)
local bRead = true;
if boundary then
print("'"..l.."'")
local i,j = string.find(l, boundary)
--print(j)
if j then
--print("'"..boundary.."'")
--if l == boundary then
l = _read()
--print (l)
if l then
local key = string.match(l, 'name="(%w+)"')
if key then
--print ("key: "..key)
l = _read()
if key == "upload" then
l = _read()
--print ("save upload: "..l)
local iStart = iSeek
local sFile = string.match(l, '^--file:([%w.]+)')
if not sFile then
sFile = "do.lua"
end
print ("save upload to ".. sFile)
file.remove(sFile)
repeat
file.close()
file.open(sFile,"a+")
local i,j = string.find(l, boundary)
if j then
file.close()
file.open("t","r")
file.seek("set",iSeek)
bRead = false
s.path = sFile
else
file.write(l)
file.close()
file.open("t","r")
file.seek("set",iSeek)
l = _read()
end
until (l == nil) or not bRead
else
s[key] = _read()
print(key .." = " .. s[key])
--s[key] = string.gsub(_read(),"[\n\r]","")
end
else
--print("no key found :-(")
end
end
end
else
boundary = string.match(l, 'boundary=([^\s]+)')
end
if bRead then
l = _read()
end
print(iSeek)
until l == nil
file.close()
M("open y")
file.open("y.htm","r")
local sH = file.read()
--M(string.len(sH))
for k, v in pairs(s) do
--M(k)
sH,n = string.gsub(sH,"_"..k,v)
--sH,n = string.gsub(sH,"_"..k,unescape(v))
end
M(string.len(sH))
s.upload = ""
print(string.len(sH))
file.close()
client:send(sH)
client:close()
collectgarbage()
M("1985 done")
end)
end)
--if s.path ~= "" then
-- if file.open(s.path,"r") then
-- dofile(s.path)
-- end
--end
--file:client.lua
function SaveX(sErr)
if (sErr) then
print (sErr)
s.err = sErr
end
file.remove("s.txt")
file.open("s.txt","w+")
for k, v in pairs(s) do
file.writeline(k .. "=" .. v)
end
file.close()
collectgarbage()
end
function NewLua(sck,c)
local nStart, nEnd = string.find(c, "\n\n")
if (nEnd == nil) then
nStart, nEnd = string.find(c, "\r\n\r\n")
end
c = string.sub(c,nEnd+1)
print("lua length: "..string.len(c))
if (string.sub(c,0,7) ~= "--file:") then
SaveX(s.domain.."/"..s.path .. " does not begin with --lua")
node.restart()
return
end
file.remove("do.lua")
file.open("do.lua","w+")
file.writeline(c)
file.close()
node.compile("do.lua")
--dofile("do.lua")
dofile("do.lc")
collectgarbage()
end
print("fetch lua..")
wifi.setmode (wifi.STATION)
wifi.sta.config(s.ssid, s.pwd)
wifi.sta.autoconnect (1)
iFail = 20
tmr.alarm (1, 1000, 1, function ( )
iFail = iFail -1
print(iFail)
if (iFail == 0) then
SaveX("could not access "..s.ssid)
node.restart()
end
if wifi.sta.getip ( ) == nil then
print(s.ssid)
else
print ("ip: " .. wifi.sta.getip ( ))
tmr.stop (1)
sk=net.createConnection(net.TCP, 0)
sk:on("receive", NewLua)
sk:connect(80,s.host)
sGet = "GET /".. s.path .. " HTTP/1.1\r\nHost: " .. s.domain .. "\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n"
print(sGet)
sk:send(sGet)
end
collectgarbage()
end)
print(collectgarbage("count").." kB: client.lua")
--]]
It seems, conn:on("receive", function(client,request)
already contains the entire string in "request" and not a stream :-(
Directly saving it to the filesystem and then stream reading/parsing it allowed me to form-upload files of size 500 bytes, ha ha :-/
Maybe someone will like that compact POST-parser:
Code: Select all
s = {ssid="", pwd="", host="", domain="", path="", err="no data",update=0,upload=""}
function _read()
l = file.readline()
if l then
iSeek = iSeek + string.len(l)
end
return l
end
srv:listen(1985,function(conn)
conn:on("receive", function(client,request)
M("1985..")
client:send("HTTP/1.x 200 OK\n")
file.remove("t")
file.open("t","w+")
file.write(request)
file.close()
request = ""
collectgarbage()
file.open("t","r")
iSeek = 0
boundary = nil
local l = _read()
repeat
local bRead = true;
if boundary then
local i,j = string.find(l, boundary)
if j then
l = _read()
if l then
local key = string.match(l, 'name="(%w+)"')
if key then
l = _read()
if key == "upload" then
l = _read()
local iStart = iSeek
local sFile = string.match(l, '^--file:([%w.]+)')
if not sFile then
sFile = "do.lua"
end
print ("save upload to ".. sFile)
file.remove(sFile)
repeat
file.close()
file.open(sFile,"a+")
local i,j = string.find(l, boundary)
if j then
file.close()
file.open("t","r")
file.seek("set",iSeek)
bRead = false
s.path = sFile
else
file.write(l)
file.close()
file.open("t","r")
file.seek("set",iSeek)
l = _read()
end
until (l == nil) or not bRead
else
s[key] = _read()
end
else
--print("no key found :-(")
end
end
end
else
boundary = string.match(l, 'boundary=([^\s]+)')
end
if bRead then
l = _read()
end
print(iSeek)
until l == nil
file.close()
-- ...
I guess the current version of ESPLoad could be optimized with http://www.esp8266.com/viewtopic.php?f=19&t=1940
But as i wrote in the first lines, this is not my way.
Ah yes: make.bat
Code: Select all
copy install.lu+y.htm+start.lua+server.lua+client.lua install.lua
i have ordered 1+3 https://www.kickstarter.com/projects/706167548/dominoio-an-open-hardware-wifi-platform-for-things
I still like the ESP-201, but only for simple sensor logging. And i guess, only 1 ADC will not be enough for me. So i guess i will have to bundle whatever wifi-SoC with a good old Arduino Mini anyway.
Ideas welcome :-)